| | |
| | | namespace HH.WCS.Mobox3.DSZSH { |
| | | public class Startup { |
| | | public void Configuration(IAppBuilder app) { |
| | | // 有关如何配置应用程序的详细信息,请访问 https://go.microsoft.com/fwlink/?LinkID=316888 |
| | | // 有关如何配置应用程序的详细信息,请访问 https://go.microsoft.com/fwlink/?LinkID=316888 |
| | | HttpConfiguration config = new HttpConfiguration(); |
| | | config.Routes.MapHttpRoute( |
| | | name: "DefaultApi", |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 开启TCP协议通讯,服务端 |
| | | /// 开启TCP协议通讯,服务端 |
| | | /// </summary> |
| | | private static void StartTcp() |
| | | { |
| | |
| | | |
| | | tasks.Add(GetTask(WCSCore.Dispatch)); |
| | | |
| | | // 测试:托盘下线 |
| | | // 测试:托盘下线 |
| | | //tasks.Add(GetTask(Monitor.CheckInbound)); |
| | | |
| | | // 轮询:出库单状态 |
| | | // 轮询:出库单状态 |
| | | tasks.Add(GetTask(Monitor.CheckOutboundOrder)); |
| | | |
| | | // 轮询:抽检单状态 |
| | | // 轮询:抽检单状态 |
| | | tasks.Add(GetTask(Monitor.CheckCheckOrder)); |
| | | |
| | | // 轮询:移库单状态 |
| | | // 轮询:移库单状态 |
| | | tasks.Add(GetTask(Monitor.CheckShiftOrder)); |
| | | |
| | | Task.WaitAll(tasks.ToArray()); |
| | |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | LogHelper.Error(ex.Message, ex); |
| | | LogHelper.InfoEx(ex); |
| | | } |
| | | Thread.Sleep(intervalMs); |
| | | } |
| | |
| | | //请将此类型的 ComVisible 特性设置为 true。 |
| | | [assembly: ComVisible(false)] |
| | | |
| | | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID |
| | | // 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID |
| | | [assembly: Guid("8e589c0d-7d65-474d-8ced-e34e087126a1")] |
| | | |
| | | // 程序集的版本信息由下列四个值组成: |
| | |
| | | // 生成号 |
| | | // 修订号 |
| | | // |
| | | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 |
| | | //通过使用 "*",如下所示: |
| | | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 |
| | | //通过使用 "*",如下所示: |
| | | // [assembly: AssemblyVersion("1.0.*")] |
| | | [assembly: AssemblyVersion("1.0.0.0")] |
| | | [assembly: AssemblyFileVersion("1.0.0.0")] |
| | |
| | | |
| | | namespace HH.WCS.Mobox3.DSZSH.api { |
| | | /// <summary> |
| | | /// 设备信息上报(HostToAGV上报、杭奥堆垛机、国自AGV) |
| | | /// 设备信息上报 (HostToAGV上报,杭奥堆垛机,国自AGV) |
| | | /// </summary> |
| | | [RoutePrefix("agv")] |
| | | public class AgvController : ApiController |
| | |
| | | [HttpPost] |
| | | [Route("AGVCallbackState")] |
| | | public ReturnResult AGVCallbackState(AgvTaskState model){ |
| | | LogHelper.InfoHostToAGV("AGVCallbackState:NDC任务状态回报", model); |
| | | LogHelper.InfoHostToAGV("AGVCallbackState:NDC任务状态回报", model); |
| | | return WCSCore.OperateAgvTaskStatus(model); |
| | | } |
| | | |
| | |
| | | [HttpPost] |
| | | [Route("SafetyInteraction")] |
| | | public ReturnResult SafetyInteraction(SafetyInteractionInfo model) { |
| | | LogHelper.InfoHostToAGV("SafetyInteraction:AGV与产线进行安全交互", model); |
| | | LogHelper.InfoHostToAGV("SafetyInteraction:AGV与产线进行安全交互", model); |
| | | return WCSCore.SafetyInteraction(model); |
| | | } |
| | | } |
| | |
| | | public static SimpleResult GoodpackOffline(GoodpackOfflineInfo model) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var taskInfo = ETask.M满箱下线入库.Info(); |
| | | const string preLog = "API:满箱下线入库:"; |
| | | const string preLog = "API:满箱下线入库:"; |
| | | const string cntrType = "好运箱"; |
| | | |
| | | try { |
| | | if (model.Num <= 0) { |
| | | return NewSimpleResult(400, preLog + $"物料数量'{model.Num}'不合法!要求:物料数量>0"); |
| | | return NewSimpleResult(400, preLog + $"物料数量'{model.Num}'不合法!要求:物料数量>0"); |
| | | } |
| | | |
| | | // 检查货品容器表:是否已经存在贴标机传递的待入库物料信息 |
| | | // TODO:数量、规格是否也参与比对? |
| | | // 检查货品容器表:是否已经存在贴标机传递的待入库物料信息 |
| | | // TODO:数量,规格是否也参与比对? |
| | | var cgDetail = db.Queryable<TN_CG_Detail>().Where(d => d.S_ITEM_CODE == model.ItemCode && d.S_BATCH_NO == model.BatchNo && d.N_ITEM_STATE == 1 && d.S_ITEM_STATE == "待检").First(); |
| | | if (cgDetail == null) { |
| | | return NewSimpleResult(1, preLog + $"没有在[货品明细表]中找到[物料编码='{model.ItemCode}',批次号='{model.BatchNo}']的物料!请检查:PDA扫码物料信息与贴标机传递的信息是否一致!要求:物料状态='待检'"); |
| | | return NewSimpleResult(1, preLog + $"没有在[货品明细表]中找到[物料编码='{model.ItemCode}',批次号='{model.BatchNo}']的物料!请检查:PDA扫码物料信息与贴标机传递的信息是否一致!要求:物料状态='待检'"); |
| | | } |
| | | |
| | | // 查询起点货位:数量=0 |
| | | var startLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y").Where(l => l.S_CODE == model.StartLoc && taskInfo.StartAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 0).First(); |
| | | // 查询起点货位:数量=0 |
| | | var startLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y" && l.S_CODE == model.StartLoc && taskInfo.StartAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 0).First(); |
| | | if (startLoc == null) { |
| | | return NewSimpleResult(2, preLog + $"没有找到起点货位'{model.StartLoc}'!要求:锁状态='无',当前容器数量=0,所在库区={LogObject(taskInfo.StartAreas)}"); |
| | | return NewSimpleResult(2, preLog + $"没有找到起点货位'{model.StartLoc}'!要求:锁状态='无',当前容器数量=0,所在库区={LogObject(taskInfo.StartAreas)}"); |
| | | } |
| | | |
| | | // 和满托下线入库的逻辑一致,由于容器移动不会更改绑定信息,所以必须删除旧数据 |
| | | var locCntrRelOld = db.Queryable<TN_Loc_Container>() |
| | | .Where(c => c.S_CNTR_CODE == cgDetail.S_CNTR_CODE).First(); |
| | | // 和满托下线入库的逻辑一致,由于容器移动不会更改绑定信息,所以必须删除旧数据 |
| | | var old = WCSHelper.GetLocCntrCg(cgDetail.S_CNTR_CODE, skipCgDetail: true); |
| | | |
| | | // 绑定货位容器,起点货位当前数量=1 |
| | | var locCntrRel = new TN_Loc_Container { S_LOC_CODE = startLoc.S_CODE, S_CNTR_CODE = cgDetail.S_CNTR_CODE, S_CNTR_TYPE = cntrType,}; |
| | | startLoc.N_CURRENT_NUM = 1; |
| | | // 绑定货位容器,起点货位当前数量=1 |
| | | var locCntrRel = WCSHelper.BindLocCntr(ref startLoc, cgDetail.S_CNTR_CODE); |
| | | locCntrRel.S_CNTR_TYPE = cntrType; |
| | | |
| | | // 查询终点货位 |
| | | // Order:按货位层数,从小到大排列 |
| | | var endLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") |
| | | .Where(l => taskInfo.EndAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 0).OrderBy(l => new { l.N_LAYER }).First(); |
| | | // Order:按货位层数,从小到大排列 |
| | | var endLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y" && taskInfo.EndAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 0).OrderBy(l => new { l.N_LAYER }).First(); |
| | | if (endLoc == null) { |
| | | return NewSimpleResult(3, preLog + $"没有找到合适的终点货位!要求:锁状态='无',当前容器数量=0,所在库区={LogObject(taskInfo.EndAreas)}"); |
| | | return NewSimpleResult(3, preLog + $"没有找到合适的终点货位!要求:锁状态='无',当前容器数量=0,所在库区={LogObject(taskInfo.EndAreas)}"); |
| | | } |
| | | |
| | | // 起点终点上锁,创建任务 |
| | | // 更新[起点/终点]锁状态,创建任务 |
| | | WCSHelper.LockStartLoc(ref startLoc); |
| | | WCSHelper.LockEndLoc(ref endLoc); |
| | | var task = WCSHelper.BuildTask(startLoc, endLoc, locCntrRel.S_CNTR_CODE, taskInfo.TaskName); |
| | | |
| | | using (var tran = db.Ado.UseTran()) { |
| | | if (locCntrRelOld != null) { |
| | | if (db.Deleteable(locCntrRelOld).ExecuteCommand() <= 0 && |
| | | db.Updateable<TN_Location>().SetColumns(l => l.N_CURRENT_NUM == 0).Where(l => l.S_CODE == locCntrRelOld.S_LOC_CODE).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"删除旧货位容器关系表失败!货位编码={locCntrRelOld.S_LOC_CODE},容器编码={locCntrRelOld.S_CNTR_CODE}"); |
| | | } |
| | | // 删除/更新旧[货位/容器/物料]信息 |
| | | if (old.LocCntrRel != null && db.Deleteable(old.LocCntrRel).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"删除[旧货位容器关系]失败!数据:{LogObject(old.LocCntrRel)}"); |
| | | } |
| | | if (old.Location != null && db.Updateable(old.Location).UpdateColumns(l => new { l.N_CURRENT_NUM, l.T_MODIFY }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[旧货位|当前容器数量]失败!货位='{old.Location.S_CODE}',数量=>{old.Location.N_CURRENT_NUM}"); |
| | | } |
| | | |
| | | // 插入新绑定的[货位-容器]表 |
| | | if (db.Insertable(locCntrRel).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"插入[容器货位绑定表]失败!数据:{LogObject(locCntrRel)}"); |
| | | return NewSimpleResult(500, preLog + $"插入[容器货位绑定表]失败!数据:{LogObject(locCntrRel)}"); |
| | | } |
| | | |
| | | // 更新[起点/终点]锁状态,创建任务 |
| | | if (db.Updateable(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, it.N_CURRENT_NUM, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | return NewSimpleResult(500, preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | } |
| | | |
| | | if (db.Updateable(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | return NewSimpleResult(500, preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | } |
| | | |
| | | if (db.Insertable(task).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | return NewSimpleResult(500, preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | |
| | | // 提交数据库更改 |
| | | tran.CommitTran(); |
| | | return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | return NewSimpleResult(-1, preLog + $"发生了异常:{ex.Message}\n{ex.StackTrace}"); |
| | | return NewSimpleResult(ex, preLog); |
| | | } |
| | | } |
| | | |
| | |
| | | public static SimpleResult EmptyInboundPallet(EmptyInboundInfo model) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var taskInfo = ETask.K空托入库.Info(); |
| | | const string preLog = "API:空托入库:"; |
| | | const string preLog = "API:空托入库:"; |
| | | const string cntrType = "托盘"; |
| | | |
| | | try { |
| | | // 查询起点货位:数量=0 |
| | | var startLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y").Where(l => l.S_CODE == model.StartLoc && taskInfo.StartAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 0).First(); |
| | | // 查询起点货位:数量=0 |
| | | var startLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y" && l.S_CODE == model.StartLoc && taskInfo.StartAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 0).First(); |
| | | if (startLoc == null) { |
| | | return NewSimpleResult(1, preLog + $"没有找到起点货位'{model.StartLoc}'!要求:锁状态='无';当前容器数量=0;所在库区={LogObject(taskInfo.StartAreas)}"); |
| | | return NewSimpleResult(1, preLog + $"没有找到起点货位'{model.StartLoc}'!要求:锁状态='无';当前容器数量=0;所在库区={LogObject(taskInfo.StartAreas)}"); |
| | | } |
| | | |
| | | // 查询容器表:容器类型字段 |
| | | // 查询容器表:容器类型字段 |
| | | var cntr = db.Queryable<TN_Container>().Where(c => c.S_CODE == model.CntrCode).First(); |
| | | if (cntr == null) { |
| | | return NewSimpleResult(2, preLog + $"容器'{model.CntrCode}'在[容器表]中不存在,请在前台页面中维护!"); |
| | | return NewSimpleResult(2, preLog + $"容器'{model.CntrCode}'在[容器表]中不存在,请在前台页面中维护!"); |
| | | } |
| | | if (cntr.S_TYPE != cntrType) { |
| | | return NewSimpleResult(3, preLog + $"容器'{model.CntrCode}'在[容器表]中的类型为'{cntr.S_TYPE}',与输入的容器类型'{cntrType}'不同!"); |
| | | return NewSimpleResult(3, preLog + $"容器'{model.CntrCode}'在[容器表]中的类型为'{cntr.S_TYPE}',与输入的容器类型'{cntrType}'不同!"); |
| | | } |
| | | |
| | | // 空箱入库时,如果存在旧的绑定数据,删除 |
| | | var old = WCSHelper.GetLocCntrCg(model.CntrCode); |
| | | |
| | | // 空箱入库时,如果存在旧的绑定数据,删除 |
| | | var cgDetailOld = db.Queryable<TN_CG_Detail>().Where(d => d.S_CNTR_CODE == model.CntrCode).First(); |
| | | var locCntrRelOld = db.Queryable<TN_Loc_Container>().Where(c => c.S_CNTR_CODE == model.CntrCode).First(); |
| | | TN_Location locOld = null; |
| | | if (locCntrRelOld != null) { |
| | | locOld = db.Queryable<TN_Location>().Where(l => l.S_CODE == locCntrRelOld.S_LOC_CODE).First(); |
| | | if (locOld != null) { |
| | | locOld.N_CURRENT_NUM = 0; // 如果旧货位存在,将旧货位的数量设置为 0 |
| | | locOld.T_MODIFY = DateTime.Now; |
| | | } |
| | | } |
| | | |
| | | // 绑定货位容器,起点货位当前数量=1 |
| | | var locCntrRel = new TN_Loc_Container { S_LOC_CODE = startLoc.S_CODE, S_CNTR_CODE = cntr.S_CODE, S_CNTR_TYPE = cntrType }; |
| | | startLoc.N_CURRENT_NUM = 1; |
| | | // 绑定货位容器,起点货位当前数量=1 |
| | | var locCntrRel = WCSHelper.BindLocCntr(ref startLoc, cntr.S_CODE); |
| | | locCntrRel.S_CNTR_TYPE = cntrType; |
| | | |
| | | // 查询终点货位 |
| | | // Order:层数从低到高、行、列 |
| | | var endLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y").Where(l => taskInfo.EndAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 0).OrderBy(l => new { l.N_LAYER, l.N_ROW, l.N_COL }).First(); |
| | | // Order:层数从低到高,行,列 |
| | | var endLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y" && taskInfo.EndAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 0).OrderBy(l => new { l.N_LAYER, l.N_ROW, l.N_COL }).First(); |
| | | if (endLoc == null) { |
| | | return NewSimpleResult(3, preLog + $"没有找到合适的终点货位!要求:锁状态='无';当前容器数量=0;所在库区={LogObject(taskInfo.EndAreas)}"); |
| | | return NewSimpleResult(3, preLog + $"没有找到合适的终点货位!要求:锁状态='无';当前容器数量=0;所在库区={LogObject(taskInfo.EndAreas)}"); |
| | | } |
| | | |
| | | // 起点终点上锁,创建任务 |
| | | // 起点终点上锁,创建任务 |
| | | WCSHelper.LockStartLoc(ref startLoc); |
| | | WCSHelper.LockEndLoc(ref endLoc); |
| | | var task = WCSHelper.BuildTask(startLoc, endLoc, locCntrRel.S_CNTR_CODE, taskInfo.TaskName); |
| | | |
| | | using (var tran = db.Ado.UseTran()) { |
| | | if (cgDetailOld != null && db.Deleteable(cgDetailOld).ExecuteCommand() <= 0) { |
| | | if (old.CgDetail != null && db.Deleteable(old.CgDetail).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"删除[旧物料信息]失败!数据:{LogObject(cgDetailOld)}"); |
| | | return NewSimpleResult(500, preLog + $"删除[旧物料信息]失败!数据:{LogObject(old.CgDetail)}"); |
| | | } |
| | | |
| | | if (locCntrRelOld != null && db.Deleteable(locCntrRelOld).ExecuteCommand() <= 0) { |
| | | if (old.LocCntrRel != null && db.Deleteable(old.LocCntrRel).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"删除[旧货位容器关系]失败!数据:{LogObject(locCntrRelOld)}"); |
| | | return NewSimpleResult(500, preLog + $"删除[旧货位容器关系]失败!数据:{LogObject(old.LocCntrRel)}"); |
| | | } |
| | | |
| | | if (locOld != null && db.Updateable(locOld).UpdateColumns(l => new { l.N_CURRENT_NUM, l.T_MODIFY }).ExecuteCommand() <= 0) { |
| | | if (old.Location != null && db.Updateable(old.Location).UpdateColumns(l => new { l.N_CURRENT_NUM, l.T_MODIFY }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[旧货位|当前容器数量]失败!货位='{locOld.S_CODE}',数量=>{locOld.N_CURRENT_NUM}"); |
| | | return NewSimpleResult(500, preLog + $"更新[旧货位|当前容器数量]失败!货位='{old.Location.S_CODE}',数量=>{old.Location.N_CURRENT_NUM}"); |
| | | } |
| | | |
| | | if (db.Insertable(locCntrRel).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"插入[货位容器绑定表]失败!数据:{LogObject(locCntrRel)}"); |
| | | return NewSimpleResult(500, preLog + $"插入[货位容器绑定表]失败!数据:{LogObject(locCntrRel)}"); |
| | | } |
| | | |
| | | // 更新[起点/终点]锁状态,创建任务 |
| | | if (db.Updateable(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, it.N_CURRENT_NUM, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | return NewSimpleResult(500, preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | } |
| | | |
| | | if (db.Updateable(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | return NewSimpleResult(500, preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | } |
| | | |
| | | if (db.Insertable(task).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | return NewSimpleResult(500, preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | |
| | | // 提交数据库更改 |
| | | tran.CommitTran(); |
| | | return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | return NewSimpleResult(-1, preLog + $"发生了异常:{ex.Message}\n{ex.StackTrace}"); |
| | | return NewSimpleResult(ex, preLog); |
| | | } |
| | | } |
| | | |
| | |
| | | public static SimpleResult EmptyInboundGoodpack(EmptyInboundInfo model) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var taskInfo = ETask.K空箱入库.Info(); |
| | | const string preLog = "API:空箱入库:"; |
| | | const string preLog = "API:空箱入库:"; |
| | | const string cntrType = "好运箱"; |
| | | |
| | | try { |
| | | // 查询起点货位:数量=0 |
| | | // 查询起点货位:数量=0 |
| | | var startLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y").Where(l => l.S_CODE == model.StartLoc && taskInfo.StartAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 0).First(); |
| | | if (startLoc == null) { |
| | | return NewSimpleResult(1, preLog + $"没有找到起点货位'{model.StartLoc}'!要求:锁状态='无';当前容器数量=0;所在库区={LogObject(taskInfo.StartAreas)}"); |
| | | return NewSimpleResult(1, preLog + $"没有找到起点货位'{model.StartLoc}'!要求:锁状态='无';当前容器数量=0;所在库区={LogObject(taskInfo.StartAreas)}"); |
| | | } |
| | | |
| | | // 查询容器表:容器类型字段 |
| | | // 查询容器表:容器类型字段 |
| | | var cntr = db.Queryable<TN_Container>().Where(c => c.S_CODE == model.CntrCode).First(); |
| | | if (cntr == null) { |
| | | return NewSimpleResult(2, preLog + $"容器'{model.CntrCode}'在[容器表]中不存在,请在前台页面中维护!"); |
| | | return NewSimpleResult(1, $"容器'{model.CntrCode}'在[容器表]中不存在,请在前台页面中维护!"); |
| | | } |
| | | if (cntr.S_TYPE != cntrType) { |
| | | return NewSimpleResult(3, preLog + $"容器'{model.CntrCode}'在[容器表]中的类型为'{cntr.S_TYPE}',与输入的容器类型'{cntrType}'不同!"); |
| | | return NewSimpleResult(2, preLog + $"容器'{model.CntrCode}'在[容器表]中的类型是'{cntr.S_TYPE},不是'{cntrType}'!"); |
| | | } |
| | | |
| | | // 空箱入库时,如果存在旧的绑定数据,删除 |
| | | var cgDetailOld = db.Queryable<TN_CG_Detail>().Where(d => d.S_CNTR_CODE == model.CntrCode).First(); |
| | | var locCntrRelOld = db.Queryable<TN_Loc_Container>().Where(c => c.S_CNTR_CODE == model.CntrCode).First(); |
| | | TN_Location locOld = null; |
| | | if (locCntrRelOld != null) { |
| | | locOld = db.Queryable<TN_Location>().Where(l => l.S_CODE == locCntrRelOld.S_LOC_CODE).First(); |
| | | if (locOld != null) { |
| | | locOld.N_CURRENT_NUM = 0; // 如果旧货位存在,将旧货位的数量设置为 0 |
| | | locOld.T_MODIFY = DateTime.Now; |
| | | } |
| | | } |
| | | // 空箱入库时,如果存在旧的绑定数据,删除 |
| | | var old = WCSHelper.GetLocCntrCg(model.CntrCode); |
| | | |
| | | // 绑定货位容器,起点货位当前数量=1 |
| | | var locCntrRel = new TN_Loc_Container { S_LOC_CODE = startLoc.S_CODE, S_CNTR_CODE = cntr.S_CODE, S_CNTR_TYPE = cntrType }; |
| | | startLoc.N_CURRENT_NUM = 1; |
| | | // 绑定货位容器,起点货位当前数量=1 |
| | | var locCntrRel = WCSHelper.BindLocCntr(ref startLoc, model.CntrCode); |
| | | locCntrRel.S_CNTR_TYPE = cntrType; |
| | | |
| | | // 查询终点货位 |
| | | // Order:层数从低到高、行、列 |
| | | // Order:层数从低到高,行,列 |
| | | var endLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y").Where(l => taskInfo.EndAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 0).OrderBy(l => new { l.N_LAYER, l.N_ROW, l.N_COL }).First(); |
| | | if (endLoc == null) { |
| | | return NewSimpleResult(3, preLog + $"没有找到合适的终点货位!要求:锁状态='无';当前容器数量=0;所在库区={LogObject(taskInfo.EndAreas)}"); |
| | | return NewSimpleResult(3, preLog + $"没有找到合适的终点货位!要求:锁状态='无';当前容器数量=0;所在库区={LogObject(taskInfo.EndAreas)}"); |
| | | } |
| | | |
| | | WCSHelper.LockStartLoc(ref startLoc); |
| | |
| | | var task = WCSHelper.BuildTask(startLoc, endLoc, locCntrRel.S_CNTR_CODE, taskInfo.TaskName); |
| | | |
| | | using (var tran = db.Ado.UseTran()) { |
| | | if (cgDetailOld != null && db.Deleteable(cgDetailOld).ExecuteCommand() <= 0) { |
| | | if (old.CgDetail != null && db.Deleteable(old.CgDetail).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"删除[旧物料信息]失败!数据:{LogObject(cgDetailOld)}"); |
| | | return NewSimpleResult(500, preLog + $"删除[旧物料信息]失败!数据:{LogObject(old.CgDetail)}"); |
| | | } |
| | | |
| | | if (locCntrRelOld != null && db.Deleteable(locCntrRelOld).ExecuteCommand() <= 0) { |
| | | if (old.LocCntrRel != null && db.Deleteable(old.LocCntrRel).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"删除[旧货位容器关系]失败!" + LogObject(locCntrRelOld)); |
| | | return NewSimpleResult(500, preLog + $"删除[旧货位容器关系]失败!数据:{LogObject(old.LocCntrRel)}"); |
| | | } |
| | | |
| | | if (locOld != null && db.Updateable(locOld).UpdateColumns(l => new { l.N_CURRENT_NUM, l.T_MODIFY }).ExecuteCommand() <= 0) { |
| | | if (old.Location != null && db.Updateable(old.Location).UpdateColumns(l => new { l.N_CURRENT_NUM, l.T_MODIFY }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[旧货位|容器数量]失败!" + LogObject(locOld)); |
| | | return NewSimpleResult(500, preLog + $"更新[旧货位|当前容器数量]失败!货位='{old.Location.S_CODE}',数量=>{old.Location.N_CURRENT_NUM}"); |
| | | } |
| | | |
| | | if (db.Insertable(locCntrRel).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"插入[货位容器关系]失败:" + LogObject(locCntrRel)); |
| | | return NewSimpleResult(500, preLog + $"插入[货位容器关系]失败:" + LogObject(locCntrRel)); |
| | | } |
| | | |
| | | // 更新[起点/终点]锁状态,创建任务 |
| | | if (db.Updateable(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, it.N_CURRENT_NUM, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | return NewSimpleResult(500, preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | } |
| | | |
| | | if (db.Updateable(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | return NewSimpleResult(500, preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | } |
| | | |
| | | if (db.Insertable(task).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | return NewSimpleResult(500, preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | |
| | | // 提交数据库更改 |
| | | tran.CommitTran(); |
| | | return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | return NewSimpleResult(-1, preLog + $"发生了异常:{ex.Message}\n{ex.StackTrace}"); |
| | | return NewSimpleResult(ex, preLog); |
| | | } |
| | | } |
| | | |
| | |
| | | public static SimpleResult EmptyOnlinePallet(EmptyOnlinePalletInfo model) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var taskInfo = ETask.K空托上线出库.Info(); |
| | | const string preLog = "API:空托上线出库:"; |
| | | const string preLog = "API:空托上线出库:"; |
| | | const string cntrType = "托盘"; |
| | | |
| | | try { |
| | | // 查询容器表:容器类型字段 |
| | | // 查询容器表:容器类型字段 |
| | | var cntr = db.Queryable<TN_Container>().Where(c => c.S_CODE == model.CntId).First(); |
| | | if (cntr == null) { |
| | | return NewSimpleResult(1, $"容器'{model.CntId}'在[容器表]中不存在,请在前台页面中维护!"); |
| | | return NewSimpleResult(1, $"容器'{model.CntId}'在[容器表]中不存在,请在前台页面中维护!"); |
| | | } |
| | | if (cntr.S_TYPE != cntrType) { |
| | | return NewSimpleResult(2, preLog + $"容器'{model.CntId}'在[容器表]中的类型是'{cntr.S_TYPE},不是'{cntrType}'!"); |
| | | return NewSimpleResult(2, preLog + $"容器'{model.CntId}'在[容器表]中的类型是'{cntr.S_TYPE},不是'{cntrType}'!"); |
| | | } |
| | | |
| | | var needUpdateContainer = false; |
| | | if (string.IsNullOrEmpty(cntr.S_SPEC)) { |
| | | // TEMP 目前流程:如果容器表中规格(物料编码)为空,根据流程的物料信息写入 |
| | | // 待定:后面可能会更改流程,或者用其他信息(如物料类型/规格)作为容器的规格 |
| | | // TEMP 目前流程:如果容器表中规格 (物料编码) 为空,根据流程的物料信息写入 |
| | | // 待定:后面可能会更改流程,或者用其他信息 (如物料类型/规格) 作为容器的规格 |
| | | |
| | | needUpdateContainer = true; |
| | | cntr.S_SPEC = model.ItemCode; |
| | | LogHelper.Info($"容器'{model.CntId}'在[容器表]中[规格(物料编码)]为空,将物料编码'{model.ItemCode}'写入容器的规格"); |
| | | LogHelper.Info($"容器'{model.CntId}'在[容器表]中[规格(物料编码)]为空,将物料编码'{model.ItemCode}'写入容器的规格"); |
| | | } |
| | | else if (cntr.S_SPEC != model.ItemCode) { |
| | | return NewSimpleResult(3, $"容器'{model.CntId}'已经与物料类型'{cntr.S_SPEC}'绑定,无法用于装载物料'{model.ItemCode}'!"); |
| | | return NewSimpleResult(3, $"容器'{model.CntId}'已经与物料类型'{cntr.S_SPEC}'绑定,无法用于装载物料'{model.ItemCode}'!"); |
| | | } |
| | | |
| | | var startLoc = db.Queryable<TN_Location>().LeftJoin<TN_Loc_Container>((l, c) => l.S_CODE == c.S_LOC_CODE).Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y").Where((l, c) => taskInfo.StartAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 1 && c.S_CNTR_CODE == model.CntId && c.S_CNTR_TYPE == cntrType).First(); |
| | | if (startLoc == null) { |
| | | return NewSimpleResult(3, preLog + $"没有找到合适的起点货位!要求:锁状态='无';当前容器数量=1;所在库区={LogObject(taskInfo.StartAreas)},绑定容器编码='{model.CntId}',绑定容器类型='{cntrType}'"); |
| | | return NewSimpleResult(3, preLog + $"没有找到合适的起点货位!要求:锁状态='无';当前容器数量=1;所在库区={LogObject(taskInfo.StartAreas)},绑定容器编码='{model.CntId}',绑定容器类型='{cntrType}'"); |
| | | } |
| | | |
| | | // 查询终点货位 |
| | | var endLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y").Where(l => taskInfo.EndAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 0).First(); |
| | | if (endLoc == null) { |
| | | return NewSimpleResult(5, preLog + $"没有找到合适的终点货位!要求:锁状态='无';当前容器数量=0;所在库区={LogObject(taskInfo.EndAreas)}"); |
| | | return NewSimpleResult(5, preLog + $"没有找到合适的终点货位!要求:锁状态='无';当前容器数量=0;所在库区={LogObject(taskInfo.EndAreas)}"); |
| | | } |
| | | |
| | | WCSHelper.LockStartLoc(ref startLoc); |
| | |
| | | |
| | | using (var tran = db.Ado.UseTran()) { |
| | | if (needUpdateContainer && db.Updateable(cntr).UpdateColumns(c => new { c.S_SPEC, c.S_SOURCE, c.T_MODIFY }).ExecuteCommand() <= 0) { |
| | | return NewSimpleResult(500, preLog + $"更新[容器表]失败!数据:{LogObject(cntr)}"); |
| | | return NewSimpleResult(500, preLog + $"更新[容器表]失败!数据:{LogObject(cntr)}"); |
| | | } |
| | | |
| | | // 更新[起点/终点]锁状态,创建任务 |
| | | if (db.Updateable(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, it.N_CURRENT_NUM, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | return NewSimpleResult(500, preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | } |
| | | |
| | | if (db.Updateable(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | return NewSimpleResult(500, preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | } |
| | | |
| | | if (db.Insertable(task).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | return NewSimpleResult(500, preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | |
| | | // 提交数据库更改 |
| | | tran.CommitTran(); |
| | | return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | return NewSimpleResult(-1, preLog + $"发生了异常:{ex.Message}\n{ex.StackTrace}"); |
| | | return NewSimpleResult(ex, preLog); |
| | | } |
| | | } |
| | | |
| | |
| | | public static SimpleResult EmptyOnlineGoodpack(EmptyOnlineGoodpackInfo model) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var taskInfo = ETask.K空箱上线出库.Info(); |
| | | const string preLog = "API:空箱上线出库:"; |
| | | const string preLog = "API:空箱上线出库:"; |
| | | const string cntrType = "好运箱"; |
| | | |
| | | try { |
| | | var cntr = db.Queryable<TN_Container>() |
| | | .Where(c => c.S_CODE == model.CntId) |
| | | .First(); |
| | | |
| | | var cntr = db.Queryable<TN_Container>().Where(c => c.S_CODE == model.CntId).First(); |
| | | if (cntr == null) { |
| | | return NewSimpleResult(1, preLog + $"容器'{model.CntId}'在[容器表]中不存在,请在前台页面中维护!"); |
| | | return NewSimpleResult(1, preLog + $"容器'{model.CntId}'在[容器表]中不存在,请在前台页面中维护!"); |
| | | } |
| | | if (cntr.S_TYPE != cntrType) { |
| | | return NewSimpleResult(2, preLog + $"容器'{model.CntId}'在[容器表]中的类型='{cntr.S_TYPE}',不是'{cntrType}'!"); |
| | | return NewSimpleResult(2, preLog + $"容器'{model.CntId}'在[容器表]中的类型='{cntr.S_TYPE}',不是'{cntrType}'!"); |
| | | } |
| | | |
| | | var startLoc = db.Queryable<TN_Location>().LeftJoin<TN_Loc_Container>((l, c) => l.S_CODE == c.S_LOC_CODE).Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y").Where((l, c) => taskInfo.StartAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 1 && c.S_CNTR_CODE == model.CntId && c.S_CNTR_TYPE == cntrType).First(); |
| | | if (startLoc == null) { |
| | | return NewSimpleResult(2, preLog + $"没有找到合适的起点货位!要求:锁状态='无',当前容器数量=1,所在库区={LogObject(taskInfo.StartAreas)},绑定容器编码='{model.CntId}',绑定容器类型='{cntrType}'"); |
| | | return NewSimpleResult(2, preLog + $"没有找到合适的起点货位!要求:锁状态='无',当前容器数量=1,所在库区={LogObject(taskInfo.StartAreas)},绑定容器编码='{model.CntId}',绑定容器类型='{cntrType}'"); |
| | | } |
| | | |
| | | var endLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") |
| | | .Where(l => taskInfo.EndAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 0).First(); |
| | | if (endLoc == null) { |
| | | return NewSimpleResult(3, preLog + $"没有找到合适的终点货位!要求:锁状态='无',当前容器数量=0,所在库区={LogObject(taskInfo.EndAreas)}"); |
| | | return NewSimpleResult(3, preLog + $"没有找到合适的终点货位!要求:锁状态='无',当前容器数量=0,所在库区={LogObject(taskInfo.EndAreas)}"); |
| | | } |
| | | |
| | | WCSHelper.LockStartLoc(ref startLoc); |
| | |
| | | var task = WCSHelper.BuildTask(startLoc, endLoc, model.CntId, taskInfo.TaskName); |
| | | |
| | | using (var tran = db.Ado.UseTran()) { |
| | | // 更新[起点/终点]锁状态,创建任务 |
| | | if (db.Updateable(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, it.N_CURRENT_NUM, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | return NewSimpleResult(500, preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | } |
| | | |
| | | if (db.Updateable(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | return NewSimpleResult(500, preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | } |
| | | |
| | | if (db.Insertable(task).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | return NewSimpleResult(500, preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | |
| | | // 提交数据库更改 |
| | | tran.CommitTran(); |
| | | return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | return NewSimpleResult(-1, preLog + $"发生了异常:{ex.Message}\n{ex.StackTrace}"); |
| | | return NewSimpleResult(ex, preLog); |
| | | } |
| | | } |
| | | |
| | |
| | | public static SimpleResult QualifiedBack(QualifiedBackInfo model) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var taskInfo = ETask.C抽检合格回库.Info(); |
| | | const string preLog = "API:抽检合格回库"; |
| | | const string preLog = "API:抽检合格回库"; |
| | | |
| | | try { |
| | | var cgDetail = db.Queryable<TN_CG_Detail>() |
| | | .Where(d => d.S_ITEM_CODE == model.ItemCode && d.S_CNTR_CODE == model.CntrCode).First(); |
| | | if (cgDetail == null) { |
| | | return NewSimpleResult(2, preLog + "没有找到待回库的抽检物料:" + LogObject(model)); |
| | | return NewSimpleResult(2, preLog + "没有找到待回库的抽检物料:" + LogObject(model)); |
| | | } |
| | | |
| | | var locCntrRel = db.Queryable<TN_Loc_Container>() |
| | | .Where(c => c.S_CNTR_CODE == cgDetail.S_CNTR_CODE).First(); |
| | | var locCntrRel = db.Queryable<TN_Loc_Container>().Where(c => c.S_CNTR_CODE == cgDetail.S_CNTR_CODE).First(); |
| | | if (locCntrRel == null) { |
| | | return NewSimpleResult(3, preLog + $"容器{model.CntrCode}在货位容器关系表中不存在"); |
| | | } |
| | | |
| | | var startLoc = db.Queryable<TN_Location>() |
| | | .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y").Where(l => l.S_CODE == locCntrRel.S_LOC_CODE && taskInfo.StartAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 1).First(); |
| | | var startLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y" && l.S_CODE == locCntrRel.S_LOC_CODE && taskInfo.StartAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 1).First(); |
| | | if (startLoc == null) { |
| | | return NewSimpleResult(4, preLog + $"没有找到合适的起点货位!要求:锁状态='无',当前容器数量=1,所在库区={LogObject(taskInfo.StartAreas)}"); |
| | | return NewSimpleResult(4, preLog + $"没有找到合适的起点货位!要求:锁状态='无',当前容器数量=1,所在库区={LogObject(taskInfo.StartAreas)}"); |
| | | } |
| | | |
| | | var endAreas = locCntrRel.S_CNTR_CODE == "托盘" ? taskInfo.EndAreas_Pallet : taskInfo.EndAreas_Goodpack; |
| | | var endLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") |
| | | .Where(l => endAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 0).First(); |
| | | var endLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y" && endAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 0).First(); |
| | | if (endLoc == null) { |
| | | return NewSimpleResult(3, preLog + $"没有找到合适的终点货位!要求:锁状态='无',当前容器数量=0,所在库区={LogObject(endAreas)}"); |
| | | return NewSimpleResult(3, preLog + $"没有找到合适的终点货位!要求:锁状态='无',当前容器数量=0,所在库区={LogObject(endAreas)}"); |
| | | } |
| | | |
| | | cgDetail.N_ITEM_STATE = 0; |
| | |
| | | using (var tran = db.Ado.UseTran()) { |
| | | if (db.Updateable(cgDetail).UpdateColumns(it => new { it.N_ITEM_STATE, it.S_ITEM_STATE, it.T_MODIFY }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[物料明细表]失败!物料号='{cgDetail.S_ITEM_CODE}',物料状态=>'合格'"); |
| | | return NewSimpleResult(500, preLog + $"更新[物料明细表]失败!物料号='{cgDetail.S_ITEM_CODE}',物料状态=>'合格'"); |
| | | } |
| | | |
| | | // 更新[起点/终点]锁状态,创建任务 |
| | | if (db.Updateable(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, it.N_CURRENT_NUM, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | return NewSimpleResult(500, preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | } |
| | | |
| | | if (db.Updateable(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | return NewSimpleResult(500, preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | } |
| | | |
| | | if (db.Insertable(task).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | return NewSimpleResult(500, preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | |
| | | // 提交数据库更改 |
| | | tran.CommitTran(); |
| | | return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | return NewSimpleResult(-1, preLog + $"发生了异常:{ex.Message}\n{ex.StackTrace}"); |
| | | return NewSimpleResult(ex, preLog); |
| | | } |
| | | } |
| | | |
| | |
| | | public static SimpleResult UnqualifiedShift(UnqualifiedShiftInfo model) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var taskInfo = ETask.C抽检不合格移库.Info(); |
| | | const string preLog = "API:抽检不合格移库:"; |
| | | const string preLog = "API:抽检不合格移库:"; |
| | | |
| | | try { |
| | | if (!taskInfo.EndAreas.Contains(model.EndArea)) { |
| | | return NewSimpleResult(1, preLog + $"终点库区'{model.EndArea}'不满足条件!需要:货区={LogObject(taskInfo.EndAreas)}"); |
| | | return NewSimpleResult(1, preLog + $"终点库区'{model.EndArea}'不满足条件!需要:货区={LogObject(taskInfo.EndAreas)}"); |
| | | } |
| | | |
| | | var cgDetail = db.Queryable<TN_CG_Detail>() |
| | | .Where(d => d.S_ITEM_CODE == model.ItemCode && d.S_CNTR_CODE == model.CntrCode).First(); |
| | | if (cgDetail == null) { |
| | | return NewSimpleResult(2, preLog + $"没有在[物料明细表]中找到物料!要求:物料编码='{model.ItemCode}',容器编码='{model.CntrCode}'"); |
| | | return NewSimpleResult(2, preLog + $"没有在[物料明细表]中找到物料!要求:物料编码='{model.ItemCode}',容器编码='{model.CntrCode}'"); |
| | | } |
| | | |
| | | var locCntrRel = db.Queryable<TN_Loc_Container>().Where(c => c.S_CNTR_CODE == cgDetail.S_CNTR_CODE).First(); |
| | | if (locCntrRel == null) { |
| | | return NewSimpleResult(3, preLog + $"在[货位容器关系表]中没有找到容器'{model.CntrCode}'!"); |
| | | return NewSimpleResult(3, preLog + $"在[货位容器关系表]中没有找到容器'{model.CntrCode}'!"); |
| | | } |
| | | |
| | | // 查询起点货位:数量=1 |
| | | var startLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y").Where(l => l.S_CODE == locCntrRel.S_LOC_CODE && taskInfo.StartAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 1).First(); |
| | | // 查询起点货位:数量=1 |
| | | var startLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y" && l.S_CODE == locCntrRel.S_LOC_CODE && taskInfo.StartAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 1).First(); |
| | | if (startLoc == null) { |
| | | return NewSimpleResult(1, preLog + $"没有找到起点货位'{locCntrRel.S_LOC_CODE}'!要求:锁状态='无';当前容器数量=1;所在库区={LogObject(taskInfo.StartAreas)}"); |
| | | return NewSimpleResult(1, preLog + $"没有找到起点货位'{locCntrRel.S_LOC_CODE}'!要求:锁状态='无';当前容器数量=1;所在库区={LogObject(taskInfo.StartAreas)}"); |
| | | } |
| | | |
| | | var endLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") |
| | | .Where(l => l.S_AREA_CODE == model.EndArea && l.N_CURRENT_NUM == 0).First(); |
| | | var endLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y" && l.S_AREA_CODE == model.EndArea && l.N_CURRENT_NUM == 0).First(); |
| | | if (endLoc == null) { |
| | | return NewSimpleResult(3, preLog + $"没有找到合适的终点货位!要求:锁状态='无',当前容器数量=0,所在库区='{model.EndArea}'"); |
| | | return NewSimpleResult(3, preLog + $"没有找到合适的终点货位!要求:锁状态='无',当前容器数量=0,所在库区='{model.EndArea}'"); |
| | | } |
| | | |
| | | cgDetail.N_ITEM_STATE = 2; |
| | |
| | | using (var tran = db.Ado.UseTran()) { |
| | | if (db.Updateable(cgDetail).UpdateColumns(it => new { it.N_ITEM_STATE, it.S_ITEM_STATE }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[货品明细表]失败!物料号='{cgDetail}',物料状态=>'{cgDetail.S_ITEM_STATE}'"); |
| | | return NewSimpleResult(500, preLog + $"更新[货品明细表]失败!物料号='{cgDetail}',物料状态=>'{cgDetail.S_ITEM_STATE}'"); |
| | | } |
| | | |
| | | // 更新[起点/终点]锁状态,创建任务 |
| | | if (db.Updateable(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, it.N_CURRENT_NUM, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | return NewSimpleResult(500, preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | } |
| | | |
| | | if (db.Updateable(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | return NewSimpleResult(500, preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | } |
| | | |
| | | if (db.Insertable(task).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | return NewSimpleResult(500, preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | |
| | | // 提交数据库更改 |
| | | tran.CommitTran(); |
| | | return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | return NewSimpleResult(-1, preLog + $"发生了异常:{ex.Message}\n{ex.StackTrace}"); |
| | | return NewSimpleResult(ex, preLog); |
| | | } |
| | | } |
| | | |
| | |
| | | public static SimpleResult RestBack(RestBackInfo model) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var taskInfo = ETask.W尾料回库.Info(); |
| | | const string preLog = "API:尾料回库:"; |
| | | const string preLog = "API:尾料回库:"; |
| | | |
| | | try { |
| | | var startLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") |
| | | .Where(l => l.S_CODE == model.StartLoc && l.N_CURRENT_NUM == 1).First(); |
| | | var startLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y" && l.S_CODE == model.StartLoc && l.N_CURRENT_NUM == 1).First(); |
| | | if (startLoc == null) { |
| | | return NewSimpleResult(2, $"没有找到起点货位'{model.StartLoc}'!要求:锁状态='无';当前容器数量=1"); |
| | | return NewSimpleResult(2, $"没有找到起点货位'{model.StartLoc}'!要求:锁状态='无';当前容器数量=1"); |
| | | } |
| | | |
| | | var locCntrRel = db.Queryable<TN_Loc_Container>().Where(c => c.S_LOC_CODE == model.StartLoc).First(); |
| | |
| | | } |
| | | |
| | | var endAreas = locCntrRel.S_CNTR_CODE == "托盘" ? taskInfo.EndAreas_Pallet : taskInfo.EndAreas_Goodpack; |
| | | var endLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") |
| | | .Where(l => endAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 0).First(); |
| | | var endLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y" && endAreas.Contains(l.S_AREA_CODE) && l.N_CURRENT_NUM == 0).First(); |
| | | if (endLoc == null) { |
| | | return NewSimpleResult(3, preLog + $"没有找到合适的终点货位!要求:锁状态='无',当前容器数量=0,所在库区={LogObject(endAreas)}"); |
| | | return NewSimpleResult(3, preLog + $"没有找到合适的终点货位!要求:锁状态='无',当前容器数量=0,所在库区={LogObject(endAreas)}"); |
| | | } |
| | | |
| | | var cntId = locCntrRel.S_CNTR_CODE; |
| | |
| | | using (var tran = db.Ado.UseTran()) { |
| | | //if (db.Insertable(locCntrRel).ExecuteCommand() <= 0) { |
| | | // tran.RollbackTran(); |
| | | // return NewSimpleResult(500, preLog + $"插入[容器货位绑定表]失败!数据:{LogObject(locCntrRel)}"); |
| | | // return NewSimpleResult(500, preLog + $"插入[容器货位绑定表]失败!数据:{LogObject(locCntrRel)}"); |
| | | //} |
| | | |
| | | // 更新[起点/终点]锁状态,创建任务 |
| | | if (db.Updateable(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, it.N_CURRENT_NUM, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | return NewSimpleResult(500, preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | } |
| | | |
| | | if (db.Updateable(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | return NewSimpleResult(500, preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | } |
| | | |
| | | if (db.Insertable(task).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(500, preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | return NewSimpleResult(500, preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | |
| | | // 提交数据库更改 |
| | | tran.CommitTran(); |
| | | return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | return NewSimpleResult(-1, preLog + $"发生了异常:{ex.Message}\n{ex.StackTrace}"); |
| | | return NewSimpleResult(ex, preLog); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 成品胶出库(PDA) 待定,暂时不需要此功能 |
| | | /// 成品胶出库(PDA) 待定,暂时不需要此功能 |
| | | /// </summary> |
| | | /// <param name="model"></param> |
| | | /// <returns></returns> |
| | | public static SimpleResult FinishedOutbound(FinishedOutboundInfo model) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var taskInfo = ETask.C成品胶出库.Info(); |
| | | const string preLog = "API:成品胶出库:"; |
| | | const string preLog = "API:成品胶出库:"; |
| | | |
| | | try { |
| | | var orderNo = GenerateOrderNo("出库单号", "CKD"); |
| | |
| | | using (var tran = db.Ado.UseTran()) { |
| | | if (db.Insertable(order).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(2, preLog + "生成出库单失败:" + LogObject(order)); |
| | | return NewSimpleResult(2, preLog + "生成出库单失败:" + LogObject(order)); |
| | | } |
| | | |
| | | if (db.Insertable(detailList).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(4, preLog + "生成出库单明细失败:" + LogObject(detailList)); |
| | | return NewSimpleResult(4, preLog + "生成出库单明细失败:" + LogObject(detailList)); |
| | | } |
| | | |
| | | tran.CommitTran(); |
| | |
| | | return NewSimpleResult(0, preLog + "生成出库单成功"); |
| | | } |
| | | catch (Exception ex) { |
| | | return NewSimpleResult(-1, preLog + $"发生了异常:{ex.Message}\n{ex.StackTrace}"); |
| | | return NewSimpleResult(ex, preLog); |
| | | } |
| | | } |
| | | |
| | |
| | | public static SimpleResult FinishedOutboundForce(FinishedOutboundInfo model) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var taskInfo = ETask.C成品胶出库.Info(); |
| | | const string preLog = "API:成品胶出库:"; |
| | | const string preLog = "API:成品胶出库:"; |
| | | |
| | | try { |
| | | var orderNo = GenerateOrderNo("出库单号", "CKD"); |
| | |
| | | using (var tran = db.Ado.UseTran()) { |
| | | if (db.Insertable(order).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(2, preLog + "生成出库单失败:" + LogObject(order)); |
| | | return NewSimpleResult(2, preLog + "生成出库单失败:" + LogObject(order)); |
| | | } |
| | | |
| | | if (db.Insertable(detailList).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewSimpleResult(4, preLog + "生成出库单明细失败:" + LogObject(detailList)); |
| | | return NewSimpleResult(4, preLog + "生成出库单明细失败:" + LogObject(detailList)); |
| | | } |
| | | |
| | | tran.CommitTran(); |
| | |
| | | return NewSimpleResult(0, preLog + "生成出库单成功"); |
| | | } |
| | | catch (Exception ex) { |
| | | return NewSimpleResult(-1, preLog + $"发生了异常:{ex.Message}\n{ex.StackTrace}"); |
| | | return NewSimpleResult(ex, preLog); |
| | | } |
| | | } |
| | | |
| | |
| | | return result; |
| | | } |
| | | |
| | | // NOTE 根据总量选detail时,是否需要考虑货位的高低? |
| | | // NOTE 根据总量选detail时,是否需要考虑货位的高低? |
| | | |
| | | var sortedMaterials = new List<TN_CG_Detail>(); |
| | | |
| | | var cntrTypeList = new List<string>(); |
| | | if (cntrType == "") { |
| | | cntrTypeList = new List<string> { "托盘", "好运箱" }; // 不指定托盘类型,二者均可 |
| | | cntrTypeList = new List<string> { "托盘", "好运箱" }; // 不指定托盘类型,二者均可 |
| | | } |
| | | else { |
| | | cntrTypeList.Add(cntrType); |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 博实物料信息下发同步(只针对好运箱) |
| | | /// 博实物料信息下发同步 (只针对好运箱) |
| | | /// </summary> |
| | | /// <param name="model"></param> |
| | | /// <returns></returns> |
| | | public static MesResult CgInfoSync(CgInfoSyncInfo model) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | const string preLog = "API:博实下发物料信息:"; |
| | | const string preLog = "API:博实下发物料信息:"; |
| | | const string cntrType = "好运箱"; |
| | | |
| | | try { |
| | | if (string.IsNullOrEmpty(model.ItemCode)) { |
| | | return NewMesResult(400, preLog + $"物料编码'{model.ItemCode}'不能为空!"); |
| | | return NewMesResult(400, preLog + $"物料编码'{model.ItemCode}'不能为空!"); |
| | | } |
| | | if (string.IsNullOrEmpty(model.CntrCode)) { |
| | | return NewMesResult(400, preLog + $"容器编码'{model.CntrCode}'不能为空!"); |
| | | return NewMesResult(400, preLog + $"容器编码'{model.CntrCode}'不能为空!"); |
| | | } |
| | | if (string.IsNullOrEmpty(model.BatchNo)) { |
| | | return NewMesResult(400, preLog + $"批次号'{model.BatchNo}'不能为空!"); |
| | | return NewMesResult(400, preLog + $"批次号'{model.BatchNo}'不能为空!"); |
| | | } |
| | | if (model.ItemNum <= 0) { |
| | | return NewMesResult(400, preLog + $"物料数量'{model.ItemNum}'不合法!要求:物料数量>0"); |
| | | return NewMesResult(400, preLog + $"物料数量'{model.ItemNum}'不合法!要求:物料数量>0"); |
| | | } |
| | | |
| | | // TEMP 目前流程:对博实下发的信息也进行检查,未找到就报错,后面有需求再更改 |
| | | // TEMP 目前流程:对博实下发的信息也进行检查,未找到就报错,后面有需求再更改 |
| | | var cntr = db.Queryable<TN_Container>() |
| | | .Where(c => c.S_CODE == model.CntrCode) // 对于前台程序而言,S_CODE就是主键,维护时必定唯一 |
| | | .Where(c => c.S_CODE == model.CntrCode) // 对于前台程序而言,S_CODE就是主键,维护时必定唯一 |
| | | .First(); |
| | | |
| | | if (cntr == null) { |
| | | return NewMesResult(1, preLog + $"容器'{model.CntrCode}'在[容器表]中不存在,请在前台页面中维护!"); |
| | | return NewMesResult(1, preLog + $"容器'{model.CntrCode}'在[容器表]中不存在,请在前台页面中维护!"); |
| | | } |
| | | if (cntr.S_TYPE != cntrType) { |
| | | return NewMesResult(2, preLog + $"容器'{model.CntrCode}'在[容器表]中的类型为'{cntr.S_TYPE}',与当前容器类型'{cntrType}'不同!"); |
| | | return NewMesResult(2, preLog + $"容器'{model.CntrCode}'在[容器表]中的类型为'{cntr.S_TYPE}',与当前容器类型'{cntrType}'不同!"); |
| | | } |
| | | |
| | | // 将下发的信息先存储到CG表中(此时托盘没有与产线处的货位绑定) |
| | | // 将下发的信息先存储到CG表中 (此时托盘没有与产线处的货位绑定) |
| | | var detail = new TN_CG_Detail { |
| | | S_ITEM_CODE = model.ItemCode, // NOT NULL |
| | | S_ITEM_NAME = model.ItemName, |
| | | S_CNTR_CODE = model.CntrCode, // NOT NULL 料箱编号(待定,现在暂时设定为博实下发) |
| | | S_CNTR_CODE = model.CntrCode, // NOT NULL 料箱编号 (待定,现在暂时设定为博实下发) |
| | | S_BATCH_NO = model.BatchNo, // NOT NULL |
| | | S_STANDARD = model.Standard, |
| | | S_NET_WEIGHT = model.NetWeight, |
| | | S_QUALITY_GRADE = model.QualityGrade, |
| | | }; |
| | | |
| | | // 产线号的逻辑待定,现在设定为博实下发产线号,看后续需求变更 |
| | | // 好运箱起点为产线货位,人工将好运箱从产线上取下,搬运到满好运箱操作区 |
| | | // 产线号的逻辑待定,现在设定为博实下发产线号,看后续需求变更 |
| | | // 好运箱起点为产线货位,人工将好运箱从产线上取下,搬运到满好运箱操作区 |
| | | //var startLocCode = ""; |
| | | //if (model.ProdLineId.Trim() == "3") { |
| | | // startLocCode = ""; |
| | | //} |
| | | |
| | | //if (model.ProdLineId.Trim() != "3" || model.ProdLineId.Trim() != "4") { |
| | | // info = $"不合法的产线号{model.ProdLineId}:好运箱产线号必须为 3 或 4"; |
| | | // info = $"不合法的产线号{model.ProdLineId}:好运箱产线号必须为 3 或 4"; |
| | | // LogHelper.Info(info); |
| | | // return NewMesResult(2, info); |
| | | //} |
| | | |
| | | if (db.Insertable(detail).ExecuteCommand() <= 0) { |
| | | return NewMesResult(500, preLog + $"插入[物料明细表]失败!数据:{LogObject(detail)}"); |
| | | return NewMesResult(500, preLog + $"插入[物料明细表]失败!数据:{LogObject(detail)}"); |
| | | } |
| | | |
| | | return NewMesResult(500, preLog + $"插入[物料明细表]成功!数据:{LogObject(detail)}"); |
| | | return NewMesResult(500, preLog + $"插入[物料明细表]成功!数据:{LogObject(detail)}"); |
| | | } |
| | | catch (Exception ex) { |
| | | return NewMesResult(-1, preLog + $"发生了异常:{ex.Message}\n{ex.StackTrace}"); |
| | | return NewMesResult(-1, preLog + $"发生了异常:{ex.Message}\n\n{ex.StackTrace}\n"); |
| | | } |
| | | } |
| | | |
| | | public static ErpResult ErpSendOutboundPlan(ErpSendOutboundPlanInfo model) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var orderNo = GenerateOrderNo("出库单号", "CKD"); |
| | | const string preLog = "API:ERP下发出库计划单:"; |
| | | const string preLog = "API:ERP下发出库计划单:"; |
| | | try { |
| | | if (model.pzjs <= 0) { |
| | | return NewErpResult(400, preLog + $"物料数量(pzjs)'{model.pzjs}'不合法!要求:物料数量>0"); |
| | | return NewErpResult(400, preLog + $"物料数量(pzjs)'{model.pzjs}'不合法!要求:物料数量>0"); |
| | | } |
| | | |
| | | var outboundPlan = db.Queryable<TN_Outbound_Plan>() |
| | | .Where(p => p.JHDH == model.jhdh).First(); |
| | | if (outboundPlan != null) { |
| | | return NewErpResult(1, preLog + $"计划单号'{model.jhdh}'已在[出库计划单]中存在!"); |
| | | return NewErpResult(1, preLog + $"计划单号'{model.jhdh}'已在[出库计划单]中存在!"); |
| | | } |
| | | |
| | | outboundPlan = new TN_Outbound_Plan { |
| | | JHDH = model.jhdh, // 计划单号(唯一标识) |
| | | CKZT = model.ckzt, // 出库状态(需要返回) |
| | | JHDH = model.jhdh, // 计划单号 (唯一标识) |
| | | CKZT = model.ckzt, // 出库状态 (需要返回) |
| | | JHLB = model.jhlb, // 计划类别 |
| | | CKDH = model.ckdh, // 参考单号 |
| | | CPH = model.cph, // 车牌号 |
| | |
| | | CPLB = model.cplb, // 产品类别 |
| | | CPLBMX = model.cplbmx, // 产品类别明细 |
| | | PP = model.pp, // 品牌 |
| | | DJ = model.dj, // 等级(需要返回) |
| | | DJ = model.dj, // 等级 (需要返回) |
| | | GH = model.gh, // 罐号 |
| | | PH = model.ph, // 批号(需要返回) |
| | | PH = model.ph, // 批号 (需要返回) |
| | | BZLX = model.bzlx, // 包装类型 |
| | | PZDH = model.pzdh, // 派装单号 |
| | | PZD_DW = model.pzd_dw, // 派装单单位 |
| | |
| | | PZ_ZFRQ = model.pz_zfrq, // 派装作废日期 |
| | | PZ_BZ = model.pz_bz, // 派装备注 |
| | | CKDBH = model.ckdbh, // 出库单编号 |
| | | SFJS = model.sfjs, // 实发件数(需要返回) |
| | | SFSL = model.sfsl, // 实发数量(需要返回) |
| | | SFCS = model.sfcs, // 实发车数(需要返回) |
| | | ZCSJ = model.zcsj, // 装车时间(需要返回) |
| | | JLDW = model.jldw, // 计量单位(需要返回) |
| | | FHRQ = model.fhrq, // 发货日期(需要返回) |
| | | CKDM = model.ckdm, // 仓库代码(需要返回) |
| | | FHR = model.fhr, // 发货人(需要返回) |
| | | CZYDM = model.czydm, // 操作员(需要返回) |
| | | SFJS = model.sfjs, // 实发件数 (需要返回) |
| | | SFSL = model.sfsl, // 实发数量 (需要返回) |
| | | SFCS = model.sfcs, // 实发车数 (需要返回) |
| | | ZCSJ = model.zcsj, // 装车时间 (需要返回) |
| | | JLDW = model.jldw, // 计量单位 (需要返回) |
| | | FHRQ = model.fhrq, // 发货日期 (需要返回) |
| | | CKDM = model.ckdm, // 仓库代码 (需要返回) |
| | | FHR = model.fhr, // 发货人 (需要返回) |
| | | CZYDM = model.czydm, // 操作员 (需要返回) |
| | | SHR_USERNAME = model.shr_username, // 审核人 |
| | | SHRQ = model.shrq, // 审核日期 |
| | | ZFBJ = model.zfbj, // 作废标记 |
| | |
| | | SHDW = model.shdw, // 收货单位 |
| | | YSDW = model.ysdw, // 运输单位 |
| | | LXR = model.lxr, // 联系人 |
| | | RY_ZXG = model.ry_zxg, // 装卸工(需要返回) |
| | | RY_CCSJ = model.ry_ccsj, // 叉车司机(需要返回) |
| | | RY_ZXG = model.ry_zxg, // 装卸工 (需要返回) |
| | | RY_CCSJ = model.ry_ccsj, // 叉车司机 (需要返回) |
| | | ERPHX_JHDH = model.erphx_jhdh, // erp交货单号 |
| | | ERPHX_WLBM = model.erphx_wlbm, // erp物料编码 |
| | | ERPHX_WLMC = model.erphx_wlmc, // erp物料名称 |
| | | ERPHX_CJRQ = model.erphx_cjrq, // erp创建日期 |
| | | HW = model.hw, // 货位(需要返回) |
| | | HWZT = model.hwzt // 货位状态(需要返回) |
| | | HW = model.hw, // 货位 (需要返回) |
| | | HWZT = model.hwzt // 货位状态 (需要返回) |
| | | }; |
| | | |
| | | //var cgDetailList = SelectCgByTotalQty( |
| | |
| | | // return NewErpResult(3, info); |
| | | //} |
| | | |
| | | var cgDetail = db.Queryable<TN_CG_Detail>() |
| | | .Where(d => d.S_ITEM_CODE == model.cpdm && d.N_ITEM_NUM >= model.pzjs).First(); |
| | | var cgDetail = db.Queryable<TN_CG_Detail>().Where(d => d.S_ITEM_CODE == model.cpdm && d.N_ITEM_NUM >= model.pzjs).First(); |
| | | if (cgDetail == null ) { |
| | | return NewErpResult(2, preLog + $"在[货品明细表]中没有找到合适的物料!要求:物料编码='{model.cpdm}',物料数量>={model.pzjs}"); |
| | | return NewErpResult(2, preLog + $"在[货品明细表]中没有找到合适的物料!要求:物料编码='{model.cpdm}',物料数量>={model.pzjs}"); |
| | | } |
| | | |
| | | var order = new TN_Outbound_Order { |
| | |
| | | using (var tran = db.Ado.UseTran()) { |
| | | if (db.Insertable(order).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewErpResult(500, preLog + $"生成[出库单]失败!数据:{LogObject(order)}"); |
| | | return NewErpResult(500, preLog + $"生成[出库单]失败!数据:{LogObject(order)}"); |
| | | } |
| | | |
| | | if (db.Insertable(detailList).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewErpResult(500, preLog + $"生成[出库单明细]失败!数据:{LogObject(detailList)}"); |
| | | return NewErpResult(500, preLog + $"生成[出库单明细]失败!数据:{LogObject(detailList)}"); |
| | | } |
| | | |
| | | if (db.Insertable(outboundPlan).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | return NewErpResult(500, preLog + $"生成[出库单计划记录表]失败!数据:{LogObject(outboundPlan)}"); |
| | | return NewErpResult(500, preLog + $"生成[出库单计划记录表]失败!数据:{LogObject(outboundPlan)}"); |
| | | } |
| | | |
| | | tran.CommitTran(); |
| | | return NewErpResult(0, preLog + $"生成[出库单]成功!出库单:{LogObject(order)}\n出库单明细:{LogObject(detail)}"); |
| | | return NewErpResult(0, preLog + $"生成[出库单]成功!出库单:{LogObject(order)}\n出库单明细:{LogObject(detail)}"); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | return NewErpResult(1, preLog + $"发生了异常:{ex.Message}\n{ex.StackTrace}"); |
| | | return NewErpResult(1, preLog + $"发生了异常:{ex.Message}\n\n{ex.StackTrace}\n"); |
| | | } |
| | | } |
| | | |
| | |
| | | public List<object> result { get; set; } = new List<object>(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 构建 <see cref="SimpleResult"/> 返回值 |
| | | /// </summary> |
| | | /// <param name="code"></param> |
| | | /// <param name="message"></param> |
| | | /// <param name="log"></param> |
| | | /// <returns></returns> |
| | | public static SimpleResult NewSimpleResult(int code, string message, bool log = true) { |
| | | if (log) { LogHelper.Info(message); } |
| | | public static SimpleResult NewSimpleResult(int code, string message, string name = "") { |
| | | LogHelper.Info(message, name); |
| | | return new SimpleResult { resultCode = code, resultMsg = message }; |
| | | } |
| | | |
| | | public static SimpleResult NewSimpleResult(Exception ex, string preLog = "", int errCode = -1) { |
| | | LogHelper.InfoEx(ex, preLog); |
| | | return new SimpleResult { resultCode = errCode, resultMsg = $"发生了[异常]:{ex.Message}" }; |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | //public int station_id { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 请求上线/下线的的站台库位名称,例如work6、work8 |
| | | /// 请求上线/下线的的站台库位名称,例如work6,work8 |
| | | /// </summary> |
| | | public string station_name { get; set; } |
| | | |
| | |
| | | [JsonProperty("n_num")] |
| | | public int Num { get; set; } |
| | | /// <summary> |
| | | /// 起点货位信息(起点货位货区要求:MXCZQ 满箱操作区) |
| | | /// 起点货位信息 (起点货位货区要求:MXCZQ 满箱操作区) |
| | | /// </summary> |
| | | [JsonProperty("s_start_loc")] |
| | | public string StartLoc { get; set; } |
| | |
| | | [JsonProperty("cntr_code")] |
| | | public string CntrCode { get; set; } |
| | | /// <summary> |
| | | /// 容器类型(必须为 '空托盘’ 或 ‘空好运箱') |
| | | /// 容器类型 (必须为 '空托盘’ 或 ‘空好运箱') |
| | | /// </summary> |
| | | [JsonProperty("cntr_type")] |
| | | public string CntrType { get; set; } |
| | | /// <summary> |
| | | /// 终点库区编码(托盘是 KTCFQ 空托存放区;好运箱是 CXHJQ 空箱货架区) |
| | | /// 终点库区编码 (托盘是 KTCFQ 空托存放区;好运箱是 CXHJQ 空箱货架区) |
| | | /// </summary> |
| | | [JsonProperty("end_area")] |
| | | public string EndArea { get; set; } |
| | | /// <summary> |
| | | /// 起点货位(托盘是 KTJBQ 空托入库接驳区;好运箱是 KXJBQ 空箱入库接驳区) |
| | | /// 起点货位 (托盘是 KTJBQ 空托入库接驳区;好运箱是 KXJBQ 空箱入库接驳区) |
| | | /// </summary> |
| | | [JsonProperty("start_loc")] |
| | | public string StartLoc { get; set; } |
| | |
| | | [JsonProperty("cntr_code")] |
| | | public string CntrCode { get; set; } |
| | | /// <summary> |
| | | /// 不合格移库终点库区(必须是 CJYCQ 抽检异常区) |
| | | /// 不合格移库终点库区 (必须是 CJYCQ 抽检异常区) |
| | | /// </summary> |
| | | [JsonProperty("end_area")] |
| | | public string EndArea { get; set; } |
| | |
| | | [JsonProperty("qualityGrade")] |
| | | public string QualityGrade { get; set; } |
| | | /// <summary> |
| | | /// 料箱编号(待定) |
| | | /// 料箱编号 (待定) |
| | | /// </summary> |
| | | [JsonProperty("cntrCode")] |
| | | public string CntrCode { get; set; } |
| | | /// <summary> |
| | | /// 物料数量(待定) |
| | | /// 物料数量 (待定) |
| | | /// </summary> |
| | | [JsonProperty("itemNum")] |
| | | public int ItemNum { get; set; } |
| | | ///// <summary> |
| | | ///// 产线号(待定,好运箱有2条产线,对应2个下线货位,这里暂定为:3和4) |
| | | ///// 产线号 (待定,好运箱有2条产线,对应2个下线货位,这里暂定为:3和4) |
| | | ///// </summary> |
| | | //[JsonProperty("prodLineId")] |
| | | //public string ProdLineId { get; set; } |
| | |
| | | public int Result { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 是否成功 True-成功,False:失败 |
| | | /// 是否成功 True-成功,False:失败 |
| | | /// </summary> |
| | | [JsonProperty("success")] |
| | | public bool Success { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 这里是string类型,对结果的描述 |
| | | /// 这里是string类型,对结果的描述 |
| | | /// </summary> |
| | | [JsonProperty("data")] |
| | | public string Data { get; set; } |
| | |
| | | if (log) { LogHelper.Info(message); } |
| | | return new MesResult { |
| | | Result = code, |
| | | Success = code == 0, // 仅当code=0时,success=true |
| | | Success = code == 0, // 仅当code=0时,success=true |
| | | Data = message, |
| | | }; |
| | | } |
| | |
| | | /// </summary> |
| | | public class ErpSendOutboundPlanInfo { |
| | | /// <summary> |
| | | /// 计划单号(唯一标识) |
| | | /// 计划单号 (唯一标识) |
| | | /// </summary> |
| | | public string jhdh { get; set; } = string.Empty; |
| | | |
| | |
| | | |
| | | public class PickUpReturnErpInfo { |
| | | /// <summary> |
| | | /// 计划单号(唯一标识) |
| | | /// 计划单号 (唯一标识) |
| | | /// </summary> |
| | | public string jhdh { get; set; } |
| | | |
| | |
| | | |
| | | public class CreateTaskReturnErpInfo { |
| | | /// <summary> |
| | | /// 计划单号(唯一标识) |
| | | /// 计划单号 (唯一标识) |
| | | /// </summary> |
| | | public string jhdh { get; set; } |
| | | |
| | |
| | | |
| | | namespace HH.WCS.Mobox3.DSZSH.api { |
| | | /// <summary> |
| | | /// 测试用:如果项目中要和设备对接,前期设备无法测试,用接口模拟 |
| | | /// 测试用:如果项目中要和设备对接,前期设备无法测试,用接口模拟 |
| | | /// </summary> |
| | | [RoutePrefix("api")] |
| | | public class DebugController : ApiController { |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// DEBUG:模拟输送线产线满托盘下线流程 |
| | | /// DEBUG:模拟输送线产线满托盘下线流程 |
| | | /// </summary> |
| | | /// <param name="model"></param> |
| | | /// <returns></returns> |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// DEBUG:模拟人工将料箱搬运到产线上线口(直接修改数据库) |
| | | /// DEBUG:模拟人工将料箱搬运到产线上线口 (直接修改数据库) |
| | | /// </summary> |
| | | /// <param name="model"></param> |
| | | /// <returns></returns> |
| | |
| | | |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | try { |
| | | // 查询起点货位:数量=0 |
| | | // 查询起点货位:数量=0 |
| | | var startLoc = db.Queryable<TN_Location>().LeftJoin<TN_Loc_Container>((l, c) => l.S_CODE == c.S_LOC_CODE) |
| | | .Where((l,c) => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y" && l.S_CODE == model.StartLoc && l.N_CURRENT_NUM == 1 && c.S_CNTR_CODE == model.CntrCode).First(); |
| | | if (startLoc == null) { |
| | | return $"没有找到起点货位'{model.StartLoc}'!要求:锁状态='无',当前容器数量=1"; |
| | | return $"没有找到起点货位'{model.StartLoc}'!要求:锁状态='无',当前容器数量=1"; |
| | | } |
| | | |
| | | // 查询终点货位 |
| | | // Order:按货位层数,从小到大排列 |
| | | // Order:按货位层数,从小到大排列 |
| | | var endLoc = db.Queryable<TN_Location>().Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y" && l.N_CURRENT_NUM == 0).First(); |
| | | if (endLoc == null) { |
| | | return $"没有找到合适的终点货位!要求:锁状态='无',当前容器数量=0"; |
| | | return $"没有找到合适的终点货位!要求:锁状态='无',当前容器数量=0"; |
| | | } |
| | | |
| | | var locCntrRel = db.Queryable<TN_Loc_Container>().Where(c => c.S_CNTR_CODE == model.CntrCode).First() ; |
| | | if (locCntrRel == null) { |
| | | return $"该容器不存在绑定的货位!"; |
| | | return $"该容器不存在绑定的货位!"; |
| | | } |
| | | |
| | | locCntrRel.S_LOC_CODE = model.StartLoc; |
| | |
| | | db.Updateable(locCntrRel).ExecuteCommand() <= 0) { |
| | | |
| | | tran.RollbackTran(); |
| | | return "数据库操作失败!"; |
| | | return "数据库操作失败!"; |
| | | } |
| | | |
| | | tran.CommitTran() ; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// DEBUG:模拟Erp下发出库计划单 |
| | | /// DEBUG:模拟Erp下发出库计划单 |
| | | /// </summary> |
| | | /// <param name="model"></param> |
| | | /// <returns></returns> |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// (内部方法请勿调用)模拟取货完成反馈Erp回报结果(默认为success) |
| | | /// (内部方法请勿调用) 模拟取货完成反馈Erp回报结果 (默认为success) |
| | | /// </summary> |
| | | /// <param name="model"></param> |
| | | /// <returns></returns> |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// (内部方法请勿调用)模拟任务创建完成反馈Erp回报结果(默认为success) |
| | | /// (内部方法请勿调用) 模拟任务创建完成反馈Erp回报结果 (默认为success) |
| | | /// </summary> |
| | | /// <param name="model"></param> |
| | | /// <returns></returns> |
| | |
| | | |
| | | public class TestErpSendOutboundPlanInfo { |
| | | /// <summary> |
| | | /// 出库计划单号(计划单号 jhdh) |
| | | /// 出库计划单号 (计划单号 jhdh) |
| | | /// </summary> |
| | | public string PlanNo { get; set; } = string.Empty; |
| | | /// <summary> |
| | | /// 物料编码(产品代码 cpdm) |
| | | /// 物料编码 (产品代码 cpdm) |
| | | /// </summary> |
| | | public string ItemCode { get; set; } = string.Empty; |
| | | /// <summary> |
| | | /// 物料数量(派装件数 pzjs) |
| | | /// 物料数量 (派装件数 pzjs) |
| | | /// </summary> |
| | | public float ItemNum { get; set; } = 0; |
| | | } |
| | |
| | | |
| | | public class AddInboundTaskInfo { |
| | | /// <summary> |
| | | /// 物料编码(暂时没用) |
| | | /// 物料编码 (暂时没用) |
| | | /// </summary> |
| | | public string ItemCode { get; set; } |
| | | /// <summary> |
| | | /// 批次号(暂时没用) |
| | | /// 批次号 (暂时没用) |
| | | /// </summary> |
| | | public string BatchNo { get; set; } |
| | | /// <summary> |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 模拟 AGV 传递信号,用于更改任务状态 |
| | | /// 模拟 AGV 传递信号,用于更改任务状态 |
| | | /// </summary> |
| | | public class UpdateTaskState { |
| | | /// <summary> |
| | |
| | | /// </summary> |
| | | public string ForkliftNo { get; set; } |
| | | /// <summary> |
| | | /// AGV 下一状态(任务回报号) |
| | | /// AGV 下一状态 (任务回报号) |
| | | /// </summary> |
| | | public int NextState { set; get; } = 0; |
| | | } |
| | |
| | | else if (model.CntrType == "空好运箱") { |
| | | return ApiHelper.EmptyInboundGoodpack(model); |
| | | } |
| | | else { // PDA前端下拉选单限制,故理论上不会进入这个流程 |
| | | return NewSimpleResult(-1, $"容器类型'{model.CntrType}'不合法!要求:类型=['空托盘','空好运箱']"); |
| | | else { // PDA前端下拉选单限制,故理论上不会进入这个流程 |
| | | return NewSimpleResult(-1, $"容器类型'{model.CntrType}'不合法!要求:类型=['空托盘','空好运箱']"); |
| | | } |
| | | } |
| | | |
| | |
| | | "NdcApiUrl": "http://127.0.0.1:5201/api/order/", // NDC AGV接口地址 |
| | | "ErpApiUrl": "http://127.0.0.1:8901/api/", // ERP接口地址 |
| | | "ErpRoute": { |
| | | "CreateTaskReturn": "CreateTaskReturn", // 根据ERP下发出库计划,创建任务后反馈ERP的接口 |
| | | "PickUpReturn": "PickUpReturn" // 根据ERP下发出库计划,AGV取货后反馈ERP的接口 |
| | | "CreateTaskReturn": "CreateTaskReturn", // 根据ERP下发出库计划,创建任务后反馈ERP的接口 |
| | | "PickUpReturn": "PickUpReturn" // 根据ERP下发出库计划,AGV取货后反馈ERP的接口 |
| | | }, |
| | | "SqlServer": "Data Source=192.168.1.87;Initial Catalog=AMS_OIMobox;User ID=sa;Password=123456;", // 数据库配置 |
| | | "TaskInfos": [ // 任务信息(名称、起点货区、终点货区) |
| | | "TaskInfos": [ // 任务信息 (名称,起点货区,终点货区) |
| | | { |
| | | "TaskName": "满托下线入库", // 任务名称(可以更改,但各任务相对位置不能更改) |
| | | "StartAreas": [ "BZQ" ], // 起点货区编号:包装区 |
| | | "EndAreas": [ "MTHJQ" ] // 终点货区编号:满托货架区 |
| | | "TaskName": "满托下线入库", // 任务名称 (可以更改,但各任务相对位置不能更改) |
| | | "StartAreas": [ "BZQ" ], // 起点货区编号:包装区 |
| | | "EndAreas": [ "MTHJQ" ] // 终点货区编号:满托货架区 |
| | | }, |
| | | { |
| | | "TaskName": "满箱下线入库", |
| | |
| | | }, |
| | | { |
| | | "TaskName": "成品胶出库", |
| | | "StartAreas": [ "MTHJQ", "MXHJQ", "HCBHQ", "QCBHQ" ], // 满托货架区、满箱货架区、火车备货区、汽车备货区 |
| | | "EndAreas": [ "HCCKQ", "QCCKQ" ] // 火车出库区、汽车出库区 |
| | | "StartAreas": [ "MTHJQ", "MXHJQ", "HCBHQ", "QCBHQ" ], // 满托货架区,满箱货架区,火车备货区,汽车备货区 |
| | | "EndAreas": [ "HCCKQ", "QCCKQ" ] // 火车出库区,汽车出库区 |
| | | }, |
| | | { |
| | | "TaskName": "空托上线出库", |
| | |
| | | }, |
| | | { |
| | | "TaskName": "空箱入库", |
| | | "StartAreas": [ "KXJBQ1", "KXJBQ2" ], // 空箱入库接驳区1、2 |
| | | "StartAreas": [ "KXJBQ1", "KXJBQ2" ], // 空箱入库接驳区1,2 |
| | | "EndAreas": [ "KXHJQ" ] // 空箱货架区 |
| | | }, |
| | | { |
| | | "TaskName": "抽检出库", |
| | | "StartAreas": [ "MTHJQ", "MXHJQ" ], // 满托货架区、满箱货架区 |
| | | "StartAreas": [ "MTHJQ", "MXHJQ" ], // 满托货架区,满箱货架区 |
| | | "EndAreas": [ "CJQ" ] // 抽检区 |
| | | }, |
| | | { |
| | | "TaskName": "抽检合格回库", |
| | | "StartAreas": [ "CJQ" ], // 抽检区 |
| | | "EndAreas_Pallet": [ "MTHJQ" ], // 终点货区(托盘):满托货架区 |
| | | "EndAreas_Goodpack": [ "MXHJQ" ] // 终点货区(好运箱):满箱货架区 |
| | | "EndAreas_Pallet": [ "MTHJQ" ], // 终点货区 (托盘) :满托货架区 |
| | | "EndAreas_Goodpack": [ "MXHJQ" ] // 终点货区 (好运箱) :满箱货架区 |
| | | }, |
| | | { |
| | | "TaskName": "抽检不合格移库", |
| | |
| | | "TaskName": "移库" |
| | | } |
| | | ], |
| | | "ProductionLines": [ // 产线信息(待定,根据后面需求再更改) |
| | | "ProductionLines": [ // 产线信息 (待定,根据后面需求再更改) |
| | | { |
| | | "Id": "1", // 产线编号 |
| | | "Name": "托盘产线1", // 产线名称 |
| | | "PlcIp": "127.0.0.1", // 产线IP |
| | | "PlcPort": 502, // 产线端口 |
| | | "SlaveId": 1, // 产线modbus slave id(根据实际情况) |
| | | "SlaveId": 1, // 产线modbus slave id (根据实际情况) |
| | | "OnLoc": [ "BZQ-1-1" ], // 上线货位 |
| | | "OffLoc": [ "BZQ-1-2" ] // 下线货位 |
| | | }, |
| | |
| | | //TcpClientHelper.Link("127.0.0.1", 8550); // 用于测试 |
| | | TcpClientHelper.Link(prod.PlcIp, prod.PlcPort); |
| | | |
| | | // TCPClient传递信息的时候,不要用断点阻塞程序 |
| | | // TCPClient传递信息的时候,不要用断点阻塞程序 |
| | | // {"item_code":"CG1001","batch_no":"BN1001","cntr_code":"CN2505111"} |
| | | if (!TcpClientHelper.TryReadProductionLine(out byte[] read)) { |
| | | info = $"测试{prod.Id}号产线{prod.PlcIp}:{prod.PlcPort}:读取产线信息失败"; |
| | | info = $"测试{prod.Id}号产线{prod.PlcIp}:{prod.PlcPort}:读取产线信息失败"; |
| | | LogHelper.Info(info); |
| | | continue; |
| | | } |
| | |
| | | |
| | | public static void CheckOutboundOrder() { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var info = ""; |
| | | |
| | | var taskInfo = Settings.GetTaskInfo(ETask.C成品胶出库); |
| | | var taskName = taskInfo.TaskName; |
| | | var taskName = "出库"; |
| | | const string preLog = "轮询:出库:"; |
| | | |
| | | try { |
| | | var orderList = db.Queryable<TN_Outbound_Order>() |
| | | .Where(c => c.N_B_STATE == 1) |
| | | .OrderBy(c => c.T_CREATE, SqlSugar.OrderByType.Asc) |
| | | .ToList(); |
| | | |
| | | var orderList = db.Queryable<TN_Outbound_Order>().Where(c => c.N_B_STATE == 1).OrderBy(c => c.T_CREATE).ToList(); |
| | | if (orderList.Count == 0) { |
| | | info = $"轮询:{taskName}:暂无待执行的{taskName}单"; |
| | | LogHelper.Info(info); |
| | | LogHelper.Debug(preLog + $"暂无待执行的{taskName}单"); |
| | | return; |
| | | } |
| | | |
| | |
| | | |
| | | var detailList = new List<TN_Outbound_Detail>(); |
| | | foreach (var order in orderList) { |
| | | var doingCount = db.Queryable<TN_Outbound_Detail>() |
| | | .Count(d => d.S_OO_NO == order.S_NO && d.N_B_STATE >= 2); // 执行中 |
| | | var allCount = db.Queryable<TN_Outbound_Detail>() |
| | | .Count(d => d.S_OO_NO == order.S_NO); |
| | | info = $"轮询:{taskName}:统计{taskName}单'{order.S_NO}'任务已下发:{doingCount}/{allCount}"; |
| | | LogHelper.Info(info); |
| | | var doingCount = db.Queryable<TN_Outbound_Detail>().Count(d => d.S_OO_NO == order.S_NO && d.N_B_STATE >= 2); |
| | | var allCount = db.Queryable<TN_Outbound_Detail>().Count(d => d.S_OO_NO == order.S_NO); |
| | | LogHelper.Info(preLog + $"统计{taskName}单'{order.S_NO}'任务已下发:{doingCount}/{allCount}"); |
| | | |
| | | if (doingCount == allCount) { |
| | | order.N_B_STATE = 2; // 所有任务都已执行 |
| | |
| | | .First(); |
| | | |
| | | if (lastDetail != null) { |
| | | info = $"轮询:{taskName}:{taskName}单'{order.S_NO}'上一个任务仍在进行中:" + JsonConvert.SerializeObject(lastDetail); |
| | | LogHelper.Info(info); |
| | | LogHelper.Info(preLog + $"{taskName}单'{order.S_NO}'上一个任务仍在进行中:" + JsonConvert.SerializeObject(lastDetail)); |
| | | continue; |
| | | } |
| | | |
| | |
| | | .First(); |
| | | |
| | | if (outboundDetail == null) { |
| | | info = $"轮询:{taskName}:仍有任务未执行完成,但当前没有已下发的任务"; |
| | | LogHelper.Info(info); |
| | | LogHelper.Info(preLog + $"仍有任务未执行完成,但当前没有已下发的任务!"); |
| | | continue; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | foreach (var detail in detailList) { |
| | | var startLoc = db.Queryable<TN_Location>() |
| | | .LeftJoin<TN_Loc_Container>((l, c) => l.S_CODE == c.S_LOC_CODE) |
| | | .Where((l, c) => c.S_CNTR_CODE == detail.S_CNTR_CODE) // 根据容器号搜索起点货位 |
| | | .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") // 筛选:未上锁 |
| | | .Where(l => l.N_CURRENT_NUM == 1) |
| | | .First(); |
| | | var startLoc = db.Queryable<TN_Location>().LeftJoin<TN_Loc_Container>((l, c) => l.S_CODE == c.S_LOC_CODE).Where((l, c) => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y" && l.N_CURRENT_NUM == 1 && c.S_CNTR_CODE == detail.S_CNTR_CODE).First(); |
| | | |
| | | if (startLoc == null) { |
| | | info = $"轮询:{taskName}:没有找到合适的起点货位!"; |
| | | LogHelper.Info(info); |
| | | LogHelper.Info(preLog + $"没有找到合适的起点货位!"); |
| | | continue; |
| | | } |
| | | |
| | |
| | | .Where(a => a.N_CURRENT_NUM == 0).First(); |
| | | |
| | | if (endLoc == null) { |
| | | info = $"轮询:{taskName}:没有找到合适的终点货位!单号'{detail.S_OO_NO}'要求终点库区为'{detail.S_END_AREA}'"; |
| | | LogHelper.Info(info); |
| | | LogHelper.Info(preLog + $"没有找到合适的终点货位!单号'{detail.S_OO_NO}'要求终点库区为'{detail.S_END_AREA}'"); |
| | | continue; |
| | | } |
| | | |
| | |
| | | using (var tran = db.Ado.UseTran()) { |
| | | if (db.Updateable(detail).UpdateColumns(it => it.N_B_STATE).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | info = $"轮询:{taskName}:修改明细表状态为完成--失败!"; |
| | | LogHelper.Info(info); |
| | | LogHelper.Info($"轮询:{taskName}:修改明细表状态为完成--失败!"); |
| | | continue; |
| | | } |
| | | |
| | | if (db.Updateable(startLoc).UpdateColumns(it => new { |
| | | it.N_LOCK_STATE, |
| | | it.S_LOCK_STATE, |
| | | it.S_LOCK_OP, |
| | | it.T_MODIFY, |
| | | it.N_CURRENT_NUM, // 起点货位绑定后,将货位状态更新 |
| | | }).ExecuteCommand() <= 0) { |
| | | // 更新[起点/终点]锁状态,创建任务 |
| | | if (db.Updateable(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, it.N_CURRENT_NUM, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | info = $"生成任务'{taskName}'失败:更新起点货位{startLoc.S_CODE}锁状态失败"; |
| | | LogHelper.Info(info); |
| | | continue; |
| | | LogHelper.Info(preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | } |
| | | |
| | | if (db.Updateable(endLoc).UpdateColumns(it => new { |
| | | it.N_LOCK_STATE, |
| | | it.S_LOCK_STATE, |
| | | it.S_LOCK_OP, |
| | | it.T_MODIFY, |
| | | }).ExecuteCommand() <= 0) { |
| | | if (db.Updateable(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | info = $"生成任务'{taskName}'失败:更新终点货位{endLoc.S_CODE}锁状态失败"; |
| | | LogHelper.Info(info); |
| | | continue; |
| | | LogHelper.Info(preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | } |
| | | |
| | | if (db.Insertable(task).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | info = $"生成任务'{taskName}'失败,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}"; |
| | | LogHelper.Info(info); |
| | | continue; |
| | | LogHelper.Info(preLog + $"生成任务'{task.S_TYPE}'失败!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | |
| | | // 提交数据库更改 |
| | | tran.CommitTran(); |
| | | info = $"生成任务'{taskName}'成功,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}"; |
| | | LogHelper.Info(info); |
| | | //continue; |
| | | LogHelper.Info(preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}"); |
| | | } |
| | | |
| | | // 如果当前出库单明细是ERP下发的,任务创建完成反馈货位信息 |
| | | // 如果当前出库单明细是ERP下发的,任务创建完成反馈货位信息 |
| | | if (detail.S_BS_TYPE == "ERP") { |
| | | //var createTaskReturnErpTask = Task.Run(() => { |
| | | // CreateTaskReturnErp(task); |
| | |
| | | |
| | | } |
| | | catch (Exception ex) { |
| | | info = $"轮询:{taskName}:发生了异常:{ex.Message}"; |
| | | LogHelper.InfoEx(ex); |
| | | LogHelper.InfoEx(ex, preLog); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | var taskInfo = Settings.GetTaskInfo(ETask.C抽检出库); |
| | | var taskName = taskInfo.TaskName; |
| | | const string preLog = "轮询:抽检:"; |
| | | |
| | | try { |
| | | var orderList = db.Queryable<TN_Spot_Check>() |
| | | .Where(c => c.N_B_STATE == 1) |
| | | .OrderBy(c => c.T_CREATE, SqlSugar.OrderByType.Asc) |
| | | .ToList(); |
| | | |
| | | var orderList = db.Queryable<TN_Spot_Check>().Where(c => c.N_B_STATE == 1).OrderBy(c => c.T_CREATE).ToList(); |
| | | if (orderList.Count == 0) { |
| | | LogHelper.Info($"轮询:{taskName}:暂无待执行的{taskName}单"); |
| | | LogHelper.Debug($"轮询:{taskName}:暂无待执行的{taskName}单"); |
| | | return; |
| | | } |
| | | |
| | | var detailList = new List<TN_SpotCheck_Detail>(); |
| | | foreach (var order in orderList) { |
| | | var doingCount = db.Queryable<TN_SpotCheck_Detail>() |
| | | .Count(d => d.S_OO_NO == order.S_NO && d.N_B_STATE >= 2); // 执行中 |
| | | var allCount = db.Queryable<TN_SpotCheck_Detail>() |
| | | .Count(d => d.S_OO_NO == order.S_NO); |
| | | LogHelper.Info($"轮询:{taskName}:统计{taskName}单'{order.S_NO}'任务已下发:{doingCount}/{allCount}"); |
| | | var doingCount = db.Queryable<TN_SpotCheck_Detail>().Count(d => d.S_OO_NO == order.S_NO && d.N_B_STATE >= 2); |
| | | var allCount = db.Queryable<TN_SpotCheck_Detail>().Count(d => d.S_OO_NO == order.S_NO); |
| | | LogHelper.Info(preLog + $"统计{taskName}单'{order.S_NO}'任务已下发:{doingCount}/{allCount}"); |
| | | |
| | | if (doingCount == allCount) { |
| | | order.N_B_STATE = 2; // 所有任务都已执行 |
| | |
| | | .ToList(); |
| | | |
| | | if (checkDetailList.Count == 0) { |
| | | LogHelper.Info($"轮询:{taskName}:仍有任务未执行完成,但当前没有已下发的任务"); |
| | | LogHelper.Info($"轮询:{taskName}:仍有任务未执行完成,但当前没有已下发的任务"); |
| | | continue; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | foreach (var detail in detailList) { |
| | | var startLoc = db.Queryable<TN_Location>() |
| | | .LeftJoin<TN_Loc_Container>((l, c) => l.S_CODE == c.S_LOC_CODE) |
| | | .Where((l, c) => c.S_CNTR_CODE == detail.S_CNTR_CODE) |
| | | .First(); |
| | | var startLoc = db.Queryable<TN_Location>() .LeftJoin<TN_Loc_Container>((l, c) => l.S_CODE == c.S_LOC_CODE) |
| | | .Where((l, c) => c.S_CNTR_CODE == detail.S_CNTR_CODE).First(); |
| | | |
| | | if (startLoc == null) { |
| | | LogHelper.Info($"轮询:{taskName}:没有找到合适的起点货位!"); |
| | | LogHelper.Info($"轮询:{taskName}:没有找到合适的起点货位!"); |
| | | continue; |
| | | } |
| | | |
| | | var endLoc = db.Queryable<TN_Location>() |
| | | .Where(l => l.S_AREA_CODE == detail.S_END_AREA) |
| | | .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 |
| | | .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 |
| | | .Where(a => a.N_CURRENT_NUM == 0).First(); |
| | | |
| | | if (endLoc == null) { |
| | | LogHelper.Info($"轮询:{taskName}:没有找到合适的终点货位!"); |
| | | LogHelper.Info($"轮询:{taskName}:没有找到合适的终点货位!"); |
| | | continue; |
| | | } |
| | | |
| | |
| | | var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); |
| | | task.S_OP_CODE = detail.S_OO_NO; |
| | | |
| | | WCSHelper.LockStartLoc(ref startLoc); // 起点出库锁 |
| | | WCSHelper.LockEndLoc(ref endLoc); // 终点入库锁 |
| | | WCSHelper.LockStartLoc(ref startLoc); |
| | | WCSHelper.LockEndLoc(ref endLoc); |
| | | |
| | | using (var tran = db.Ado.UseTran()) { |
| | | if (db.Updateable(detail).UpdateColumns(it => it.N_B_STATE).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | LogHelper.Info($"轮询:{taskName}:修改{taskName}单明细表状态为完成--失败!"); |
| | | LogHelper.Info($"轮询:{taskName}:修改{taskName}单明细表状态为完成--失败!"); |
| | | continue; |
| | | } |
| | | |
| | | if (db.Updateable(startLoc).UpdateColumns(it => new { |
| | | it.N_LOCK_STATE, |
| | | it.S_LOCK_STATE, |
| | | it.S_LOCK_OP, |
| | | it.T_MODIFY, |
| | | it.N_CURRENT_NUM, // 起点货位绑定后,将货位状态更新 |
| | | }).ExecuteCommand() <= 0) { |
| | | if (db.Updateable(startLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, it.N_CURRENT_NUM, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | info = $"生成任务'{taskName}'失败:更新起点货位{startLoc.S_CODE}锁状态失败"; |
| | | LogHelper.Info(info); |
| | | LogHelper.Info(preLog + $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态=>'出库锁'"); |
| | | continue; |
| | | } |
| | | |
| | | if (db.Updateable(endLoc).UpdateColumns(it => new { |
| | | it.N_LOCK_STATE, |
| | | it.S_LOCK_STATE, |
| | | it.S_LOCK_OP, |
| | | it.T_MODIFY, |
| | | }).ExecuteCommand() <= 0) { |
| | | if (db.Updateable(endLoc).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | info = $"生成任务'{taskName}'失败:更新终点货位{endLoc.S_CODE}锁状态失败"; |
| | | LogHelper.Info(info); |
| | | LogHelper.Info(preLog + $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态=>'入库锁'"); |
| | | continue; |
| | | } |
| | | |
| | | if (db.Insertable(task).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | info = $"生成任务'{taskName}'失败,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}"; |
| | | info = $"生成任务'{taskName}'失败,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}"; |
| | | LogHelper.Info(info); |
| | | continue; |
| | | } |
| | | |
| | | tran.CommitTran(); |
| | | info = $"生成任务'{taskName}'成功,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}"; |
| | | info = $"生成任务'{taskName}'成功,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}"; |
| | | LogHelper.Info(info); |
| | | continue; |
| | | } |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.InfoEx(ex); |
| | | LogHelper.InfoEx(ex, preLog); |
| | | } |
| | | } |
| | | |
| | |
| | | |
| | | var taskInfo = Settings.GetTaskInfo(ETask.Y移库); |
| | | var taskName = taskInfo.TaskName; |
| | | const string preLog = "轮询:移库:"; |
| | | |
| | | try { |
| | | var orderList = db.Queryable<TN_Relocation_List>() |
| | |
| | | .ToList(); |
| | | |
| | | if (orderList.Count == 0) { |
| | | LogHelper.Info($"轮询:{taskName}:暂无待执行的{taskName}单"); |
| | | LogHelper.Debug($"轮询:{taskName}:暂无待执行的{taskName}单"); |
| | | return; |
| | | } |
| | | |
| | |
| | | .Count(d => d.S_OO_NO == order.S_NO && d.N_B_STATE >= 2); // 执行中 |
| | | var allCount = db.Queryable<TN_RelocationList_Detail>() |
| | | .Count(d => d.S_OO_NO == order.S_NO); |
| | | LogHelper.Info($"轮询:{taskName}:统计{taskName}单={order.S_NO}任务已下发:{doingCount}/{allCount}"); |
| | | LogHelper.Info($"轮询:{taskName}:统计{taskName}单={order.S_NO}任务已下发:{doingCount}/{allCount}"); |
| | | |
| | | if (doingCount == allCount) { |
| | | order.N_B_STATE = 2; // 所有任务都已执行 |
| | |
| | | .ToList(); |
| | | |
| | | if (checkDetailList.Count == 0) { |
| | | LogHelper.Info($"轮询:{taskName}:仍有任务未执行完成,但当前没有已下发的任务"); |
| | | LogHelper.Info($"轮询:{taskName}:仍有任务未执行完成,但当前没有已下发的任务"); |
| | | continue; |
| | | } |
| | | |
| | |
| | | var startLoc = db.Queryable<TN_Location>() |
| | | .LeftJoin<TN_Loc_Container>((l, c) => l.S_CODE == c.S_LOC_CODE) |
| | | .Where((l, c) => c.S_CNTR_CODE == detail.S_CNTR_CODE) |
| | | .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") // 筛选:未上锁 |
| | | .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y") // 筛选:未上锁 |
| | | .Where(l => l.N_CURRENT_NUM == 1) |
| | | .First(); |
| | | |
| | | if (startLoc == null) { |
| | | info = $"轮询:{taskName}:没有找到容器号={detail.S_CNTR_CODE}的起点货位!需要满足:未上锁、当前容器数量=1"; |
| | | info = $"轮询:{taskName}:没有找到容器号={detail.S_CNTR_CODE}的起点货位!需要满足:未上锁,当前容器数量=1"; |
| | | LogHelper.Info(info); |
| | | continue; |
| | | } |
| | | |
| | | var endLoc = db.Queryable<TN_Location>() |
| | | .Where(l => l.S_AREA_CODE == detail.S_END_AREA) |
| | | .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 |
| | | .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 |
| | | .Where(a => a.N_CURRENT_NUM == 0).First(); |
| | | |
| | | if (endLoc == null) { |
| | | info = $"轮询:{taskName}:没有找到终点货位={detail.S_END_AREA}的终点货位!需要满足:未上锁、当前容器数量=0"; |
| | | info = $"轮询:{taskName}:没有找到终点货位={detail.S_END_AREA}的终点货位!需要满足:未上锁,当前容器数量=0"; |
| | | LogHelper.Info(info); |
| | | continue; |
| | | } |
| | |
| | | using (var tran = db.Ado.UseTran()) { |
| | | if (db.Updateable(detail).UpdateColumns(it => it.N_B_STATE).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | LogHelper.Info($"轮询:{taskName}:修改{taskName}单明细表状态为完成--失败!"); |
| | | LogHelper.Info($"轮询:{taskName}:修改{taskName}单明细表状态为完成--失败!"); |
| | | continue; |
| | | } |
| | | |
| | |
| | | it.S_LOCK_STATE, |
| | | it.S_LOCK_OP, |
| | | it.T_MODIFY, |
| | | it.N_CURRENT_NUM, // 起点货位绑定后,将货位状态更新 |
| | | it.N_CURRENT_NUM, // 起点货位绑定后,将货位状态更新 |
| | | }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | info = $"生成任务'{taskName}'失败:更新起点货位{startLoc.S_CODE}锁状态失败"; |
| | | info = $"生成任务'{taskName}'失败:更新起点货位{startLoc.S_CODE}锁状态失败"; |
| | | LogHelper.Info(info); |
| | | continue; |
| | | } |
| | |
| | | it.T_MODIFY, |
| | | }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | info = $"生成任务'{taskName}'失败:更新终点货位{endLoc.S_CODE}锁状态失败"; |
| | | info = $"生成任务'{taskName}'失败:更新终点货位{endLoc.S_CODE}锁状态失败"; |
| | | LogHelper.Info(info); |
| | | continue; |
| | | } |
| | | |
| | | if (db.Insertable(task).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | info = $"生成任务'{taskName}'失败,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}"; |
| | | info = $"生成任务'{taskName}'失败,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}"; |
| | | LogHelper.Info(info); |
| | | continue; |
| | | } |
| | | |
| | | tran.CommitTran(); |
| | | info = $"生成任务'{taskName}'成功,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}"; |
| | | info = $"生成任务'{taskName}'成功,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}"; |
| | | LogHelper.Info(info); |
| | | continue; |
| | | } |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.InfoEx(ex); |
| | | LogHelper.InfoEx(ex, preLog); |
| | | } |
| | | } |
| | | |
| | |
| | | .First(); |
| | | |
| | | if (plan == null) { |
| | | info = $"计划单号{task.S_BS_NO}不存在!"; |
| | | info = $"计划单号{task.S_BS_NO}不存在!"; |
| | | LogHelper.Info(info); |
| | | } |
| | | |
| | |
| | | .First(); |
| | | |
| | | if (cgDetail == null) { |
| | | info = $"物料编码不存在!"; |
| | | info = $"物料编码不存在!"; |
| | | LogHelper.Info(info); |
| | | } |
| | | |
| | | var model = new OtherModel.CreateTaskReturnErpInfo { |
| | | jhdh = plan.JHDH , // 计划单号(唯一标识) |
| | | ckzt = plan.CKZT , // 出库状态(需要返回) |
| | | jhdh = plan.JHDH , // 计划单号 (唯一标识) |
| | | ckzt = plan.CKZT , // 出库状态 (需要返回) |
| | | jhlb = plan.JHLB , // 计划类别 |
| | | ckdh = plan.CKDH , // 参考单号 |
| | | cph = plan.CPH , // 车牌号 |
| | |
| | | cplb = plan.CPLB , // 产品类别 |
| | | cplbmx = plan.CPLBMX , // 产品类别明细 |
| | | pp = plan.PP , // 品牌 |
| | | dj = plan.DJ , // 等级(需要返回) |
| | | dj = plan.DJ , // 等级 (需要返回) |
| | | gh = plan.GH , // 罐号 |
| | | ph = plan.PH , // 批号(需要返回) |
| | | ph = plan.PH , // 批号 (需要返回) |
| | | bzlx = plan.BZLX , // 包装类型 |
| | | pzdh = plan.PZDH , // 派装单号 |
| | | pzd_dw = plan.PZD_DW , // 派装单单位 |
| | |
| | | pz_zfrq = plan.PZ_ZFRQ , // 派装作废日期 |
| | | pz_bz = plan.PZ_BZ , // 派装备注 |
| | | ckdbh = plan.CKDBH , // 出库单编号 |
| | | //sfjs = plan.SFJS , // 实发件数(需要返回) |
| | | //sfsl = plan.SFSL , // 实发数量(需要返回) |
| | | //sfcs = plan.SFCS , // 实发车数(需要返回) |
| | | //zcsj = plan.ZCSJ , // 装车时间(需要返回) |
| | | //jldw = plan.JLDW , // 计量单位(需要返回) |
| | | //fhrq = plan.FHRQ , // 发货日期(需要返回) |
| | | //ckdm = plan.CKDM , // 仓库代码(需要返回) |
| | | //fhr = plan.FHR , // 发货人(需要返回) |
| | | //czydm = plan.CZYDM , // 操作员(需要返回) |
| | | //sfjs = plan.SFJS , // 实发件数 (需要返回) |
| | | //sfsl = plan.SFSL , // 实发数量 (需要返回) |
| | | //sfcs = plan.SFCS , // 实发车数 (需要返回) |
| | | //zcsj = plan.ZCSJ , // 装车时间 (需要返回) |
| | | //jldw = plan.JLDW , // 计量单位 (需要返回) |
| | | //fhrq = plan.FHRQ , // 发货日期 (需要返回) |
| | | //ckdm = plan.CKDM , // 仓库代码 (需要返回) |
| | | //fhr = plan.FHR , // 发货人 (需要返回) |
| | | //czydm = plan.CZYDM , // 操作员 (需要返回) |
| | | shr_username = plan.SHR_USERNAME , // 审核人 |
| | | shrq = plan.SHRQ , // 审核日期 |
| | | zfbj = plan.ZFBJ , // 作废标记 |
| | |
| | | shdw = plan.SHDW , // 收货单位 |
| | | ysdw = plan.YSDW , // 运输单位 |
| | | lxr = plan.LXR , // 联系人 |
| | | //ry_zxg = plan.RY_ZXG , // 装卸工(需要返回) |
| | | //ry_ccsj = plan.RY_CCSJ , // 叉车司机(需要返回) |
| | | //ry_zxg = plan.RY_ZXG , // 装卸工 (需要返回) |
| | | //ry_ccsj = plan.RY_CCSJ , // 叉车司机 (需要返回) |
| | | erphx_jhdh = plan.ERPHX_JHDH , // erp交货单号 |
| | | erphx_wlbm = plan.ERPHX_WLBM , // erp物料编码 |
| | | erphx_wlmc = plan.ERPHX_WLMC , // erp物料名称 |
| | | erphx_cjrq = plan.ERPHX_CJRQ , // erp创建日期 |
| | | hw = plan.HW , // 货位(需要返回) |
| | | hwzt = plan.HWZT // 货位状态(需要返回) |
| | | hw = plan.HW , // 货位 (需要返回) |
| | | hwzt = plan.HWZT // 货位状态 (需要返回) |
| | | }; |
| | | model.hw = task.S_START_LOC; |
| | | model.hwzt = "待出库"; |
| | |
| | | var jsonInfo = JsonConvert.SerializeObject(model); |
| | | var result = httpH.WebPost(Settings.ErpApiUrl + Settings.ErpRoute.CreateTaskReturn, jsonInfo); |
| | | |
| | | LogHelper.InfoApi($"创建任务完成反馈ERP接口,结果={result},调用参数:", model); |
| | | LogHelper.InfoApi($"创建任务完成反馈ERP接口,结果={result},调用参数:", model); |
| | | |
| | | plan.HW = model.hw; |
| | | plan.HWZT = model.hwzt; |
| | |
| | | namespace HH.WCS.Mobox3.DSZSH.core { |
| | | public class WCSCore { |
| | | public static ReturnResult OperateAgvTaskStatus(AgvTaskState model) { |
| | | const string preLog = "AGV:任务状态回报:"; |
| | | const string preLog = "AGV:任务状态回报:"; |
| | | try { |
| | | if (model.state > 0) { |
| | | // AGV 执行任务的逻辑处理 |
| | | if (!AgvTaskProcessOk(model)) { |
| | | // 执行不OK,说明没有找到任务 |
| | | return NewReturnResult(1, preLog + $"根据任务号'{model.task_no}'未找到对应的任务!"); |
| | | // 执行不OK,说明没有找到任务 |
| | | return NewReturnResult(1, preLog + $"根据任务号'{model.task_no}'未找到对应的任务!"); |
| | | } |
| | | } |
| | | |
| | | return NewReturnResult(0, "success"); // 不返回详细成功日志,避免NDC以msg=success作为成功判定(参考国自) |
| | | return NewReturnResult(0, "success"); // 不返回详细成功日志,避免NDC以msg=success作为成功判定 (参考国自) |
| | | } |
| | | catch (Exception ex) { |
| | | return NewReturnResult(-1, $"发生了异常:{ex.Message}\n{ex.StackTrace}"); |
| | | return NewReturnResult(-1, $"发生了异常:{ex.Message}\n\n{ex.StackTrace}\n"); |
| | | } |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 执行 AGV 任务,查询不到任务返回 <see langword="false"/> |
| | | /// 执行 AGV 任务,查询不到任务返回 <see langword="false"/> |
| | | /// </summary> |
| | | /// <param name="model"></param> |
| | | /// <returns></returns> |
| | |
| | | break; |
| | | } |
| | | |
| | | // 将AGV执行状态,加入TN_Task_Action表中 |
| | | // 将AGV执行状态,加入TN_Task_Action表中 |
| | | WCSHelper.AddActionRecord(model.task_no, model.state, model.forklift_no, model.ext_data); |
| | | //调用第三方接口(如果有)TaskProcess.ReportStatus,添加任务动作关系表 |
| | | //调用第三方接口 (如果有) TaskProcess.ReportStatus,添加任务动作关系表 |
| | | |
| | | return true; |
| | | } |
| | |
| | | var info = ""; |
| | | |
| | | try { |
| | | var cgDetail = new TN_CG_Detail(); // 如果没有信息,默认就是空值,可以直接填入,不需要判断 |
| | | var cgDetail = new TN_CG_Detail(); // 如果没有信息,默认就是空值,可以直接填入,不需要判断 |
| | | |
| | | //var emptyTask = false; // 空托/空箱任务 |
| | | if (task.S_TYPE != ETask.K空托上线出库.Name() && task.S_TYPE != ETask.K空托入库.Name() && |
| | | task.S_TYPE != ETask.K空箱上线出库.Name() && task.S_TYPE != ETask.K空箱入库.Name()) { |
| | | // 非空托/空箱任务(空托/空箱任务无法在CGDetail查到物料信息) |
| | | // 非空托/空箱任务 (空托/空箱任务无法在CGDetail查到物料信息) |
| | | //emptyTask= true; |
| | | cgDetail = db.Queryable<TN_CG_Detail>() |
| | | .Where(d => d.S_CNTR_CODE == task.S_CNTR_CODE) |
| | | .First(); |
| | | |
| | | if (cgDetail == null) { |
| | | info = $"任务{task.S_CODE}完成,记录出入库存在问题:无法在容器货品明细表中找到托盘{task.S_CNTR_CODE}对应的物料"; |
| | | info = $"任务{task.S_CODE}完成,记录出入库存在问题:无法在容器货品明细表中找到托盘{task.S_CNTR_CODE}对应的物料"; |
| | | LogHelper.Info(info); |
| | | //return; |
| | | cgDetail = new TN_CG_Detail() ; |
| | |
| | | } |
| | | } |
| | | |
| | | var isInbound = false; // 入库类型的任务(包括移库类任务) |
| | | var isInbound = false; // 入库类型的任务 (包括移库类任务) |
| | | var inboundTasks = new List<string> { |
| | | ETask.M满托下线入库.Name(), ETask.M满箱下线入库.Name(), ETask.K空托入库.Name(), ETask.K空箱入库.Name(), |
| | | ETask.C抽检合格回库.Name(), ETask.C抽检不合格移库.Name(), ETask.Y移库.Name() |
| | |
| | | S_ITEM_CODE = cgDetail.S_ITEM_CODE, |
| | | S_BATCH_NO = cgDetail.S_BATCH_NO, |
| | | S_ITEM_NAME = cgDetail.S_ITEM_NAME, |
| | | S_LOC_CODE = isInbound ? task.S_END_LOC : task.S_START_LOC, // 入库记录终点货位,出库记录起点货位 |
| | | S_LOC_CODE = isInbound ? task.S_END_LOC : task.S_START_LOC, // 入库记录终点货位,出库记录起点货位 |
| | | S_CNTR_CODE = task.S_CNTR_CODE, |
| | | S_ITEM_SPEC = cgDetail.S_ITEM_SPEC, |
| | | S_NET_WEIGHT = cgDetail.S_NET_WEIGHT, |
| | |
| | | S_TASK_NO = task.S_CODE, |
| | | T_RECORD_TIME = DateTime.Now, |
| | | S_TYPE = task.S_TYPE, |
| | | S_BS_CODE = task.S_BS_NO, // ERP单号,默认为空 |
| | | S_BS_CODE = task.S_BS_NO, // ERP单号,默认为空 |
| | | N_QTY = cgDetail.N_ITEM_NUM, |
| | | S_NO = task.S_OP_CODE, // 出库/抽检/移库单 |
| | | }; |
| | | |
| | | // 数据库操作 |
| | | if (db.Insertable(record).ExecuteCommand() <= 0) { |
| | | info = "插入出入库记录表失败:" + JsonConvert.SerializeObject(record); |
| | | info = "插入出入库记录表失败:" + JsonConvert.SerializeObject(record); |
| | | LogHelper.Info(info); |
| | | return; |
| | | } |
| | |
| | | /// <returns></returns> |
| | | public static ReturnResult SafetyInteraction(SafetyInteractionInfo model) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | const string preLog = "AGV:产线安全交互:"; |
| | | const string preLog = "AGV:产线安全交互:"; |
| | | |
| | | try { |
| | | ModbusHelper.Relink(); |
| | |
| | | //} |
| | | |
| | | if (prodLineDevice.SystemState != 1) { |
| | | return NewReturnResult(3, preLog + $"当前产线无法与AGV联动:状态{prodLineDevice.SystemState}"); |
| | | return NewReturnResult(3, preLog + $"当前产线无法与AGV联动:状态{prodLineDevice.SystemState}"); |
| | | } |
| | | |
| | | // 请求取货 |
| | | if (model.apply_code == "5") { |
| | | if (prodLineDevice.FullOffline != 1) { |
| | | return NewReturnResult(4, preLog + $"当前输送线满料下线信号不为1,无法取货"); |
| | | return NewReturnResult(4, preLog + $"当前输送线满料下线信号不为1,无法取货"); |
| | | } |
| | | |
| | | if (!prodLineDevice.SetAgvPicking(1)) { |
| | |
| | | // 请求卸货 |
| | | else if (model.apply_code == "1") { |
| | | if (prodLineDevice.AllowAgvPlacePallet != 1) { |
| | | return NewReturnResult(6, preLog + $"当前输送线允许放托盘信号不为1,无法放货"); |
| | | return NewReturnResult(6, preLog + $"当前输送线允许放托盘信号不为1,无法放货"); |
| | | } |
| | | |
| | | if (!prodLineDevice.SetAgvPlacingPallet(1)) { |
| | |
| | | |
| | | } |
| | | catch (Exception ex) { |
| | | return NewReturnResult(1, preLog + $"发生了异常:{ex.Message}\n{ex.StackTrace}"); |
| | | return NewReturnResult(1, preLog + $"发生了异常:{ex.Message}\n\n{ex.StackTrace}\n"); |
| | | } |
| | | } |
| | | |
| | |
| | | .First(d => d.N_B_STATE == 2); |
| | | |
| | | if (detail == null) { |
| | | LogHelper.Info($"{taskName}:AGV取货:查询明细单:当前没有执行中的明细单"); |
| | | LogHelper.Info($"{taskName}:AGV取货:查询明细单:当前没有执行中的明细单"); |
| | | return; |
| | | } |
| | | |
| | |
| | | detail.N_B_STATE = spotStateCode; |
| | | if (db.Updateable(detail).UpdateColumns(it => it.N_B_STATE).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | LogHelper.Info($"{taskName}:AGV取货:修改明细单状态为【3任务执行完成】失败!"); |
| | | LogHelper.Info($"{taskName}:AGV取货:修改明细单状态为【3任务执行完成】失败!"); |
| | | return; |
| | | } |
| | | |
| | | var finishedCount = db.Queryable<TN_Outbound_Detail>().Count(d => d.S_OO_NO == detail.S_OO_NO && d.N_B_STATE == 3); |
| | | var allCount = db.Queryable<TN_Outbound_Detail>().Count(d => d.S_OO_NO == detail.S_OO_NO); |
| | | |
| | | LogHelper.Info($"{taskName}:AGV取货:统计任务已完成:{finishedCount}/{allCount}"); |
| | | LogHelper.Info($"{taskName}:AGV取货:统计任务已完成:{finishedCount}/{allCount}"); |
| | | |
| | | if (finishedCount == allCount) { // 当前出库单下的所有明细单,任务都已经完成 |
| | | if (finishedCount == allCount) { // 当前出库单下的所有明细单,任务都已经完成 |
| | | |
| | | if (db.Updateable<TN_Outbound_Order>().SetColumns(it => it.N_B_STATE == 3) |
| | | .Where(it => it.S_NO == detail.S_OO_NO) |
| | | .ExecuteCommand() <= 0) { |
| | | |
| | | tran.RollbackTran(); |
| | | LogHelper.Info($"{taskName}:AGV取货:所有任务完成时:修改单据状态为3任务执行完成--失败!"); |
| | | LogHelper.Info($"{taskName}:AGV取货:所有任务完成时:修改单据状态为3任务执行完成--失败!"); |
| | | return; |
| | | } |
| | | } |
| | |
| | | .First(); |
| | | |
| | | if (plan == null) { |
| | | info = $"计划单号{task.S_BS_NO}不存在!"; |
| | | info = $"计划单号{task.S_BS_NO}不存在!"; |
| | | LogHelper.Info(info); |
| | | } |
| | | |
| | |
| | | .First(); |
| | | |
| | | if (cgDetail == null) { |
| | | info = $"物料编码不存在!"; |
| | | info = $"物料编码不存在!"; |
| | | LogHelper.Info(info); |
| | | } |
| | | |
| | | var model = new OtherModel.PickUpReturnErpInfo { |
| | | jhdh = plan.JHDH, // 计划单号(唯一标识) |
| | | ckzt = plan.CKZT, // 出库状态(需要返回) |
| | | jhdh = plan.JHDH, // 计划单号 (唯一标识) |
| | | ckzt = plan.CKZT, // 出库状态 (需要返回) |
| | | jhlb = plan.JHLB, // 计划类别 |
| | | ckdh = plan.CKDH, // 参考单号 |
| | | cph = plan.CPH, // 车牌号 |
| | |
| | | cplb = plan.CPLB, // 产品类别 |
| | | cplbmx = plan.CPLBMX, // 产品类别明细 |
| | | pp = plan.PP, // 品牌 |
| | | dj = plan.DJ, // 等级(需要返回) |
| | | dj = plan.DJ, // 等级 (需要返回) |
| | | gh = plan.GH, // 罐号 |
| | | ph = plan.PH, // 批号(需要返回) |
| | | ph = plan.PH, // 批号 (需要返回) |
| | | bzlx = plan.BZLX, // 包装类型 |
| | | pzdh = plan.PZDH, // 派装单号 |
| | | pzd_dw = plan.PZD_DW, // 派装单单位 |
| | |
| | | pz_zfrq = plan.PZ_ZFRQ, // 派装作废日期 |
| | | pz_bz = plan.PZ_BZ, // 派装备注 |
| | | ckdbh = plan.CKDBH, // 出库单编号 |
| | | sfjs = plan.SFJS, // 实发件数(需要返回)--更新 |
| | | sfsl = plan.SFSL, // 实发数量(需要返回)--更新 |
| | | //sfcs = plan.SFCS , // 实发车数(需要返回) |
| | | //zcsj = plan.ZCSJ , // 装车时间(需要返回) |
| | | //jldw = plan.JLDW , // 计量单位(需要返回) |
| | | //fhrq = plan.FHRQ , // 发货日期(需要返回) |
| | | //ckdm = plan.CKDM , // 仓库代码(需要返回) |
| | | //fhr = plan.FHR , // 发货人(需要返回) |
| | | //czydm = plan.CZYDM , // 操作员(需要返回) |
| | | sfjs = plan.SFJS, // 实发件数 (需要返回) --更新 |
| | | sfsl = plan.SFSL, // 实发数量 (需要返回) --更新 |
| | | //sfcs = plan.SFCS , // 实发车数 (需要返回) |
| | | //zcsj = plan.ZCSJ , // 装车时间 (需要返回) |
| | | //jldw = plan.JLDW , // 计量单位 (需要返回) |
| | | //fhrq = plan.FHRQ , // 发货日期 (需要返回) |
| | | //ckdm = plan.CKDM , // 仓库代码 (需要返回) |
| | | //fhr = plan.FHR , // 发货人 (需要返回) |
| | | //czydm = plan.CZYDM , // 操作员 (需要返回) |
| | | shr_username = plan.SHR_USERNAME, // 审核人 |
| | | shrq = plan.SHRQ, // 审核日期 |
| | | zfbj = plan.ZFBJ, // 作废标记 |
| | |
| | | shdw = plan.SHDW, // 收货单位 |
| | | ysdw = plan.YSDW, // 运输单位 |
| | | lxr = plan.LXR, // 联系人 |
| | | //ry_zxg = plan.RY_ZXG , // 装卸工(需要返回) |
| | | //ry_ccsj = plan.RY_CCSJ , // 叉车司机(需要返回) |
| | | //ry_zxg = plan.RY_ZXG , // 装卸工 (需要返回) |
| | | //ry_ccsj = plan.RY_CCSJ , // 叉车司机 (需要返回) |
| | | erphx_jhdh = plan.ERPHX_JHDH, // erp交货单号 |
| | | erphx_wlbm = plan.ERPHX_WLBM, // erp物料编码 |
| | | erphx_wlmc = plan.ERPHX_WLMC, // erp物料名称 |
| | | erphx_cjrq = plan.ERPHX_CJRQ, // erp创建日期 |
| | | hw = plan.HW, // 货位(需要返回) |
| | | hwzt = plan.HWZT // 货位状态(需要返回) |
| | | hw = plan.HW, // 货位 (需要返回) |
| | | hwzt = plan.HWZT // 货位状态 (需要返回) |
| | | }; |
| | | model.sfjs = cgDetail.N_ITEM_NUM; |
| | | model.sfsl = (decimal) cgDetail.F_QTY; // TEMP |
| | |
| | | var jsonInfo = JsonConvert.SerializeObject(model); |
| | | var result = httpH.WebPost(Settings.ErpApiUrl + Settings.ErpRoute.PickUpReturn, jsonInfo); |
| | | |
| | | LogHelper.InfoApi($"取货完成反馈ERP接口,结果={result},调用参数:", model); |
| | | LogHelper.InfoApi($"取货完成反馈ERP接口,结果={result},调用参数:", model); |
| | | |
| | | plan.SFJS = model.sfjs; |
| | | plan.SFSL = model.sfsl; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 任务分发,根据调度类型发给不同的调度系统 |
| | | /// 任务分发,根据调度类型发给不同的调度系统 |
| | | /// </summary> |
| | | internal static void Dispatch() { |
| | | //查询任务 |
| | | //获取所有等待的任务 |
| | | var list = WCSHelper.GetWaitingTaskList(); |
| | | LogHelper.Info("等待任务信息" + JsonConvert.SerializeObject(list), "API"); |
| | | if (list.Count > 0) { |
| | | LogHelper.Info($"轮询:任务分发:等待任务信息\n\n{JsonConvert.SerializeObject(list)}\n"); |
| | | list.ForEach(task => { |
| | | //使用自定义任务推送 |
| | | //TaskProcess.SendTask(task);//调度NDC或杭奥或国自设备 |
| | |
| | | }); |
| | | } |
| | | else { |
| | | LogHelper.Info("暂无任务"); |
| | | LogHelper.Debug("轮询:任务分发:暂无任务"); |
| | | } |
| | | } |
| | | |
| | |
| | | var ListenPort = Settings.TcpServerPort; |
| | | TcpListener listener = new TcpListener(IPAddress.Any, ListenPort); |
| | | listener.Start(); |
| | | Console.WriteLine($"后台服务已启动,监听端口 {ListenPort}..."); |
| | | Console.WriteLine($"后台服务已启动,监听端口 {ListenPort}..."); |
| | | |
| | | while (true) { |
| | | try { |
| | |
| | | System.Net.Sockets.TcpClient client = listener.AcceptTcpClient(); |
| | | Console.WriteLine($"产线客户端已连接: {client.Client.RemoteEndPoint}"); |
| | | |
| | | // 处理客户端请求(使用Task避免阻塞主线程) |
| | | // 处理客户端请求 (使用Task避免阻塞主线程) |
| | | Task.Run(() => HandleClientRequest(client)); |
| | | } |
| | | catch (Exception ex) { |
| | |
| | | |
| | | // 解析消息 |
| | | var message = JsonConvert.DeserializeObject<ProductCompletedMessage>(jsonMessage); |
| | | //Console.WriteLine($"收到产品完成通知 - 物料:{message.ItemCode};批次号:{message.BatchNo};容器号:{message.CntrCode}"); |
| | | LogHelper.Info($"收到产品下线通知:"+message); |
| | | //Console.WriteLine($"收到产品完成通知 - 物料:{message.ItemCode};批次号:{message.BatchNo};容器号:{message.CntrCode}"); |
| | | LogHelper.Info($"收到产品下线通知:"+message); |
| | | |
| | | string startLocCode = ""; |
| | | |
| | | // A. 如果是单个产线PLC,通过TCP传播,需要传递产线ID,根据ID计算起点货位 |
| | | //startLocCode = Settings.ProductionLines[message.Id].OffLoc[0]; // 理论上应该只有1个OffLoc,否则应该注明是哪一个 |
| | | // A. 如果是单个产线PLC,通过TCP传播,需要传递产线ID,根据ID计算起点货位 |
| | | //startLocCode = Settings.ProductionLines[message.Id].OffLoc[0]; // 理论上应该只有1个OffLoc,否则应该注明是哪一个 |
| | | |
| | | // B. 如果是每条产线各一个客户端,更简单,直接根据IP地址确定终点货位 |
| | | // B. 如果是每条产线各一个客户端,更简单,直接根据IP地址确定终点货位 |
| | | // TODO 具体逻辑待后续确定时补完 |
| | | |
| | | var success = CreateInboundTask(startLocCode, message.CntrCode).Value; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 入库作业创建只接收起点货位和容器号(物料信息待定、通过产线号计算起点的逻辑放在方法外) |
| | | /// 入库作业创建只接收起点货位和容器号 (物料信息待定,通过产线号计算起点的逻辑放在方法外) |
| | | /// </summary> |
| | | /// <param name="startLocCode"></param> |
| | | /// <param name="cntrCode"></param> |
| | |
| | | .First(); |
| | | |
| | | if (startLoc == null) { |
| | | info = $"没有找到起点货位'{startLocCode}',或不满足要求:未上锁、当前容器数量=0"; |
| | | info = $"没有找到起点货位'{startLocCode}',或不满足要求:未上锁,当前容器数量=0"; |
| | | LogHelper.Info(info); |
| | | return new Result<bool>(false, info); |
| | | } |
| | |
| | | |
| | | var endLoc = db.Queryable<TN_Location>() |
| | | .Where(a => endAreas.Contains(a.S_AREA_CODE)) |
| | | .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 |
| | | .Where(a => a.N_CURRENT_NUM == 0) // 筛选:空货位 |
| | | .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") // 筛选:未上锁 |
| | | .Where(a => a.N_CURRENT_NUM == 0) // 筛选:空货位 |
| | | .OrderBy(l => l.N_LAYER) |
| | | .First(); |
| | | |
| | | if (endLoc == null) { |
| | | info = $"没有找到合适的【终点货位】,需要满足要求:未上锁、当前容器数量=0"; |
| | | info = $"没有找到合适的【终点货位】,需要满足要求:未上锁,当前容器数量=0"; |
| | | LogHelper.Info(info); |
| | | return new Result<bool>(false, info); |
| | | } |
| | |
| | | if (db.Deleteable(locCntrRelOld).ExecuteCommand() <= 0 && |
| | | db.Updateable<TN_Location>().SetColumns(l => l.N_CURRENT_NUM == 0).Where(l => l.S_CODE == locCntrRelOld.S_LOC_CODE).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | info = $"删除旧货位容器关系表失败:货位编码{locCntrRelOld.S_LOC_CODE},容器编码{locCntrRelOld.S_CNTR_CODE}"; |
| | | info = $"删除旧货位容器关系表失败:货位编码{locCntrRelOld.S_LOC_CODE},容器编码{locCntrRelOld.S_CNTR_CODE}"; |
| | | LogHelper.Info(info); |
| | | return new Result<bool>(false, info); |
| | | } |
| | |
| | | |
| | | if (db.Insertable(locCntrRel).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | info = $"插入货位容器关系表失败:货位编码{locCntrRel.S_LOC_CODE},容器编码{locCntrRel.S_CNTR_CODE}"; |
| | | info = $"插入货位容器关系表失败:货位编码{locCntrRel.S_LOC_CODE},容器编码{locCntrRel.S_CNTR_CODE}"; |
| | | LogHelper.Info(info); |
| | | return new Result<bool>(false, info); |
| | | } |
| | |
| | | it.S_LOCK_STATE, |
| | | it.S_LOCK_OP, |
| | | it.T_MODIFY, |
| | | it.N_CURRENT_NUM, // 起点货位绑定后,将货位状态更新 |
| | | it.N_CURRENT_NUM, // 起点货位绑定后,将货位状态更新 |
| | | }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | info = $"生成任务'{taskName}'失败:更新起点货位{startLoc.S_CODE}锁状态失败"; |
| | | info = $"生成任务'{taskName}'失败:更新起点货位{startLoc.S_CODE}锁状态失败"; |
| | | LogHelper.Info(info); |
| | | return new Result<bool>(false, info); |
| | | } |
| | |
| | | it.T_MODIFY, |
| | | }).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | info = $"生成任务'{taskName}'失败:更新终点货位{endLoc.S_CODE}锁状态失败"; |
| | | info = $"生成任务'{taskName}'失败:更新终点货位{endLoc.S_CODE}锁状态失败"; |
| | | LogHelper.Info(info); |
| | | return new Result<bool>(false, info); |
| | | } |
| | | |
| | | if (db.Insertable(task).ExecuteCommand() <= 0) { |
| | | tran.RollbackTran(); |
| | | info = $"生成任务'{taskName}'失败,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}"; |
| | | info = $"生成任务'{taskName}'失败,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}"; |
| | | LogHelper.Info(info); |
| | | return new Result<bool>(false, info); |
| | | } |
| | | |
| | | tran.CommitTran(); |
| | | info = $"生成任务'{taskName}'成功,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}"; |
| | | info = $"生成任务'{taskName}'成功,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}"; |
| | | LogHelper.Info(info); |
| | | return new Result<bool>(true, info); |
| | | } |
| | |
| | | |
| | | // 常用的Modbus功能码方法 |
| | | /// <summary> |
| | | /// 读一个或多个线圈,返回一个bit真假数组 |
| | | /// 读一个或多个线圈,返回一个bit真假数组 |
| | | /// </summary> |
| | | /// <param name="startingAddress"></param> |
| | | /// <param name="quantity"></param> |
| | | /// <returns></returns> |
| | | bool[] ReadCoils(int startingAddress, int quantity); |
| | | /// <summary> |
| | | /// 读一个或多个离散输入,返回一个bit真假数组 |
| | | /// 读一个或多个离散输入,返回一个bit真假数组 |
| | | /// </summary> |
| | | /// <param name="startingAddress"></param> |
| | | /// <param name="quantity"></param> |
| | | /// <returns></returns> |
| | | bool[] ReadDiscreteInputs(int startingAddress, int quantity); |
| | | /// <summary> |
| | | /// 批量读取或单独读取保持寄存器,返回的是32位int数组 |
| | | /// 批量读取或单独读取保持寄存器,返回的是32位int数组 |
| | | /// </summary> |
| | | /// <param name="startingAddress"></param> |
| | | /// <param name="quantity"></param> |
| | | /// <returns></returns> |
| | | int[] ReadHoldingRegisters(int startingAddress, int quantity); |
| | | /// <summary> |
| | | /// 读一个或多个输入寄存器,返回一个int32位数组 |
| | | /// 读一个或多个输入寄存器,返回一个int32位数组 |
| | | /// </summary> |
| | | /// <param name="startingAddress"></param> |
| | | /// <param name="quantity"></param> |
| | |
| | | case ModbusCommunicationType.TcpSocket: |
| | | return new TcpSocketCommunicator(); |
| | | default: |
| | | //throw new ArgumentException("不支持的Modbus通信方式:请选择EasyModbus或TcpSocket"); |
| | | LogHelper.Info("不支持的Modbus通信方式:请选择EasyModbus或TcpSocket"); |
| | | //throw new ArgumentException("不支持的Modbus通信方式:请选择EasyModbus或TcpSocket"); |
| | | LogHelper.Info("不支持的Modbus通信方式:请选择EasyModbus或TcpSocket"); |
| | | return null; |
| | | } |
| | | } |
| | |
| | | _modbusClient.Connect(); |
| | | |
| | | if (IsConnected) { |
| | | LogHelper.Info($"连接成功:{ipAddress}:{port}"); |
| | | LogHelper.Info($"连接成功:{ipAddress}:{port}"); |
| | | } |
| | | else { |
| | | LogHelper.Info($"连接失败:{ipAddress}:{port}"); |
| | | LogHelper.Info($"连接失败:{ipAddress}:{port}"); |
| | | } |
| | | } |
| | | |
| | |
| | | _modbusClient?.Disconnect(); |
| | | |
| | | if (IsConnected) { |
| | | LogHelper.Info($"连接成功:{_modbusClient.IPAddress}:{_modbusClient.Port}"); |
| | | LogHelper.Info($"连接成功:{_modbusClient.IPAddress}:{_modbusClient.Port}"); |
| | | } |
| | | else { |
| | | LogHelper.Info($"连接失败:{_modbusClient.IPAddress} : {_modbusClient.Port}"); |
| | | LogHelper.Info($"连接失败:{_modbusClient.IPAddress} : {_modbusClient.Port}"); |
| | | } |
| | | } |
| | | |
| | |
| | | res = _modbusClient.ReadCoils(startingAddress, quantity); |
| | | if (res.Length != 0) { |
| | | //读取成功 |
| | | LogHelper.Info($"读取成功:ReadCoils:IP:{ip},Port:{port}"); |
| | | LogHelper.Info($"读取成功:ReadCoils:IP:{ip},Port:{port}"); |
| | | } |
| | | else { |
| | | //读取失败 |
| | | LogHelper.Info($"读取失败:ReadCoils:IP:{ip},Port:{port}"); |
| | | LogHelper.Info($"读取失败:ReadCoils:IP:{ip},Port:{port}"); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | |
| | | } |
| | | } |
| | | else { |
| | | LogHelper.Info($"未找到Modbus设备实例对象,或对象未成功连接"); |
| | | LogHelper.Info($"未找到Modbus设备实例对象,或对象未成功连接"); |
| | | } |
| | | return res; |
| | | } |
| | |
| | | res = _modbusClient.ReadDiscreteInputs(startingAddress, quantity); |
| | | if (res.Length != 0) { |
| | | //读取成功 |
| | | LogHelper.Info($"读取成功:ReadDiscreteInputs:IP:{ip},Port:{port}"); |
| | | LogHelper.Info($"读取成功:ReadDiscreteInputs:IP:{ip},Port:{port}"); |
| | | } |
| | | else { |
| | | //读取失败 |
| | | LogHelper.Info($"读取失败:ReadDiscreteInputs:IP:{ip},Port:{port}"); |
| | | LogHelper.Info($"读取失败:ReadDiscreteInputs:IP:{ip},Port:{port}"); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | |
| | | } |
| | | } |
| | | else { |
| | | LogHelper.Info($"未找到Modbus设备实例对象,或对象未成功连接"); |
| | | LogHelper.Info($"未找到Modbus设备实例对象,或对象未成功连接"); |
| | | } |
| | | return res; |
| | | } |
| | |
| | | var ip = client.IPAddress; |
| | | var port = client.Port; |
| | | try { |
| | | //一个寄存器是16位,返回2个int类型 |
| | | //一个寄存器是16位,返回2个int类型 |
| | | res = client.ReadHoldingRegisters(startingAddress, quantity); |
| | | if (res.Length != 0) { |
| | | //读取成功 |
| | | LogHelper.Info($"读取成功:ReadHoldingRegisters:IP:{ip},Port:{port}"); |
| | | LogHelper.Info($"读取成功:ReadHoldingRegisters:IP:{ip},Port:{port}"); |
| | | } |
| | | else { |
| | | //读取失败 |
| | | LogHelper.Info($"读取失败:ReadHoldingRegisters:IP:{ip},Port:{port}"); |
| | | LogHelper.Info($"读取失败:ReadHoldingRegisters:IP:{ip},Port:{port}"); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | //如果请求数量超出保持寄存器的最大数据行数,会报错 |
| | | //如果请求数量超出保持寄存器的最大数据行数,会报错 |
| | | LogHelper.InfoEx(ex); |
| | | } |
| | | } |
| | | else { |
| | | LogHelper.Info($"未找到Modbus设备实例对象,或对象未成功连接"); |
| | | LogHelper.Info($"未找到Modbus设备实例对象,或对象未成功连接"); |
| | | } |
| | | return res; |
| | | } |
| | |
| | | res = client.ReadInputRegisters(startingAddress, quantity); |
| | | if (res.Length != 0) { |
| | | //读取成功 |
| | | LogHelper.Info($"读取成功:ReadInputRegisters:IP:{ip},Port:{port}"); |
| | | LogHelper.Info($"读取成功:ReadInputRegisters:IP:{ip},Port:{port}"); |
| | | } |
| | | else { |
| | | //读取失败 |
| | | LogHelper.Info($"读取失败:ReadInputRegisters:IP:{ip},Port:{port}"); |
| | | LogHelper.Info($"读取失败:ReadInputRegisters:IP:{ip},Port:{port}"); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | |
| | | } |
| | | } |
| | | else { |
| | | LogHelper.Info($"未找到Modbus设备实例对象,或对象未成功连接"); |
| | | LogHelper.Info($"未找到Modbus设备实例对象,或对象未成功连接"); |
| | | } |
| | | return res; |
| | | } |
| | |
| | | res = value == client.ReadCoils(coilAddress, 1)[0]; |
| | | if (res) { |
| | | //写入成功 |
| | | LogHelper.Info($"写入成功:WriteSingleCoil:IP:{ip},Port:{port}"); |
| | | LogHelper.Info($"写入成功:WriteSingleCoil:IP:{ip},Port:{port}"); |
| | | } |
| | | else { |
| | | //写入失败 |
| | | LogHelper.Info($"写入失败:WriteSingleCoil:IP:{ip},Port:{port}"); |
| | | LogHelper.Info($"写入失败:WriteSingleCoil:IP:{ip},Port:{port}"); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | |
| | | } |
| | | } |
| | | else { |
| | | LogHelper.Info($"未找到Modbus设备实例对象,或对象未成功连接"); |
| | | LogHelper.Info($"未找到Modbus设备实例对象,或对象未成功连接"); |
| | | } |
| | | return res; |
| | | } |
| | |
| | | res = value == client.ReadHoldingRegisters(registerAddress, 1)[0]; |
| | | if (res) { |
| | | //写入成功 |
| | | LogHelper.Info($"写入成功:WriteSingleRegister:IP:{ip},Port:{port}"); |
| | | LogHelper.Info($"写入成功:WriteSingleRegister:IP:{ip},Port:{port}"); |
| | | } |
| | | else { |
| | | //写入失败 |
| | | LogHelper.Info($"写入失败:WriteSingleRegister:IP:{ip},Port:{port}"); |
| | | LogHelper.Info($"写入失败:WriteSingleRegister:IP:{ip},Port:{port}"); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | |
| | | } |
| | | } |
| | | else { |
| | | LogHelper.Info($"未找到Modbus设备实例对象,或对象未成功连接"); |
| | | LogHelper.Info($"未找到Modbus设备实例对象,或对象未成功连接"); |
| | | } |
| | | return res; |
| | | } |
| | |
| | | res = values.SequenceEqual(dataRead); |
| | | if (res) { |
| | | //写入成功 |
| | | LogHelper.Info($"写入成功:WriteMultipleCoils:IP:{ip},Port:{port}"); |
| | | LogHelper.Info($"写入成功:WriteMultipleCoils:IP:{ip},Port:{port}"); |
| | | } |
| | | else { |
| | | //写入失败 |
| | | LogHelper.Info($"写入失败:WriteMultipleCoils:IP:{ip},Port:{port}"); |
| | | LogHelper.Info($"写入失败:WriteMultipleCoils:IP:{ip},Port:{port}"); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | |
| | | } |
| | | } |
| | | else { |
| | | LogHelper.Info($"未找到Modbus设备实例对象,或对象未成功连接"); |
| | | LogHelper.Info($"未找到Modbus设备实例对象,或对象未成功连接"); |
| | | } |
| | | return res; |
| | | } |
| | |
| | | } |
| | | } |
| | | else { |
| | | LogHelper.Info($"未找到Modbus设备实例对象,或对象未成功连接"); |
| | | LogHelper.Info($"未找到Modbus设备实例对象,或对象未成功连接"); |
| | | } |
| | | return res; |
| | | } |
| | |
| | | if (quantity < 1 || quantity > 2000) |
| | | throw new ArgumentException("Quantity must be between 1 and 2000"); |
| | | |
| | | // 构建请求报文(12字节) |
| | | // 构建请求报文 (12字节) |
| | | byte[] request = new byte[12]; |
| | | request[0] = 0x00; // 事务ID高字节 |
| | | request[1] = 0x01; // 事务ID低字节(示例值) |
| | | request[2] = 0x00; // 协议ID高字节(固定0) |
| | | request[3] = 0x00; // 协议ID低字节(固定0) |
| | | request[4] = 0x00; // 长度高字节(后续6字节) |
| | | request[1] = 0x01; // 事务ID低字节 (示例值) |
| | | request[2] = 0x00; // 协议ID高字节 (固定0) |
| | | request[3] = 0x00; // 协议ID低字节 (固定0) |
| | | request[4] = 0x00; // 长度高字节 (后续6字节) |
| | | request[5] = 0x06; // 长度低字节 |
| | | request[6] = unitIdentifier; // 单元标识符 |
| | | request[7] = 0x01; // 功能码(读线圈) |
| | | request[7] = 0x01; // 功能码 (读线圈) |
| | | request[8] = (byte)(startingAddress >> 8); // 起始地址高字节 |
| | | request[9] = (byte)startingAddress; // 起始地址低字节 |
| | | request[10] = (byte)(quantity >> 8); // 数量高字节 |
| | |
| | | // 发送请求 |
| | | _networkStream.Write(request, 0, request.Length); |
| | | |
| | | // 读取响应头(8字节) |
| | | // 读取响应头 (8字节) |
| | | byte[] responseHeader = new byte[8]; |
| | | int bytesRead = _networkStream.Read(responseHeader, 0, 8); |
| | | if (bytesRead != 8) |
| | | throw new Exception("Invalid response header length"); |
| | | |
| | | // 校验事务ID、协议ID、单元标识符 |
| | | // 校验事务ID,协议ID,单元标识符 |
| | | if (responseHeader[0] != request[0] || responseHeader[1] != request[1] || |
| | | responseHeader[2] != 0x00 || responseHeader[3] != 0x00 || |
| | | responseHeader[6] != unitIdentifier) |
| | | throw new Exception("Invalid response header"); |
| | | |
| | | // 检查异常响应(功能码 + 0x80) |
| | | // 检查异常响应 (功能码 + 0x80) |
| | | if (responseHeader[7] == 0x81) { |
| | | int errorCode = _networkStream.ReadByte(); |
| | | throw new Exception($"Modbus error. Code: {errorCode}"); |
| | |
| | | else if (responseHeader[7] != 0x01) |
| | | throw new Exception("Invalid function code in response"); |
| | | |
| | | // 读取数据部分(字节数 + 实际数据) |
| | | // 读取数据部分 (字节数 + 实际数据) |
| | | byte byteCount = responseHeader[8]; |
| | | byte[] responseData = new byte[byteCount]; |
| | | bytesRead = _networkStream.Read(responseData, 0, byteCount); |
| | | if (bytesRead != byteCount) |
| | | throw new Exception("Invalid response data length"); |
| | | |
| | | // 解析线圈状态(每个位表示一个线圈) |
| | | // 解析线圈状态 (每个位表示一个线圈) |
| | | bool[] coils = new bool[quantity]; |
| | | for (int i = 0; i < quantity; i++) { |
| | | int byteIndex = i / 8; |
| | |
| | | } |
| | | |
| | | public bool[] ReadDiscreteInputs(int startingAddress, int quantity) { |
| | | // 报文结构与ReadCoils几乎相同,仅功能码改为0x02 |
| | | // 报文结构与ReadCoils几乎相同,仅功能码改为0x02 |
| | | byte[] request = new byte[12]; |
| | | request[0] = 0x00; // 事务ID高字节 |
| | | request[1] = 0x01; // 事务ID低字节(示例值) |
| | | request[2] = 0x00; // 协议ID高字节(固定0) |
| | | request[3] = 0x00; // 协议ID低字节(固定0) |
| | | request[4] = 0x00; // 长度高字节(后续6字节) |
| | | request[1] = 0x01; // 事务ID低字节 (示例值) |
| | | request[2] = 0x00; // 协议ID高字节 (固定0) |
| | | request[3] = 0x00; // 协议ID低字节 (固定0) |
| | | request[4] = 0x00; // 长度高字节 (后续6字节) |
| | | request[5] = 0x06; // 长度低字节 |
| | | request[6] = unitIdentifier; |
| | | request[7] = 0x02; // 功能码:读离散输入 |
| | | request[7] = 0x02; // 功能码:读离散输入 |
| | | request[8] = (byte)(startingAddress >> 8); // 起始地址高字节 |
| | | request[9] = (byte)startingAddress; // 起始地址低字节 |
| | | request[10] = (byte)(quantity >> 8); // 数量高字节 |
| | |
| | | byte[] responseHeader = new byte[8]; |
| | | _networkStream.Read(responseHeader, 0, 8); |
| | | |
| | | // 校验和异常处理(参考ReadCoils) |
| | | // 校验和异常处理 (参考ReadCoils) |
| | | if (responseHeader[7] == 0x82) // 异常响应 |
| | | { |
| | | int errorCode = _networkStream.ReadByte(); |
| | |
| | | if (quantity < 1 || quantity > 125) |
| | | throw new ArgumentException("Quantity must be between 1 and 125"); |
| | | |
| | | // 构建请求报文(12字节) |
| | | // 构建请求报文 (12字节) |
| | | byte[] request = new byte[12]; |
| | | request[0] = 0x00; // 事务ID高字节(示例值) |
| | | request[0] = 0x00; // 事务ID高字节 (示例值) |
| | | request[1] = 0x01; // 事务ID低字节 |
| | | request[2] = 0x00; // 协议ID高字节(固定0) |
| | | request[3] = 0x00; // 协议ID低字节(固定0) |
| | | request[4] = 0x00; // 长度高字节(后续6字节) |
| | | request[2] = 0x00; // 协议ID高字节 (固定0) |
| | | request[3] = 0x00; // 协议ID低字节 (固定0) |
| | | request[4] = 0x00; // 长度高字节 (后续6字节) |
| | | request[5] = 0x06; // 长度低字节 |
| | | request[6] = unitIdentifier; // 单元标识符 |
| | | request[7] = 0x03; // 功能码(读保持寄存器) |
| | | request[7] = 0x03; // 功能码 (读保持寄存器) |
| | | request[8] = (byte)(startingAddress >> 8); // 起始地址高字节 |
| | | request[9] = (byte)startingAddress; // 起始地址低字节 |
| | | request[10] = (byte)(quantity >> 8); // 数量高字节 |
| | |
| | | // 发送请求 |
| | | _networkStream.Write(request, 0, request.Length); |
| | | |
| | | // 读取响应头(8字节) |
| | | // 读取响应头 (8字节) |
| | | byte[] responseHeader = new byte[8]; |
| | | int bytesRead = _networkStream.Read(responseHeader, 0, 8); |
| | | if (bytesRead != 8) |
| | | throw new Exception("Invalid response header length"); |
| | | |
| | | // 校验事务ID、协议ID、单元标识符 |
| | | // 校验事务ID,协议ID,单元标识符 |
| | | if (responseHeader[0] != request[0] || responseHeader[1] != request[1] || |
| | | responseHeader[2] != 0x00 || responseHeader[3] != 0x00 || |
| | | responseHeader[6] != unitIdentifier) |
| | | throw new Exception("Invalid response header"); |
| | | |
| | | // 检查异常响应(功能码 + 0x80) |
| | | // 检查异常响应 (功能码 + 0x80) |
| | | if (responseHeader[7] == 0x83) { |
| | | int errorCode = _networkStream.ReadByte(); |
| | | throw new Exception($"Modbus error. Code: {errorCode}"); |
| | |
| | | else if (responseHeader[7] != 0x03) |
| | | throw new Exception("Invalid function code in response"); |
| | | |
| | | // 读取数据部分(字节数 + 实际数据) |
| | | // 读取数据部分 (字节数 + 实际数据) |
| | | byte byteCount = responseHeader[8]; |
| | | byte[] responseData = new byte[byteCount]; |
| | | bytesRead = _networkStream.Read(responseData, 0, byteCount); |
| | | if (bytesRead != byteCount) |
| | | throw new Exception("Invalid response data length"); |
| | | |
| | | // 解析寄存器值(大端序) |
| | | // 解析寄存器值 (大端序) |
| | | int[] registers = new int[quantity]; |
| | | for (int i = 0; i < quantity; i++) { |
| | | int offset = i * 2; |
| | |
| | | // 构建Modbus TCP请求报文 |
| | | byte[] request = new byte[12]; |
| | | |
| | | // 事务标识符(可以简单递增) |
| | | // 事务标识符 (可以简单递增) |
| | | request[0] = 0x00; |
| | | request[1] = 0x01; |
| | | |
| | | // 协议标识符(Modbus固定为0) |
| | | // 协议标识符 (Modbus固定为0) |
| | | request[2] = 0x00; |
| | | request[3] = 0x00; |
| | | |
| | | // 长度字段(后面还有6字节) |
| | | // 长度字段 (后面还有6字节) |
| | | request[4] = 0x00; |
| | | request[5] = 0x06; |
| | | |
| | | // 单元标识符 |
| | | request[6] = unitIdentifier; |
| | | |
| | | // 功能码(4表示读输入寄存器) |
| | | // 功能码 (4表示读输入寄存器) |
| | | request[7] = 0x04; |
| | | |
| | | // 起始地址 |
| | |
| | | |
| | | _networkStream.Write(request, 0, request.Length); |
| | | |
| | | // 响应应与请求完全一致(回显) |
| | | // 响应应与请求完全一致 (回显) |
| | | byte[] response = new byte[12]; |
| | | int bytesRead = _networkStream.Read(response, 0, 12); |
| | | if (bytesRead != 12) |
| | |
| | | |
| | | _networkStream.Write(request, 0, request.Length); |
| | | |
| | | // 检查回显响应(同WriteSingleCoil) |
| | | // 检查回显响应 (同WriteSingleCoil) |
| | | byte[] response = new byte[12]; |
| | | _networkStream.Read(response, 0, 12); |
| | | if (!response.SequenceEqual(request)) |
| | |
| | | if (quantity < 1 || quantity > 1968) |
| | | throw new ArgumentException("Quantity must be between 1 and 1968"); |
| | | |
| | | // 计算需要的字节数(每个字节存储8个线圈状态) |
| | | // 计算需要的字节数 (每个字节存储8个线圈状态) |
| | | int byteCount = (quantity + 7) / 8; |
| | | byte[] coilBytes = new byte[byteCount]; |
| | | |
| | |
| | | } |
| | | } |
| | | |
| | | // 构建请求报文(13 + 线圈字节数) |
| | | // 构建请求报文 (13 + 线圈字节数) |
| | | byte[] request = new byte[13 + coilBytes.Length]; |
| | | request[0] = 0x00; // 事务ID高字节 |
| | | request[1] = 0x01; // 事务ID低字节 |
| | |
| | | request[4] = (byte)((7 + coilBytes.Length) >> 8); // 长度高字节 |
| | | request[5] = (byte)(7 + coilBytes.Length); // 长度低字节 |
| | | request[6] = unitIdentifier; |
| | | request[7] = 0x0F; // 功能码(写多个线圈) |
| | | request[7] = 0x0F; // 功能码 (写多个线圈) |
| | | request[8] = (byte)(startingAddress >> 8); // 起始地址高字节 |
| | | request[9] = (byte)startingAddress; // 起始地址低字节 |
| | | request[10] = (byte)(quantity >> 8); // 数量高字节 |
| | |
| | | // 发送请求 |
| | | _networkStream.Write(request, 0, request.Length); |
| | | |
| | | // 读取响应(固定12字节) |
| | | // 读取响应 (固定12字节) |
| | | byte[] response = new byte[12]; |
| | | int bytesRead = _networkStream.Read(response, 0, 12); |
| | | if (bytesRead != 12) |
| | |
| | | if (quantity < 1 || quantity > 123) |
| | | throw new ArgumentException("Quantity must be between 1 and 123"); |
| | | |
| | | // 将ushort数组转换为字节数组(大端序) |
| | | // 将ushort数组转换为字节数组 (大端序) |
| | | byte[] valueBytes = new byte[quantity * 2]; |
| | | for (int i = 0; i < quantity; i++) { |
| | | valueBytes[i * 2] = (byte)(values[i] >> 8); |
| | | valueBytes[i * 2 + 1] = (byte)values[i]; |
| | | } |
| | | |
| | | // 构建请求报文(13 + 值字节数) |
| | | // 构建请求报文 (13 + 值字节数) |
| | | byte[] request = new byte[13 + valueBytes.Length]; |
| | | request[0] = 0x00; // 事务ID高字节 |
| | | request[1] = 0x01; // 事务ID低字节 |
| | |
| | | request[4] = (byte)((7 + valueBytes.Length) >> 8); // 长度高字节 |
| | | request[5] = (byte)(7 + valueBytes.Length); // 长度低字节 |
| | | request[6] = unitIdentifier; |
| | | request[7] = 0x10; // 功能码(写多个寄存器) |
| | | request[7] = 0x10; // 功能码 (写多个寄存器) |
| | | request[8] = (byte)(startingAddress >> 8); // 起始地址高字节 |
| | | request[9] = (byte)startingAddress; // 起始地址低字节 |
| | | request[10] = (byte)(quantity >> 8); // 数量高字节 |
| | |
| | | // 发送请求 |
| | | _networkStream.Write(request, 0, request.Length); |
| | | |
| | | // 读取响应(固定12字节) |
| | | // 读取响应 (固定12字节) |
| | | byte[] response = new byte[12]; |
| | | int bytesRead = _networkStream.Read(response, 0, 12); |
| | | if (bytesRead != 12) |
| | |
| | | /// modbus tcp 用第三方的包 |
| | | /// </summary> |
| | | public class ModbusHelper { |
| | | // 内存,连接上的 Modbus 通讯对象 |
| | | // 内存,连接上的 Modbus 通讯对象 |
| | | private static Dictionary<string, ModbusClient> _ipPort_ModbusClient = new Dictionary<string, ModbusClient>(); |
| | | |
| | | public ModbusHelper(string ip, int port = 502, byte slaveId = 1) { |
| | |
| | | try { |
| | | if (ip == null || ip.Trim() == "") { |
| | | // 读取配置信息失败 |
| | | LogHelper.Info("Modbus:读取配置信息失败"); |
| | | LogHelper.Info("Modbus:读取配置信息失败"); |
| | | return; |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 连接 Modbus 下位机(私有,内部调用) |
| | | /// 连接 Modbus 下位机 (私有,内部调用) |
| | | /// </summary> |
| | | /// <param name="modbusClient"></param> |
| | | private static void Link(ModbusClient modbusClient) { |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 读一个或多个线圈,返回一个bit真假数组 |
| | | /// 读一个或多个线圈,返回一个bit真假数组 |
| | | /// </summary> |
| | | /// <param name="address"></param> |
| | | /// <param name="qty"></param> |
| | |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | |
| | | LogHelper.InfoEx(ex); |
| | | } |
| | | } |
| | | else { |
| | |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | |
| | | LogHelper.InfoEx(ex); |
| | | } |
| | | } |
| | | else { |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 批量读取或单独读取保持寄存器,返回的是32位int数组 |
| | | /// 批量读取或单独读取保持寄存器,返回的是32位int数组 |
| | | /// </summary> |
| | | /// <param name="address">读取起始位</param> |
| | | /// <param name="qty">读取的数量</param> |
| | |
| | | var client = GetModbusClient(ip, port); |
| | | if (client != null && client.Connected) { |
| | | try { |
| | | //一个寄存器是16位,返回2个int类型 |
| | | //一个寄存器是16位,返回2个int类型 |
| | | res = client.ReadHoldingRegisters(address, qty); |
| | | if (res.Length != 0) { |
| | | //读取成功 |
| | |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | //如果请求数量超出保持寄存器的最大数据行数,会报错 |
| | | //如果请求数量超出保持寄存器的最大数据行数,会报错 |
| | | LogHelper.Info($"发生了异常:{ex.Message},IP:{ip},Port:{port}", "Error"); |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | |
| | | LogHelper.InfoEx(ex); |
| | | } |
| | | } |
| | | else { |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 读一个或多个离散输入,返回一个bit真假数组 |
| | | /// 读一个或多个离散输入,返回一个bit真假数组 |
| | | /// </summary> |
| | | /// <param name="address"></param> |
| | | /// <param name="qty"></param> |
| | |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | |
| | | LogHelper.InfoEx(ex); |
| | | } |
| | | } |
| | | else { |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 读一个或多个输入寄存器,返回一个int32位数组 |
| | | /// 读一个或多个输入寄存器,返回一个int32位数组 |
| | | /// </summary> |
| | | /// <param name="address"></param> |
| | | /// <param name="qty"></param> |
| | |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | |
| | | LogHelper.InfoEx(ex); |
| | | } |
| | | } |
| | | else { |
| | |
| | | } |
| | | |
| | | #region Modbus 协议读写字符串 |
| | | // 将字符串转换为 Modbus 寄存器数组(int[] 形式,每个int存一个16位值) |
| | | // 将字符串转换为 Modbus 寄存器数组 (int[] 形式,每个int存一个16位值) |
| | | private static int[] StringToRegisters(string text) { |
| | | // 填充为偶数长度 |
| | | if (text.Length % 2 != 0) { |
| | |
| | | int[] registers = new int[bytes.Length / 2]; |
| | | |
| | | for (int i = 0; i < registers.Length; i++) { |
| | | // 大端序:高位字节在前 |
| | | // 大端序:高位字节在前 |
| | | registers[i] = (bytes[i * 2] << 8) | bytes[i * 2 + 1]; |
| | | } |
| | | |
| | |
| | | byte[] bytes = new byte[registers.Length * 2]; |
| | | |
| | | for (int i = 0; i < registers.Length; i++) { |
| | | // 提取低16位(忽略高16位) |
| | | // 提取低16位 (忽略高16位) |
| | | ushort registerValue = (ushort)(registers[i] & 0xFFFF); |
| | | |
| | | // 解析大端序 |
| | |
| | | #endregion |
| | | |
| | | /// <summary> |
| | | /// 获取 Modbus 通讯对象(私有,内部调用) |
| | | /// 获取 Modbus 通讯对象 (私有,内部调用) |
| | | /// </summary> |
| | | /// <param name="ip"></param> |
| | | /// <param name="port"></param> |
| | |
| | | { |
| | | try |
| | | { |
| | | // 创建一个应用配置对象,用于设置应用名称、唯一标识、类型、证书和安全策略 |
| | | // 创建一个应用配置对象,用于设置应用名称,唯一标识,类型,证书和安全策略 |
| | | var config = new ApplicationConfiguration() |
| | | { |
| | | ApplicationName = "MyClient", |
| | |
| | | // 验证应用配置对象 |
| | | await config.Validate(ApplicationType.Client); |
| | | |
| | | // 设置证书验证事件,用于自动接受不受信任的证书 |
| | | // 设置证书验证事件,用于自动接受不受信任的证书 |
| | | if (config.SecurityConfiguration.AutoAcceptUntrustedCertificates) |
| | | { |
| | | config.CertificateValidator.CertificateValidation += (s, e) => { e.Accept = (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted); }; |
| | | } |
| | | |
| | | // 创建一个应用实例对象,用于检查证书 |
| | | // 创建一个应用实例对象,用于检查证书 |
| | | var application = new ApplicationInstance(config); |
| | | |
| | | // 检查应用实例对象的证书 |
| | | bool check = await application.CheckApplicationInstanceCertificate(false, 2048); |
| | | // 创建一个会话对象,用于连接到 OPC UA 服务器 |
| | | // 创建一个会话对象,用于连接到 OPC UA 服务器 |
| | | EndpointDescription endpointDescription = CoreClientUtils.SelectEndpoint("opc.tcp://172.16.57.41:4840", true); |
| | | EndpointConfiguration endpointConfiguration = EndpointConfiguration.Create(config); |
| | | ConfiguredEndpoint endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration); |
| | |
| | | public string Id { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 系统状态:0本地 1联动(AGV模式) 2故障 |
| | | /// 系统状态:0本地 1联动(AGV模式) 2故障 |
| | | /// </summary> |
| | | public int SystemState { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 满垛下线:1输送线末端有成品料,需要AGV搬运 0默认值 |
| | | /// 满垛下线:1输送线末端有成品料,需要AGV搬运 0默认值 |
| | | /// </summary> |
| | | public int FullOffline { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 呼叫托盘垛:1需要空托,呼叫AGV配送 0默认值 |
| | | /// 呼叫托盘垛:1需要空托,呼叫AGV配送 0默认值 |
| | | /// </summary> |
| | | public int CallPallet { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 允许 AGV 放托盘垛:1允许放垛 0默认值 |
| | | /// 允许 AGV 放托盘垛:1允许放垛 0默认值 |
| | | /// </summary> |
| | | public int AllowAgvPlacePallet { get; set; } |
| | | |
| | | /// <summary> |
| | | /// AGV 正在取货:下线AGV写入1,取货完成后恢复0 |
| | | /// AGV 正在取货:下线AGV写入1,取货完成后恢复0 |
| | | /// </summary> |
| | | public int AgvPicking { get; set; } |
| | | |
| | | /// <summary> |
| | | /// AGV 正在取货:下线AGV写入1,取货完成后恢复0 |
| | | /// AGV 正在取货:下线AGV写入1,取货完成后恢复0 |
| | | /// </summary> |
| | | /// <param name="value"></param> |
| | | /// <returns></returns> |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// AGV 正在放托盘垛:上线AGV写入1,放托完成后恢复0 |
| | | /// AGV 正在放托盘垛:上线AGV写入1,放托完成后恢复0 |
| | | /// </summary> |
| | | public int AgvPlacingPallet { get; set; } |
| | | |
| | | /// <summary> |
| | | /// AGV 正在放托盘垛:上线AGV写入1,放托完成后恢复0 |
| | | /// AGV 正在放托盘垛:上线AGV写入1,放托完成后恢复0 |
| | | /// </summary> |
| | | public bool SetAgvPlacingPallet(int value) { |
| | | if (!ModbusHelper.WriteSingleRegister(11, value, Ip, Port)) { |
| | |
| | | /// </summary> |
| | | public class S7Helper |
| | | { |
| | | public static Dictionary<string, Plc> ip_Plc = new Dictionary<string, Plc>();//内存,连接上的PLC通讯对象 |
| | | public static Dictionary<string, Plc> ip_Plc = new Dictionary<string, Plc>();//内存,连接上的PLC通讯对象 |
| | | |
| | | public S7Helper(string ip, short rack, short slot) |
| | | { |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 批量读取或单独读取DB块数据(8位byte),并转换成字符串形式 |
| | | /// 批量读取或单独读取DB块数据 (8位byte) ,并转换成字符串形式 |
| | | /// </summary> |
| | | /// <param name="deviceIp">plc设备通讯地址</param> |
| | | /// <param name="dbNo">DB块号</param> |
| | | /// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param> |
| | | /// <param name="count">读取的个数,1个=8位十六进制数</param> |
| | | /// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param> |
| | | /// <param name="count">读取的个数,1个=8位十六进制数</param> |
| | | /// <returns></returns> |
| | | public static string ReadString(string deviceIp, int dbNo, int startByteAdr, int count) |
| | | { |
| | |
| | | if (plc.IsConnected) |
| | | { |
| | | var data = plc.ReadBytes(DataType.DataBlock, dbNo, startByteAdr, count); |
| | | result = System.Text.Encoding.UTF8.GetString(data).TrimEnd('\0').TrimEnd('\n').TrimEnd('\r'); ;//此方法可以把byte数组转换成字符串,但是会造成\0\u结束符不显示,需要下位机正确的数据 |
| | | result = System.Text.Encoding.UTF8.GetString(data).TrimEnd('\0').TrimEnd('\n').TrimEnd('\r'); ;//此方法可以把byte数组转换成字符串,但是会造成\0\u结束符不显示,需要下位机正确的数据 |
| | | if (result == string.Empty) |
| | | { |
| | | Link(plc);//设备发送的数据为空,重连 |
| | | Link(plc);//设备发送的数据为空,重连 |
| | | } |
| | | } |
| | | else |
| | | { |
| | | Link(plc);//设备未连接,重连 |
| | | Link(plc);//设备未连接,重连 |
| | | } |
| | | } |
| | | else |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 批量写入或单独写入DB块数据(8位byte),以字符串转换byte形式写入 |
| | | /// 批量写入或单独写入DB块数据 (8位byte) ,以字符串转换byte形式写入 |
| | | /// </summary> |
| | | /// <param name="deviceIp">plc设备通讯地址</param> |
| | | /// <param name="dbNo">DB块号</param> |
| | | /// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param> |
| | | /// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param> |
| | | /// <param name="data">要写入的数据</param> |
| | | /// <returns></returns> |
| | | public static bool WriteString(string deviceIp, int dbNo, int startByteAdr, string data) |
| | |
| | | } |
| | | else |
| | | { |
| | | Link(plc);//设备未连接,重连 |
| | | Link(plc);//设备未连接,重连 |
| | | } |
| | | } |
| | | else |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 批量读取或单独读取DB块数据(8位byte) |
| | | /// 批量读取或单独读取DB块数据 (8位byte) |
| | | /// </summary> |
| | | /// <param name="deviceIp">plc设备通讯地址</param> |
| | | /// <param name="dbNo">DB块号</param> |
| | | /// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param> |
| | | /// <param name="count">读取的个数,1个=8位十六进制数</param> |
| | | /// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param> |
| | | /// <param name="count">读取的个数,1个=8位十六进制数</param> |
| | | /// <returns></returns> |
| | | public static byte[] ReadBytes(string deviceIp, int dbNo, int startByteAdr, int count) |
| | | { |
| | |
| | | |
| | | if (result.Length == 0) |
| | | { |
| | | Link(plc);//设备发送的数据为空,重连 |
| | | Link(plc);//设备发送的数据为空,重连 |
| | | } |
| | | } |
| | | else |
| | | { |
| | | Link(plc);//设备未连接,重连 |
| | | Link(plc);//设备未连接,重连 |
| | | } |
| | | } |
| | | else |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 批量写入或单独写入DB块数据(8位byte) |
| | | /// 批量写入或单独写入DB块数据 (8位byte) |
| | | /// </summary> |
| | | /// <param name="deviceIp">plc设备通讯地址</param> |
| | | /// <param name="dbNo">DB块号</param> |
| | | /// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param> |
| | | /// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param> |
| | | /// <param name="data">要写入的数据</param> |
| | | /// <returns></returns> |
| | | public static bool WriteBytes(string deviceIp, int dbNo, int startByteAdr, byte[] data) |
| | |
| | | } |
| | | else |
| | | { |
| | | Link(plc);//设备未连接,重连 |
| | | Link(plc);//设备未连接,重连 |
| | | } |
| | | } |
| | | else |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 批量读取或单独读取DB块数据(1位bit) |
| | | /// 批量读取或单独读取DB块数据 (1位bit) |
| | | /// </summary> |
| | | /// <param name="deviceIp">plc设备通讯地址</param> |
| | | /// <param name="dbNo">DB块号</param> |
| | | /// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param> |
| | | /// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param> |
| | | /// <param name="count">要读取多少位</param> |
| | | /// <param name="bitAdr">从第几位开始读取</param> |
| | | /// <returns></returns> |
| | |
| | | } |
| | | if (result.Length == 0) |
| | | { |
| | | Link(plc);//设备发送的数据为空,重连 |
| | | Link(plc);//设备发送的数据为空,重连 |
| | | } |
| | | } |
| | | else |
| | | { |
| | | Link(plc);//设备未连接,重连 |
| | | Link(plc);//设备未连接,重连 |
| | | } |
| | | } |
| | | else |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 批量写入或单独写入DB块数据(1位bit) |
| | | /// 批量写入或单独写入DB块数据 (1位bit) |
| | | /// </summary> |
| | | /// <param name="deviceIp">plc设备通讯地址</param> |
| | | /// <param name="dbNo">DB块号</param> |
| | | /// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param> |
| | | /// <param name="biteAdr">起始bit地址,从第几位开始写k</param> |
| | | /// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param> |
| | | /// <param name="biteAdr">起始bit地址,从第几位开始写k</param> |
| | | /// <param name="bitValue">要写入的数据</param> |
| | | /// <returns></returns> |
| | | public static bool WriteBits(string deviceIp, int dbNo, int startByteAdr, byte biteAdr, BitArray bitValue) |
| | |
| | | } |
| | | else |
| | | { |
| | | Link(plc);//设备未连接,重连 |
| | | Link(plc);//设备未连接,重连 |
| | | } |
| | | } |
| | | else |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 通过S7协议连接下位机时需要的model,应该放在model层,这里我懒了 |
| | | /// 通过S7协议连接下位机时需要的model,应该放在model层,这里我懒了 |
| | | /// </summary> |
| | | public class S7ConfigModel |
| | | { |
| | |
| | | res = BitConverter.ToString(data).Replace("-", ""); |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.Error(ex.Message, ex); |
| | | LogHelper.InfoEx(ex); |
| | | } |
| | | client.Disconnect(true); |
| | | client.Dispose(); |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 读保持寄存器,modbus rtu的封装 |
| | | /// 读保持寄存器,modbus rtu的封装 |
| | | /// </summary> |
| | | /// <param name="address"></param> |
| | | /// <param name="qty"></param> |
| | |
| | | public static bool Init(string ip, int port) { |
| | | lock (_connectLock) { |
| | | try { |
| | | // 若正在连接中,直接返回 |
| | | // 若正在连接中,直接返回 |
| | | if (_isConnecting) { |
| | | LogHelper.Info("已有连接正在尝试中,禁止重复操作"); |
| | | LogHelper.Info("已有连接正在尝试中,禁止重复操作"); |
| | | return false; |
| | | } |
| | | |
| | | _isConnecting = true; // 标记为连接中 |
| | | |
| | | // 释放旧 Socket(仅在未连接时) |
| | | // 释放旧 Socket (仅在未连接时) |
| | | if (_clientSocket != null && !_clientSocket.Connected) { |
| | | SafeCloseSocket(); |
| | | } |
| | |
| | | } |
| | | catch (SocketException ex) { |
| | | _isConnecting = false; |
| | | LogHelper.Error($"初始化连接失败: {ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | return false; |
| | | } |
| | | } |
| | |
| | | lock (_linkLock) { |
| | | try { |
| | | |
| | | // 若Socket存在但实际已断开,强制清理 |
| | | // 若Socket存在但实际已断开,强制清理 |
| | | if (_clientSocket != null && (_clientSocket.Poll(0, SelectMode.SelectRead) && _clientSocket.Available == 0)) { |
| | | SafeCloseSocket(); |
| | | } |
| | |
| | | // 原有逻辑 |
| | | if (_clientSocket != null && _clientSocket.Connected) { |
| | | //if (ip == _ip && port == _port) { |
| | | LogHelper.Info($"产线已连接,无需重连,IP:{ip},端口:{port}"); |
| | | LogHelper.Info($"产线已连接,无需重连,IP:{ip},端口:{port}"); |
| | | return false; |
| | | //} |
| | | |
| | |
| | | return Init(ip, port); |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.Error($"产线重连失败,IP:{ip},端口:{port},异常:{ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | return false; |
| | | } |
| | | } |
| | |
| | | |
| | | // 仅在连接成功时启动接收 |
| | | if (_clientSocket.Connected) { |
| | | LogHelper.Info($"成功连接到服务端:{_ip}:{_port}"); |
| | | LogHelper.Info($"成功连接到服务端:{_ip}:{_port}"); |
| | | _clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceiveCallback, null); |
| | | } |
| | | else { |
| | | LogHelper.Info("连接未成功,关闭Socket"); |
| | | LogHelper.Info("连接未成功,关闭Socket"); |
| | | SafeCloseSocket(); |
| | | } |
| | | } |
| | |
| | | LogHelper.Info("连接过程中Socket被释放"); |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.Error($"连接失败:{ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | SafeCloseSocket(); |
| | | } |
| | | finally { |
| | |
| | | _clientSocket.Close(); |
| | | _clientSocket.Dispose(); |
| | | |
| | | // 断开后:清除对应IP:Port的接收数据 |
| | | // 断开后:清除对应IP:Port的接收数据 |
| | | string key = $"{_ip}:{_port}"; |
| | | if (_receivedDataQueue.ContainsKey(key)) { |
| | | _receivedDataQueue.Remove(key); |
| | | LogHelper.Info($"已清理队列数据,Key:{key}"); |
| | | LogHelper.Info($"已清理队列数据,Key:{key}"); |
| | | } |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.Error($"释放Socket资源异常:{ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | } |
| | | finally { |
| | | _clientSocket = null; |
| | |
| | | _clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, ReceiveCallback, null); |
| | | } |
| | | else { |
| | | // 服务端主动关闭连接,触发清理 |
| | | // 服务端主动关闭连接,触发清理 |
| | | LogHelper.Info("连接已被服务端关闭"); |
| | | SafeCloseSocket(); |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.Error($"接收数据异常:{ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | SafeCloseSocket(); // 异常时主动关闭 |
| | | } |
| | | } |
| | |
| | | //read = result; |
| | | return false; |
| | | } |
| | | LogHelper.Info($"读产线托盘下线数据成功:{BitConverter.ToString(result)}"); |
| | | LogHelper.Info($"读产线托盘下线数据成功:{BitConverter.ToString(result)}"); |
| | | read = result; |
| | | return true; |
| | | } |
| | | else { |
| | | //LogHelper.Info($"_clientSocket={_clientSocket} connected={_clientSocket?.Connected}"); |
| | | Link(_ip, _port); |
| | | LogHelper.Info($"读产线托盘下线数据失败(未连接),准备重连"); |
| | | LogHelper.Info($"读产线托盘下线数据失败 (未连接) ,准备重连"); |
| | | return false; |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | //LogHelper.Error($"读产线托盘下线数据失败(发生了异常:{JsonConvert.SerializeObject(ex)}):{ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | return false; |
| | | /* 异常处理 */ |
| | |
| | | /// <param name="registers">Modbus寄存器数组</param> |
| | | /// <returns>字节数组</returns> |
| | | public static byte[] ConvertRegistersToBytes(ushort[] registers) { |
| | | // 每个寄存器是16位(2字节),所以总字节数是寄存器数量的2倍 |
| | | // 每个寄存器是16位(2字节),所以总字节数是寄存器数量的2倍 |
| | | byte[] bytes = new byte[registers.Length * 2]; |
| | | |
| | | for (int i = 0; i < registers.Length; i++) { |
| | | // Modbus使用大端序,高位字节在前 |
| | | // Modbus使用大端序,高位字节在前 |
| | | bytes[i * 2] = (byte)(registers[i] >> 8); // 高位字节 |
| | | bytes[i * 2 + 1] = (byte)(registers[i] & 0xFF); // 低位字节 |
| | | } |
| | |
| | | public static string ConvertBytesToString(byte[] bytes) { |
| | | // 查找第一个0x00字节(字符串结束符)的位置 |
| | | int length = Array.IndexOf(bytes, (byte)0); |
| | | if (length < 0) length = bytes.Length; // 如果没有结束符,使用全部字节 |
| | | if (length < 0) length = bytes.Length; // 如果没有结束符,使用全部字节 |
| | | |
| | | // 根据设备使用的编码转换(常见的有ASCII或UTF-8) |
| | | // 这里使用ASCII编码作为示例,实际应根据设备文档确定编码方式 |
| | | // 这里使用ASCII编码作为示例,实际应根据设备文档确定编码方式 |
| | | return Encoding.ASCII.GetString(bytes, 0, length); |
| | | |
| | | // 如果是UTF-8编码,使用下面这行代替上面那行 |
| | | // 如果是UTF-8编码,使用下面这行代替上面那行 |
| | | // return Encoding.UTF8.GetString(bytes, 0, length); |
| | | } |
| | | |
| | |
| | | } |
| | | else { |
| | | Link(_ip, _port); |
| | | LogHelper.Info($"写电梯入货数据失败(未连接):{Encoding.UTF8.GetString(sends)}"); |
| | | LogHelper.Info($"写电梯入货数据失败 (未连接) :{Encoding.UTF8.GetString(sends)}"); |
| | | return false; |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.Error($"写电梯入货数据失败(发送了异常):{ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | return false; |
| | | } |
| | | } |
| | |
| | | try { |
| | | if (_clientSocket != null && _clientSocket?.Connected == true) { |
| | | _receivedDataQueue.TryGetValue($"{_ip}:{_port}", out byte[] result); |
| | | LogHelper.Info($"读电梯出货数据成功:{BitConverter.ToString(result)}"); |
| | | LogHelper.Info($"读电梯出货数据成功:{BitConverter.ToString(result)}"); |
| | | return result; |
| | | } |
| | | else { |
| | | Link(_ip, _port); |
| | | LogHelper.Info($"读电梯出货数据失败(未连接),准备重连"); |
| | | LogHelper.Info($"读电梯出货数据失败 (未连接) ,准备重连"); |
| | | return null; |
| | | } |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.Error($"读电梯出货数据失败(发生了异常:{JsonConvert.SerializeObject(ex)}):{ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | return null; |
| | | /* 异常处理 */ |
| | | } |
| | |
| | | |
| | | public static string ChekElevator() { |
| | | try { |
| | | var res = "读取电梯数据的model,索引从1开始,满足以下条件才能发任务 \r\n " + |
| | | "字段,isNormal ,是否正常模式,1:正常模式,第7个Byte右侧第一位Bit \r\n" + |
| | | "字段,isValid,当前位置是否有效,1:有效,0:不用管,第9个Byte右侧第一位Bit \r\n" + |
| | | "字段,runMode,电梯运行模式,9=空闲泊停,7=自动运行,第10个Byte\r\n" + |
| | | "字段,isLock_1_Out,一层出口是否占用,1 = 占用,第14个Byte右侧第一位Bit\r\n" + |
| | | "字段,isLock_2_Out,二层出口是否占用,1 = 占用,第14个Byte右侧第二位Bit\r\n" + |
| | | "字段,taskNO,任务号\r\n" + |
| | | "判断电梯是否符合2楼到1楼搬送条件:isNormal 且 (runMode == 9 或 runMode == 7) 且 !isLock_1_Out \r\n" + |
| | | "判断电梯是否符合1楼到成品库区条件:isNormal 且 (runMode == 9 或 runMode == 7) 且 isLock_1_Out\r\n"; |
| | | var res = "读取电梯数据的model,索引从1开始,满足以下条件才能发任务 \r\n " + |
| | | "字段,isNormal ,是否正常模式,1:正常模式,第7个Byte右侧第一位Bit \r\n" + |
| | | "字段,isValid,当前位置是否有效,1:有效,0:不用管,第9个Byte右侧第一位Bit \r\n" + |
| | | "字段,runMode,电梯运行模式,9=空闲泊停,7=自动运行,第10个Byte\r\n" + |
| | | "字段,isLock_1_Out,一层出口是否占用,1 = 占用,第14个Byte右侧第一位Bit\r\n" + |
| | | "字段,isLock_2_Out,二层出口是否占用,1 = 占用,第14个Byte右侧第二位Bit\r\n" + |
| | | "字段,taskNO,任务号\r\n" + |
| | | "判断电梯是否符合2楼到1楼搬送条件:isNormal 且 (runMode == 9 或 runMode == 7) 且 !isLock_1_Out \r\n" + |
| | | "判断电梯是否符合1楼到成品库区条件:isNormal 且 (runMode == 9 或 runMode == 7) 且 isLock_1_Out\r\n"; |
| | | |
| | | |
| | | var isRead = ReadElevatorOutOk(); |
| | | var log = BitConverter.ToString(isRead); |
| | | res += "读取到的电梯byte数组:" + log + "\r\n"; |
| | | res += "读取到的电梯byte数组:" + log + "\r\n"; |
| | | //if (isRead != null && isRead.Length >= 14) { |
| | | // var elevatorReadInfo = new ElevatorReadInfo() { |
| | | // isNormal = (isRead[6] & 1) == 1, |
| | |
| | | |
| | | // var res1 = elevatorReadInfo.is2To1Ok(); |
| | | |
| | | // res += "判断电梯是否符合2楼到1楼搬送条件,如果符合则返回true,结果" + res1 + "\r\n"; |
| | | // res += "判断电梯是否符合2楼到1楼搬送条件,如果符合则返回true,结果" + res1 + "\r\n"; |
| | | |
| | | // var res2 = elevatorReadInfo.is1ToOk(); |
| | | |
| | | // res += "判断电梯是否符合1楼到成品库区条件,如果符合则返回true,结果" + res2 + "\r\n"; |
| | | // res += "判断电梯是否符合1楼到成品库区条件,如果符合则返回true,结果" + res2 + "\r\n"; |
| | | //} |
| | | //else { |
| | | // return "读取电梯状态失败,byte数组要求大于等于14个且不为空"; |
| | | // return "读取电梯状态失败,byte数组要求大于等于14个且不为空"; |
| | | //} |
| | | return res; |
| | | } |
| | |
| | | return false; |
| | | } |
| | | catch (Exception ex) { |
| | | LogHelper.Error($"判断电梯是否断电(发生了异常:{JsonConvert.SerializeObject(ex)}):{ex.Message}", ex); |
| | | LogHelper.InfoEx(ex); |
| | | return false; |
| | | } |
| | | } |
| | |
| | | } |
| | | private void Init(string ip, int port) |
| | | { |
| | | //创建一个新的Socket,这里我们使用最常用的基于TCP的Stream Socket(流式套接字) |
| | | //创建一个新的Socket,这里我们使用最常用的基于TCP的Stream Socket (流式套接字) |
| | | var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); |
| | | try |
| | | { |
| | | //将该socket绑定到主机上面的某个端口,端口应该放到配置文件中 |
| | | //将该socket绑定到主机上面的某个端口,端口应该放到配置文件中 |
| | | socket.Bind(new IPEndPoint(IPAddress.Parse(ip), port)); |
| | | Console.WriteLine(port); |
| | | //启动监听,并且设置一个最大的队列长度 |
| | | //启动监听,并且设置一个最大的队列长度 |
| | | socket.Listen(30); |
| | | //开始接受客户端连接请求 |
| | | socket.BeginAccept(new AsyncCallback(ClientAccepted), socket); |
| | |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | Console.WriteLine($"【接收客户端的消息异常】:" + ex.Message); |
| | | Console.WriteLine($"【接收客户端的消息异常】:" + ex.Message); |
| | | } |
| | | //准备接受下一个客户端请求 |
| | | socket.BeginAccept(new AsyncCallback(ClientAccepted), socket); |
| | |
| | | } |
| | | } |
| | | |
| | | //LogHelper.Info($"接收到信息,IP:{remote_ip},MSG:{BitConverter.ToString(buffers[remote_ip])}"); |
| | | //LogHelper.Info($"接收到信息,IP:{remote_ip},MSG:{BitConverter.ToString(buffers[remote_ip])}"); |
| | | |
| | | if (buffers.Keys.Contains(remote_ip)) |
| | | { |
| | |
| | | |
| | | string rfids16 = BitConverter.ToString(rfid); |
| | | string rfids = Encoding.ASCII.GetString(rfid); |
| | | //LogHelper.Info($"读卡器校验对应容器号:{rfids},其16进制形式:{rfids16}"); |
| | | //LogHelper.Info($"读卡器校验对应容器号:{rfids},其16进制形式:{rfids16}"); |
| | | //if (ScanCodeHelper.Analysis(remote_ip, rfids))//校验RFID |
| | | //{ |
| | | // isCheck[remote_ip] = false; |
| | |
| | | } |
| | | else |
| | | { |
| | | LogHelper.Info($"不满足读卡器校验规定:IP:{remote_ip},MSG:{message}"); |
| | | LogHelper.Info($"不满足读卡器校验规定:IP:{remote_ip},MSG:{message}"); |
| | | } |
| | | } |
| | | catch(Exception ex) |
| | | { |
| | | LogHelper.Info($"扫码校验发生了异常:{ex.Message}"); |
| | | LogHelper.Info($"扫码校验发生了异常:{ex.Message}"); |
| | | saoMa[remote_ip] = 4;//扫码异常 |
| | | } |
| | | |
| | |
| | | } |
| | | catch(Exception ex) |
| | | { |
| | | LogHelper.Info($"卷帘门校验发生了异常:{ex.Message}"); |
| | | LogHelper.Info($"卷帘门校验发生了异常:{ex.Message}"); |
| | | } |
| | | //TcpServerSend(remote_ip, System.Text.Encoding.Default.GetBytes(msgSend)); |
| | | Array.Clear(buffers[remote_ip], 0, buffers[remote_ip].Length);//清空当前IP Buffer |
| | |
| | | } |
| | | } |
| | | |
| | | //接收下一个消息(因为这是一个递归的调用,所以这样就可以一直接收消息了) |
| | | //接收下一个消息(因为这是一个递归的调用,所以这样就可以一直接收消息了) |
| | | socket.BeginReceive(buffers[remote_ip], 0, buffers[remote_ip].Length, SocketFlags.None, new AsyncCallback(ReceiveMessage), socket); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | |
| | | LogHelper.InfoEx(ex); |
| | | } |
| | | } |
| | | |
| | |
| | | try |
| | | { |
| | | client.Send(msg); |
| | | LogHelper.Info($"已发送给该AGV地址{ip},{msg}"); |
| | | LogHelper.Info($"已发送给该AGV地址{ip},{msg}"); |
| | | return true; |
| | | } |
| | | catch (SocketException ex) |
| | |
| | | } |
| | | else |
| | | { |
| | | LogHelper.Info("未找到该设备,是否已连接?"); |
| | | LogHelper.Info("未找到该设备,是否已连接?"); |
| | | } |
| | | return false; |
| | | |
| | |
| | | /// <param name="created_user"></param> |
| | | /// <returns></returns> |
| | | public static int CreateOrder(string taskNo, int priority, string param, string ts = "churuku", string created_user = "hanhe") { |
| | | LogHelper.Info($"CreateOrder参数信息:taskNo:{taskNo},priority:{priority},param:{param},ts:{ts},created_user:{created_user}", "API"); |
| | | LogHelper.Info($"CreateOrder参数信息:taskNo:{taskNo},priority:{priority},param:{param},ts:{ts},created_user:{created_user}", "API"); |
| | | var msg = ""; |
| | | var orderId = 0; |
| | | var data = new OrderInfo() { order_name = taskNo, priority = priority, dead_line = DateTime.Now, ts_name = ts, parameters = param, created_user = created_user }; |
| | |
| | | // orderId = dataResult.data[0].in_order_id; |
| | | //} |
| | | |
| | | // 返回参数中,code目前不再使用,可通过msg字段判断是否成功,如果msg为”success”则表示成功,否则为报错信息或不存在。http code为422时候的报错为系统报错,其中的msg无法全部获取。 |
| | | // SELFNOTE: 直接调用HttpHelper.Post方法,无法获取header,暂时不考虑 |
| | | // 返回参数中,code目前不再使用,可通过msg字段判断是否成功,如果msg为”success”则表示成功,否则为报错信息或不存在。http code为422时候的报错为系统报错,其中的msg无法全部获取。 |
| | | // SELFNOTE: 直接调用HttpHelper.Post方法,无法获取header,暂时不考虑 |
| | | if (dataResult.msg == "success") { |
| | | orderId = dataResult.data[0].in_order_id; |
| | | } |
| | |
| | | // return result; |
| | | //} |
| | | |
| | | // 返回参数中,code目前不再使用,可通过msg字段判断是否成功,如果msg为”success”则表示成功,否则为报错信息或不存在。http code为422时候的报错为系统报错,其中的msg无法全部获取。 |
| | | // SELFNOTE: 直接调用HttpHelper.Post方法,无法获取header,暂时不考虑 |
| | | // 返回参数中,code目前不再使用,可通过msg字段判断是否成功,如果msg为”success”则表示成功,否则为报错信息或不存在。http code为422时候的报错为系统报错,其中的msg无法全部获取。 |
| | | // SELFNOTE: 直接调用HttpHelper.Post方法,无法获取header,暂时不考虑 |
| | | // 尊重文档的版本 |
| | | if (dataResult.msg == "success") { // 目前只取消一个任务,成功无需再检查success_list和error_list |
| | | if (dataResult.msg == "success") { // 目前只取消一个任务,成功无需再检查success_list和error_list |
| | | Console.WriteLine("[guozi-CancelOrder]取消订单成功"); |
| | | result = true; |
| | | return result; |
| | |
| | | // return result; |
| | | //} |
| | | |
| | | // 返回参数中,code目前不再使用,可通过msg字段判断是否成功,如果msg为”success”则表示成功,否则为报错信息或不存在。http code为422时候的报错为系统报错,其中的msg无法全部获取。 |
| | | // SELFNOTE: 直接调用HttpHelper.Post方法,无法获取header,暂时不考虑 |
| | | // 返回参数中,code目前不再使用,可通过msg字段判断是否成功,如果msg为”success”则表示成功,否则为报错信息或不存在。http code为422时候的报错为系统报错,其中的msg无法全部获取。 |
| | | // SELFNOTE: 直接调用HttpHelper.Post方法,无法获取header,暂时不考虑 |
| | | // 尊重文档的版本 |
| | | if (dataResult.msg == "success") { // 目前只取消一个任务,成功无需再检查success_list和error_list |
| | | if (dataResult.msg == "success") { // 目前只取消一个任务,成功无需再检查success_list和error_list |
| | | if (dataResult.success_list.Count == requests.Count && dataResult.error_list.Count == 0) { |
| | | Console.WriteLine("[guozi-CancelOrder]取消订单成功"); |
| | | result = true; |
| | |
| | | /// </summary> |
| | | public string trkType { get; set; } |
| | | /// <summary> |
| | | /// 1-999(值越大优先级越高) |
| | | /// 1-999 (值越大优先级越高) |
| | | /// </summary> |
| | | public string trkPrty { get; set; } = "1"; |
| | | public string frmPos { get; set; } |
| | |
| | | public string groupNo { get; set; } = ""; |
| | | public string clientCode { get; set; } = "WMS"; |
| | | /// <summary> |
| | | /// 格式:2022-11-11 11:32:08 |
| | | /// 格式:2022-11-11 11:32:08 |
| | | /// </summary> |
| | | public string reqTime { get; set; } = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); |
| | | |
| | |
| | | public string requestPk { get; set; } |
| | | public string contNo { get; set; } |
| | | /// <summary> |
| | | /// 双方系统共同定义 1-入库 2-出库 3-移库 (后续如有增加再协定) |
| | | /// 双方系统共同定义 1-入库 2-出库 3-移库 (后续如有增加再协定) |
| | | /// </summary> |
| | | public string noticeType { get; set; } |
| | | public string curPos { get; set; } |
| | | public string noticeInfo { get; set; } |
| | | /// <summary> |
| | | /// 0-成功 (入库上架完成/出库下架完成/库内移库完成:移库只上报最终移库上架) 或 其他-异常码(反馈相关结果原因,WMS根据情况处理 |
| | | /// 0-成功 (入库上架完成/出库下架完成/库内移库完成:移库只上报最终移库上架) 或 其他-异常码(反馈相关结果原因,WMS根据情况处理 |
| | | /// 1-入库有货 2-入远近有货 3-出库无货 4-出远近有货) |
| | | /// </summary> |
| | | public string code { get; set; } |
| | |
| | | // 此代码由工具生成。 |
| | | // 运行时版本:4.0.30319.42000 |
| | | // |
| | | // 对此文件的更改可能会导致不正确的行为,并且如果 |
| | | // 重新生成代码,这些更改将会丢失。 |
| | | // 对此文件的更改可能会导致不正确的行为,并且如果 |
| | | // 重新生成代码,这些更改将会丢失。 |
| | | // </auto-generated> |
| | | //------------------------------------------------------------------------------ |
| | | |
| | |
| | | namespace HH.WCS.Mobox3.DSZSH.dispatch |
| | | { |
| | | /// <summary> |
| | | /// NDC的API接口,用于替代原NDC、NDCHelper和HostToAGV模块 |
| | | /// NDC的API接口,用于替代原NDC,NDCHelper和HostToAGV模块 |
| | | /// </summary> |
| | | public class NDCApi |
| | | { |
| | |
| | | try |
| | | { |
| | | string jsonInfo = JsonConvert.SerializeObject(model); |
| | | LogHelper.Info($"任务{taskNo}下发,{jsonInfo}", "NDC"); |
| | | LogHelper.Info($"NDC任务下发:{taskNo}\n\n{jsonInfo}\n", "NDC"); |
| | | var result = httpH.WebPost(NDCApiUrl + "Add", jsonInfo); |
| | | LogHelper.Info($"任务下发结果res={result}", "NDC"); |
| | | LogHelper.Info($"NDC任务下发结果:res='{result}'", "NDC"); |
| | | agvApiResult = JsonConvert.DeserializeObject<AgvApiResult>(result); |
| | | return agvApiResult; |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | LogHelper.Info($"任务下发失败 res={e.Message}", "NDC"); |
| | | LogHelper.Info($"任务下发失败:res='{e.Message}'", "NDC"); |
| | | agvApiResult.err_code = -1; |
| | | agvApiResult.err_msg = e.Message; |
| | | return agvApiResult; |
| | |
| | | try |
| | | { |
| | | string jsonInfo = JsonConvert.SerializeObject(model); |
| | | LogHelper.Info($"任务{model.task_no}下发,{jsonInfo}", "NDC"); |
| | | LogHelper.Info($"任务{model.task_no}下发,{jsonInfo}", "NDC"); |
| | | |
| | | var result = httpH.WebPost(NDCApiUrl + "Add", jsonInfo); |
| | | LogHelper.Info($"任务下发结果res={result}", "NDC"); |
| | |
| | | try |
| | | { |
| | | string jsonInfo = JsonConvert.SerializeObject(model); |
| | | LogHelper.Info($"任务{model.task_no}取消,{jsonInfo}", "NDC"); |
| | | LogHelper.Info($"任务{model.task_no}取消,{jsonInfo}", "NDC"); |
| | | |
| | | var result = httpH.WebPost(NDCApiUrl + "Cancel", jsonInfo); |
| | | LogHelper.Info($"任务{model.task_no}取消结果={result}", "NDC"); |
| | |
| | | try |
| | | { |
| | | string jsonInfo = JsonConvert.SerializeObject(model); |
| | | LogHelper.Info($"任务{model.task_no}取消,{jsonInfo}", "NDC"); |
| | | LogHelper.Info($"任务{model.task_no}取消,{jsonInfo}", "NDC"); |
| | | |
| | | var result = httpH.WebPost(NDCApiUrl + "Cancel", jsonInfo); |
| | | LogHelper.Info($"任务{model.task_no}取消结果={result}", "NDC"); |
| | |
| | | try |
| | | { |
| | | string jsonInfo = JsonConvert.SerializeObject(model); |
| | | LogHelper.Info($"任务{model.task_no}优先级更改,{jsonInfo}", "NDC"); |
| | | LogHelper.Info($"任务{model.task_no}优先级更改,{jsonInfo}", "NDC"); |
| | | |
| | | var result = httpH.WebPost(NDCApiUrl + "ChangePri", jsonInfo); |
| | | LogHelper.Info($"任务{model.task_no}优先级更改结果={result}", "NDC"); |
| | |
| | | try |
| | | { |
| | | string jsonInfo = JsonConvert.SerializeObject(model); |
| | | LogHelper.Info($"任务{model.task_no}优先级更改,{jsonInfo}", "NDC"); |
| | | LogHelper.Info($"任务{model.task_no}优先级更改,{jsonInfo}", "NDC"); |
| | | |
| | | var result = httpH.WebPost(NDCApiUrl + "ChangePri", jsonInfo); |
| | | LogHelper.Info($"任务{model.task_no}优先级更改结果={result}", "NDC"); |
| | |
| | | try |
| | | { |
| | | string jsonInfo = JsonConvert.SerializeObject(model); |
| | | LogHelper.Info($"任务{model.task_no}参数更改,{jsonInfo}", "NDC"); |
| | | LogHelper.Info($"任务{model.task_no}参数更改,{jsonInfo}", "NDC"); |
| | | |
| | | var result = httpH.WebPost(NDCApiUrl + "ChangeParam", jsonInfo); |
| | | LogHelper.Info($"任务{model.task_no}参数更改结果={result}", "NDC"); |
| | |
| | | try |
| | | { |
| | | string jsonInfo = JsonConvert.SerializeObject(model); |
| | | LogHelper.Info($"任务{model.task_no}参数更改,{jsonInfo}", "NDC"); |
| | | LogHelper.Info($"任务{model.task_no}参数更改,{jsonInfo}", "NDC"); |
| | | |
| | | var result = httpH.WebPost(NDCApiUrl + "ChangeParam", jsonInfo); |
| | | LogHelper.Info($"任务{model.task_no}参数更改结果={result}", "NDC"); |
| | |
| | | /// </summary> |
| | | public class AgvApiResult |
| | | { |
| | | public int err_code { set; get; }//异常码:0 - 正常,其它值为异常错误码 |
| | | public string err_msg { set; get; }//返回的错误描述,在 err_code <> 0 时返回 |
| | | public object result { set; get; }//正确返回的结果内容,在 err_code = 0 且有返回内容时 |
| | | public int err_code { set; get; }//异常码:0 - 正常,其它值为异常错误码 |
| | | public string err_msg { set; get; }//返回的错误描述,在 err_code <> 0 时返回 |
| | | public object result { set; get; }//正确返回的结果内容,在 err_code = 0 且有返回内容时 |
| | | } |
| | | |
| | | public class AddOrderNewModel |
| | | { |
| | | public int ts_no { set; get; }//TS 号,必须有值 |
| | | public int ts_no { set; get; }//TS 号,必须有值 |
| | | public int pri { set; get; }//优先级 |
| | | public string task_no { set; get; }//上游任务编码,如果 no_feedback = 1 时,可以为空 |
| | | public string task_no { set; get; }//上游任务编码,如果 no_feedback = 1 时,可以为空 |
| | | public List<param> param { set; get; } = new List<param>();//参数列表 |
| | | } |
| | | |
| | |
| | | public class CancelOrderModel |
| | | { |
| | | public string task_no { set; get; }//上游任务编码 |
| | | public bool is_force { set; get; } = true;//是否强制取消,1 – 强制 |
| | | public bool is_force { set; get; } = true;//是否强制取消,1 – 强制 |
| | | } |
| | | |
| | | public class ChangeParamModel |
| | | { |
| | | public string task_no { set; get; }//上游任务编码 |
| | | public int param_no { set; get; }//参数号 |
| | | public string param { set; get; }//参数内容,多个参数以英文分号(;)分隔 |
| | | public string param { set; get; }//参数内容,多个参数以英文分号(;)分隔 |
| | | } |
| | | |
| | | public class ChangePriModel |
| | |
| | | |
| | | namespace HH.WCS.Mobox3.DSZSH.models { |
| | | /// <summary> |
| | | /// 【框架】模板抽象类:基本表数据模型 |
| | | /// 【框架】模板抽象类:基本表数据模型 |
| | | /// </summary> |
| | | public abstract class BaseModel { |
| | | |
| | | /// <summary> |
| | | /// 唯一识别码(底层主键) |
| | | /// 唯一识别码 (底层主键) |
| | | /// </summary> |
| | | [SugarColumn(IsPrimaryKey = true)] |
| | | public string S_ID { get; set; } = Guid.NewGuid().ToString("D"); |
| | |
| | | public DateTime T_MODIFY { get; set; } = DateTime.Now; |
| | | |
| | | /// <summary> |
| | | /// 数据状态:编辑、定版 |
| | | /// 数据状态:编辑,定版 |
| | | /// </summary> |
| | | public string S_STATE { get; set; } = "编辑"; |
| | | } |
| | |
| | | public string S_CNTR_CODE { set; get; } |
| | | |
| | | /// <summary> |
| | | /// 生产车数,逗号分割 |
| | | /// 生产车数,逗号分割 |
| | | /// </summary> |
| | | public string S_CAR_CODE { set; get; } |
| | | public string S_B_STATE { set; get; }//状态 |
| | |
| | | public string S_CNTR_CODE { get; set; } = string.Empty; |
| | | |
| | | /// <summary> |
| | | /// 货品状态:0合格 1待检 2不合格 3抽检中;下线即待检 |
| | | /// 货品状态:0合格 1待检 2不合格 3抽检中;下线即待检 |
| | | /// </summary> |
| | | public string S_ITEM_STATE { get; set; } = "待检"; |
| | | |
| | | /// <summary> |
| | | /// 货品状态:0合格 1待检 2不合格 3正在检验;下线即待检 |
| | | /// 货品状态:0合格 1待检 2不合格 3正在检验;下线即待检 |
| | | /// </summary> |
| | | public int N_ITEM_STATE { get; set; } = 1; |
| | | |
| | |
| | | ///// <summary> |
| | | ///// 产线号 |
| | | ///// </summary> |
| | | //public int N_PRODUCT_LINE { get; set; } = 0; // NOTE 后续MES可能会提供,先创建 |
| | | //public int N_PRODUCT_LINE { get; set; } = 0; // NOTE 后续MES可能会提供,先创建 |
| | | |
| | | // ---------------- |
| | | |
| | |
| | | /// </summary> |
| | | public string S_TYPE { get; set; } = string.Empty; |
| | | /// <summary> |
| | | /// 规格(用于记录容器适用的物料编号) |
| | | /// 规格 (用于记录容器适用的物料编号) |
| | | /// </summary> |
| | | public string S_SPEC { get; set; } = string.Empty; |
| | | /// <summary> |
| | | /// 来源(这里记录为创建该容器的主体:Mobox或具体的任务) |
| | | /// 来源 (这里记录为创建该容器的主体:Mobox或具体的任务) |
| | | /// </summary> |
| | | public string S_SOURCE { get; set; } = string.Empty; |
| | | |
| | |
| | | /// <summary> |
| | | /// 国自 AGV 对应的库位名称 |
| | | /// </summary> |
| | | public string S_AGV_SITE { get; set; } = ""; |
| | | public string S_AGV_SITE { get; set; } = "0"; |
| | | |
| | | /// <summary> |
| | | /// 货位容器容量 |
| | |
| | | // END |
| | | |
| | | /// <summary> |
| | | /// 上锁状态号:0无 1入库锁 2出库锁 3其它锁 |
| | | /// 上锁状态号:0无 1入库锁 2出库锁 3其它锁 |
| | | /// </summary> |
| | | public int N_LOCK_STATE { get; set; } = 0; |
| | | |
| | | /// <summary> |
| | | /// 上锁状态名称:0无 1入库锁 2出库锁 3其它锁 |
| | | /// 上锁状态名称:0无 1入库锁 2出库锁 3其它锁 |
| | | /// </summary> |
| | | public string S_LOCK_STATE { get; set; } = "无"; |
| | | |
| | | /// <summary> |
| | | /// Lock Operator:上锁的操作来源(通常是任务号) |
| | | /// Lock Operator:上锁的操作来源 (通常是任务号) |
| | | /// </summary> |
| | | public string S_LOCK_OP { get; set; } = ""; |
| | | |
| | | /// <summary> |
| | | /// 货位是否启用:Y启用 |
| | | /// 货位是否启用:Y启用 |
| | | /// </summary> |
| | | public string C_ENABLE { get; set; } = "Y"; |
| | | |
| | |
| | | /// 货位-容器 关系映射 |
| | | /// </summary> |
| | | /// <remarks> |
| | | /// 默认是一对多,通常情况是一对一 |
| | | /// 默认是一对多,通常情况是一对一 |
| | | /// </remarks> |
| | | [Navigate(NavigateType.OneToMany, nameof(TN_Loc_Container.S_LOC_CODE))] |
| | | public List<TN_Loc_Container> LocCntrRels { get; set; } |
| | |
| | | |
| | | public string S_BS_TYPE { get; set; } = string.Empty; // ERP |
| | | |
| | | public string S_BS_NO { get; set; } = string.Empty; // ERP 单号(来源单号) |
| | | public string S_BS_NO { get; set; } = string.Empty; // ERP 单号 (来源单号) |
| | | |
| | | /// <summary> |
| | | /// 业务状态:0待执行 1已下发 2执行中 3已完成 |
| | | /// 业务状态:0待执行 1已下发 2执行中 3已完成 |
| | | /// </summary> |
| | | public int N_B_STATE { get; set; } = 1; // 创建即执行 |
| | | |
| | |
| | | public string S_BATCH_NO { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 出库货品数量(整数,用于生成任务数) |
| | | /// 出库货品数量 (整数,用于生成任务数) |
| | | /// </summary> |
| | | public int N_COUNT { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 终点库区(由WMS下发任务时指定) |
| | | /// 终点库区 (由WMS下发任务时指定) |
| | | /// </summary> |
| | | public string S_END_AREA { get; set; } |
| | | |
| | |
| | | |
| | | public string S_BS_TYPE { get; set; } = string.Empty; // ERP |
| | | |
| | | public string S_BS_NO { get; set; } = string.Empty; // ERP 单号(来源单号) |
| | | public string S_BS_NO { get; set; } = string.Empty; // ERP 单号 (来源单号) |
| | | |
| | | /// <summary> |
| | | /// 业务状态:0待执行 1已下发 2执行中 3已完成 |
| | | /// 业务状态:0待执行 1已下发 2执行中 3已完成 |
| | | /// </summary> |
| | | public int N_B_STATE { get; set; } = 1; |
| | | |
| | |
| | | //public float F_OUT_QTY { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 终点库区(由WMS下发任务时指定) |
| | | /// 终点库区 (由WMS下发任务时指定) |
| | | /// </summary> |
| | | public string S_END_AREA { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 是否强制出库:0不强制 1强制 |
| | | /// 是否强制出库:0不强制 1强制 |
| | | /// </summary> |
| | | public bool B_FORCE_OUT { get; set; } |
| | | |
| | |
| | | [SugarTable("TN_Outbound_Plan")] |
| | | public class TN_Outbound_Plan : BaseModel { |
| | | /// <summary> |
| | | /// 计划单号(唯一标识) |
| | | /// 计划单号 (唯一标识) |
| | | /// </summary> |
| | | public string JHDH { get; set; } |
| | | |
| | |
| | | public int N_QTY { get; set; } = 0; |
| | | |
| | | /// <summary> |
| | | /// 货位编码(库内货位,入库就是终点,出库就是起点) |
| | | /// 货位编码 (库内货位,入库就是终点,出库就是起点) |
| | | /// </summary> |
| | | public string S_LOC_CODE { get; set; } |
| | | |
| | |
| | | public string S_BATCH_NO { get; set; } |
| | | public string S_END_AREA { get; set; } |
| | | /// <summary> |
| | | /// 业务状态:0等待执行 1已执行待生成任务 2任务执行中 3任务完成 |
| | | /// 业务状态:0等待执行 1已执行待生成任务 2任务执行中 3任务完成 |
| | | /// </summary> |
| | | public int N_B_STATE { get; set; } = 1; // 创建即执行 |
| | | } |
| | |
| | | //public int N_COUNT { get; set; } |
| | | public string S_END_AREA { get; set; } |
| | | /// <summary> |
| | | /// 业务状态:0等待执行 1已执行待生成任务 2任务执行中 3任务完成 |
| | | /// 业务状态:0等待执行 1已执行待生成任务 2任务执行中 3任务完成 |
| | | /// </summary> |
| | | public int N_B_STATE { get; set; } = 0; // 创建后需要确认执行 |
| | | } |
| | |
| | | public string S_BATCH_NO { get; set; } |
| | | public string S_END_AREA { get; set; } |
| | | /// <summary> |
| | | /// 业务状态:0等待执行 1已执行待生成任务 2任务执行中 3任务完成 |
| | | /// 业务状态:0等待执行 1已执行待生成任务 2任务执行中 3任务完成 |
| | | /// </summary> |
| | | public int N_B_STATE { get; set; } = 1; // 创建即执行 |
| | | } |
| | |
| | | //public int N_COUNT { get; set; } |
| | | public string S_END_AREA { get; set; } |
| | | /// <summary> |
| | | /// 业务状态:0等待执行 1已执行待生成任务 2任务执行中 3任务完成 |
| | | /// 业务状态:0等待执行 1已执行待生成任务 2任务执行中 3任务完成 |
| | | /// </summary> |
| | | public int N_B_STATE { get; set; } = 0; // 创建后需要确认执行 |
| | | } |
| | |
| | | public string S_EQ_NO { get; set; } |
| | | |
| | | /// <summary> |
| | | /// 任务状态:0等待 1已推送 2执行 3完成 4错误 |
| | | /// 任务状态:0等待 1已推送 2执行 3完成 4错误 |
| | | /// </summary> |
| | | public string S_B_STATE { get; set; } = "等待"; |
| | | |
| | | /// <summary> |
| | | /// 任务状态:0等待 1已推送 2执行 3完成 4错误 |
| | | /// 任务状态:0等待 1已推送 2执行 3完成 4错误 |
| | | /// </summary> |
| | | public int N_B_STATE { get; set; } |
| | | |
| | |
| | | public string S_BS_TYPE { get; set; } = string.Empty; |
| | | |
| | | ///// <summary> |
| | | ///// 是否强制出库:0不强制 1强制 |
| | | ///// 是否强制出库:0不强制 1强制 |
| | | ///// </summary> |
| | | //public int N_FORCE { get; set; } = 0; |
| | | |
| | |
| | | namespace HH.WCS.Mobox3.DSZSH.process |
| | | { |
| | | /// <summary> |
| | | /// 设备信号处理,主要是tcp信号,我们做server被动接收信号来处理,根据项目定制的 |
| | | /// 设备信号处理,主要是tcp信号,我们做server被动接收信号来处理,根据项目定制的 |
| | | /// </summary> |
| | | internal class DeviceProcess |
| | | { |
| | |
| | | #region 任务相关 |
| | | //--------------------------------------------------任务相关-------------------------------------------------- |
| | | /// <summary> |
| | | /// 取货卸货完成,缓存位状态更新 |
| | | /// 取货卸货完成,缓存位状态更新 |
| | | /// </summary> |
| | | /// <param name="mst"></param> |
| | | /// <param name="load"></param> |
| | | internal static void BufferLocUpdate(TN_Task mst, bool load) { |
| | | //var trayCarryCount = mst.N_CNTR_COUNT > 0 ? mst.N_CNTR_COUNT : 1; |
| | | if (load) { |
| | | Console.WriteLine($"任务{mst.S_CODE} 货位{mst.S_START_LOC}取货完成,起点解绑容器{mst.S_CNTR_CODE}"); |
| | | LogHelper.Info($"任务{mst.S_CODE} 货位{mst.S_START_LOC}取货完成,起点解绑容器{mst.S_CNTR_CODE}"); |
| | | Console.WriteLine($"任务{mst.S_CODE} 货位{mst.S_START_LOC}取货完成,起点解绑容器{mst.S_CNTR_CODE}"); |
| | | LogHelper.Info($"任务{mst.S_CODE} 货位{mst.S_START_LOC}取货完成,起点解绑容器{mst.S_CNTR_CODE}"); |
| | | LocationHelper.UnbindLocCntr(mst.S_START_LOC, mst.S_CNTR_CODE.Split(',').ToList()); |
| | | } |
| | | else { |
| | | Console.WriteLine($"任务{mst.S_CODE} 货位{mst.S_END_LOC}卸货完成,终点绑定容器{mst.S_CNTR_CODE}"); |
| | | LogHelper.Info($"任务{mst.S_CODE} 货位{mst.S_END_LOC}卸货完成,终点绑定容器{mst.S_CNTR_CODE}"); |
| | | Console.WriteLine($"任务{mst.S_CODE} 货位{mst.S_END_LOC}卸货完成,终点绑定容器{mst.S_CNTR_CODE}"); |
| | | LogHelper.Info($"任务{mst.S_CODE} 货位{mst.S_END_LOC}卸货完成,终点绑定容器{mst.S_CNTR_CODE}"); |
| | | LocationHelper.BindingLoc(mst.S_END_LOC, mst.S_CNTR_CODE.Split(',').ToList()); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 任务取消,缓存位状态更新 |
| | | /// 任务取消,缓存位状态更新 |
| | | /// </summary> |
| | | /// <param name="mst"></param> |
| | | internal static void BufferLocCancelUpdate(TN_Task mst) { |
| | | //任务取消,取货完成前的,起点的loadingCount和终点unLoadingCount都清除,取货完成的只处理终点 |
| | | //任务取消,取货完成前的,起点的loadingCount和终点unLoadingCount都清除,取货完成的只处理终点 |
| | | if (WCSHelper.CheckActionRecordExist(mst.S_CODE, 4)) { |
| | | //根据客户现场要求,如果取货完成任务失败人工拉到终点,我们就当卸货完成处理;如果是人工拉走到其它区域,我们就解锁终点,删除托盘。 |
| | | //根据客户现场要求,如果取货完成任务失败人工拉到终点,我们就当卸货完成处理;如果是人工拉走到其它区域,我们就解锁终点,删除托盘。 |
| | | //终点绑定 |
| | | BufferLocUpdate(mst, false); |
| | | LocationHelper.UnLockLoc(mst.S_END_LOC); |
| | |
| | | /// <param name="extData"></param> |
| | | internal static void OperateReq(string no, int state, string forkliftNo, string extData = "") { |
| | | if (state == 1101) { |
| | | //请求取货, |
| | | //请求取货, |
| | | } |
| | | if (state == 1102) { |
| | | //请求卸货, |
| | | //根据终点判断,是cb02的入口,判断内存中状态(要状态时间),允许卸货,通知agv改参数 |
| | | //请求卸货, |
| | | //根据终点判断,是cb02的入口,判断内存中状态 (要状态时间) ,允许卸货,通知agv改参数 |
| | | var dic = new Dictionary<string, string>(); |
| | | //< Req >< Order No = 'TN2302020002' ParamNo = '18' Param1 = '12' /></ Req > |
| | | dic.Add("No", no); |
| | |
| | | //改完参数车子就会自己卸货 |
| | | } |
| | | if (state == 1103) { |
| | | //大铁框叉走以后通知,我们要通知输送线 |
| | | //大铁框叉走以后通知,我们要通知输送线 |
| | | } |
| | | } |
| | | |
| | |
| | | internal static bool SendTask(TN_Task mst) { |
| | | var result = false; |
| | | switch (mst.N_SCHEDULE_TYPE) { |
| | | case 1: //通过NDC,hosttoagv调度设备 |
| | | case 1: //通过NDC,hosttoagv调度设备 |
| | | return SendNDCTask(mst); |
| | | case 5: //通过杭奥调度设备 |
| | | return SendHanAoTask(mst); |
| | |
| | | if (mst.N_B_STATE == 0) { |
| | | start = LocationHelper.GetAgvSite(mst.S_START_LOC); |
| | | end = LocationHelper.GetAgvSite(mst.S_END_LOC); |
| | | LogHelper.Info($"NDC推送任务:{mst.S_CODE};start='{start}',end='{end}'"); |
| | | |
| | | LogHelper.Info($"NDC推送任务 {mst.S_CODE};" + "start=" + start + "end= " + end); |
| | | var startLoc = LocationHelper.GetLoc(mst.S_START_LOC); |
| | | var endLoc = LocationHelper.GetLoc(mst.S_END_LOC); |
| | | var dic = new List<param>(); |
| | |
| | | dic.Add(new param() { name = "From", value = start.ToString() }); |
| | | dic.Add(new param() { name = "To", value = end.ToString() }); |
| | | dic.Add(new param() { name = "FUNC", value = startLoc.N_LAYER.ToString() }); |
| | | |
| | | dic.Add(new param() { name = "Ctype", value = "0" }); |
| | | |
| | | var res = NDCApi.AddOrderNew(1, 1, mst.S_CODE, dic);//添加新命令 |
| | | if (res != null && (res.err_code == 0 || res.err_code == 50009)) { |
| | | //推送成功,修改任务优先级 |
| | | //推送成功,修改任务优先级 |
| | | mst.N_B_STATE = 1; |
| | | mst.S_B_STATE = TN_Task.GetStateStr(1); |
| | | WCSHelper.UpdateStatus(mst);//更新任务状态 |
| | | result = true; |
| | | LogHelper.Info($"NDC推送任务成功 {mst.S_CODE}start= {mst.S_START_LOC} + end = {mst.S_END_LOC}"); |
| | | LogHelper.Info($"NDC推送任务成功:{mst.S_CODE};start='{mst.S_START_LOC}',end='{mst.S_END_LOC}'"); |
| | | } |
| | | else { |
| | | LogHelper.Info($"NDC推送任务失败 {mst.S_CODE};Res:" + JsonConvert.SerializeObject(res)); |
| | | LogHelper.Info($"NDC推送任务失败:{mst.S_CODE};Res:" + JsonConvert.SerializeObject(res)); |
| | | } |
| | | } |
| | | return result; |
| | |
| | | dataType: "json", |
| | | success: function(data) { |
| | | var modelDesc = data.ModelDesc; |
| | | // 在模型展示区域添加描述 |
| | | // 在模型展示区域添加描述 |
| | | $(".model-box").each(function() { |
| | | var modelName = $(this).find(".model-title").text(); |
| | | if (modelDesc[modelName]) { |
| | |
| | | |
| | | /* jshint quotmark: float */ |
| | | window.SwaggerTranslator.learn({ |
| | | "Warning: Deprecated": "警告:已过时", |
| | | "Implementation Notes": "实现备注", |
| | | "Response Class": "响应类", |
| | | "Status": "״̬", |
| | | "Parameters": "参数", |
| | | "Parameter": "参数", |
| | | "Value": "ֵ", |
| | | "Description": "描述", |
| | | "Parameter Type": "参数类型", |
| | | "Data Type": "数据类型", |
| | | "Response Messages": "响应消息", |
| | | "HTTP Status Code": "HTTP 状态码", |
| | | "Reason": "原因", |
| | | "Response Model": "响应模型", |
| | | "Request URL": "请求 URL", |
| | | "Response Body": "响应体", |
| | | "Response Code": "响应码", |
| | | "Response Headers": "响应头", |
| | | "Hide Response": "隐藏响应", |
| | | "Headers": "ͷ", |
| | | "Try it out!": "试一下!", |
| | | "Show/Hide": "显示/隐藏", |
| | | "List Operations": "显示操作", |
| | | "Expand Operations": "展开操作", |
| | | "Raw": "ԭʼ", |
| | | "can't parse JSON. Raw result": "无法解析 JSON。原始结果", |
| | | "Model Schema": "模型架构", |
| | | "Model": "模型", |
| | | "apply": "应用", |
| | | "Username": "用户名", |
| | | "Password": "密码", |
| | | "Terms of service": "服务条款", |
| | | "Created by": "创建者", |
| | | "See more at": "查看更多:", |
| | | "Contact the developer": "联系开发者", |
| | | "api version": "api 版本", |
| | | "Response Content Type": "响应 Content Type", |
| | | "fetching resource": "正在获取资源", |
| | | "fetching resource list": "正在获取资源列表", |
| | | "Explore": "浏览", |
| | | "Show Swagger Petstore Example Apis": "显示 Swagger Petstore 示例 Apis", |
| | | "Can't read from server. It may not have the appropriate access-control-origin settings.": "无法从服务器读取。可能没有正确设置 access-control-origin。", |
| | | "Please specify the protocol for": "请指定协议:", |
| | | "Can't read swagger JSON from": "无法读取 swagger JSON于", |
| | | "Finished Loading Resource Information. Rendering Swagger UI": "已加载资源信息。正在渲染 Swagger UI", |
| | | "Unable to read api": "无法读取 api", |
| | | "from path": "从路径", |
| | | "server returned": "服务器返回" |
| | | "Warning: Deprecated": "警告:已过时", |
| | | "Implementation Notes": "实现备注", |
| | | "Response Class": "响应类", |
| | | "Status": "状态", |
| | | "Parameters": "参数", |
| | | "Parameter": "参数", |
| | | "Value": "值", |
| | | "Description": "描述", |
| | | "Parameter Type": "参数类型", |
| | | "Data Type": "数据类型", |
| | | "Response Messages": "响应消息", |
| | | "HTTP Status Code": "HTTP 状态码", |
| | | "Reason": "原因", |
| | | "Response Model": "响应模型", |
| | | "Request URL": "请求 URL", |
| | | "Response Body": "响应体", |
| | | "Response Code": "响应码", |
| | | "Response Headers": "响应头", |
| | | "Hide Response": "隐藏响应", |
| | | "Headers": "头", |
| | | "Try it out!": "试一下!", |
| | | "Show/Hide": "显示/隐藏", |
| | | "List Operations": "显示操作", |
| | | "Expand Operations": "展开操作", |
| | | "Raw": "原始", |
| | | "can't parse JSON. Raw result": "无法解析 JSON。原始结果", |
| | | "Model Schema": "模型架构", |
| | | "Model": "模型", |
| | | "apply": "应用", |
| | | "Username": "用户名", |
| | | "Password": "密码", |
| | | "Terms of service": "服务条款", |
| | | "Created by": "创建者", |
| | | "See more at": "查看更多:", |
| | | "Contact the developer": "联系开发者", |
| | | "api version": "api 版本", |
| | | "Response Content Type": "响应 Content Type", |
| | | "fetching resource": "正在获取资源", |
| | | "fetching resource list": "正在获取资源列表", |
| | | "Explore": "浏览", |
| | | "Show Swagger Petstore Example Apis": "显示 Swagger Petstore 示例 Apis", |
| | | "Can't read from server. It may not have the appropriate access-control-origin settings.": "无法从服务器读取。可能没有正确设置 access-control-origin。", |
| | | "Please specify the protocol for": "请指定协议:", |
| | | "Can't read swagger JSON from": "无法读取 swagger JSON于", |
| | | "Finished Loading Resource Information. Rendering Swagger UI": "已加载资源信息。正在渲染 Swagger UI", |
| | | "Unable to read api": "无法读取 api", |
| | | "from path": "从路径", |
| | | "server returned": "服务器返回" |
| | | }); |
| | | $(function () |
| | | { |
| | |
| | | public class HttpHelper { |
| | | public string WebPost(string url, string postData, string cotentType = "application/json") |
| | | { |
| | | Console.WriteLine(url); |
| | | LogHelper.Info($"WebPost:访问:{url}", "API"); |
| | | WebRequest request = WebRequest.Create(url); |
| | | request.Method = "POST"; |
| | | //string postData = JsonConvert.SerializeObject(data); ; |
| | |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | LogHelper.Info($"WebPost res={e.Message}", "API"); |
| | | LogHelper.Info($"WebPost:异常:{e.Message}\n\n{e.StackTrace}\n", "API"); |
| | | return ""; |
| | | } |
| | | finally |
| | |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Xml.Linq; |
| | | |
| | | using Newtonsoft.Json; |
| | | |
| | |
| | | } |
| | | |
| | | #region 自定义方法 |
| | | public static void InfoEx(Exception ex) { |
| | | Info($"发生了异常:{ex.Message}\n{ex.StackTrace}"); |
| | | public static void Warn(string msg, string preLog = "") { |
| | | Info(preLog + $"出现了[警告]:{msg}", "Warn"); |
| | | } |
| | | |
| | | public static void InfoEx(Exception ex, string preLog = "") { |
| | | Info(preLog + $"发生了[异常]:{ex.Message}\n\n{ex.StackTrace}\n", "Exception"); |
| | | } |
| | | |
| | | public static void InfoApi(string apiName, object model) { |
| | | Info($"触发API:{apiName} " + JsonConvert.SerializeObject(model), "API"); |
| | | Info($"触发API:{apiName} " + JsonConvert.SerializeObject(model), "API"); |
| | | } |
| | | |
| | | public static void InfoHostToAGV(string taskName, object model) { |
| | | Info($"AGV任务:{taskName}" + JsonConvert.SerializeObject(model), "HosttoagvTask"); |
| | | Info($"AGV任务:{taskName}" + JsonConvert.SerializeObject(model), "HosttoagvTask"); |
| | | } |
| | | #endregion |
| | | } |
| | |
| | | /// 通过配置文件配置日志 |
| | | /// </summary> |
| | | static LogFactory() { |
| | | var loggerNames = new List<string>() { "HosttoagvTask", "HosttoagvCar", "NDC", "杭奥", "PLC", "API", "OPC" }; |
| | | var loggerNames = new List<string>() { "HosttoagvTask", "HosttoagvCar", "NDC", "杭奥", "PLC", "API", "OPC", "Warn", "Exception" }; |
| | | LogManager.Configuration = DefaultConfig(loggerNames); |
| | | } |
| | | |
| | |
| | | namespace HH.WCS.Mobox3.DSZSH.util { |
| | | //https://www.donet5.com/Home/Doc |
| | | public class SqlHelper<T> where T : class, new() { |
| | | // NOTE:如果用Oracle数据库,需要包Oracle.ManagedDataAccess/21.15.0,环境netframework 4.6.2(太新了4.8有的服务器安装不上去) |
| | | // NOTE:如果用Oracle数据库,需要包Oracle.ManagedDataAccess/21.15.0,环境netframework 4.6.2 (太新了4.8有的服务器安装不上去) |
| | | |
| | | public SqlSugarClient GetInstance(string url = "") { |
| | | //创建数据库对象 |
| | |
| | | }); |
| | | }; |
| | | |
| | | //据转换 (ExecuteCommand才会拦截,查询不行) |
| | | //据转换 (ExecuteCommand才会拦截,查询不行) |
| | | //db.Aop.DataExecuting = (value, entity) => { |
| | | // //var val=entity.EntityColumnInfo |
| | | // Console.WriteLine(entity.EntityName); |
| | |
| | | |
| | | namespace HH.WCS.Mobox3.DSZSH.wms { |
| | | /// <summary> |
| | | /// 货位帮助类(包含货位-容器关系的处理) |
| | | /// 货位帮助类 (包含货位-容器关系的处理) |
| | | /// </summary> |
| | | public class LocationHelper |
| | | { |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 取货完解锁起点,卸货完解锁终点,可检验锁的来源,也可以不校验 |
| | | /// 取货完解锁起点,卸货完解锁终点,可检验锁的来源,也可以不校验 |
| | | /// </summary> |
| | | /// <param name="loc"></param> |
| | | /// <returns></returns> |
| | |
| | | public static string UnbindLocCntr(string loc, List<string> cntrs) |
| | | { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var logs = $"货位:{loc},容器:{JsonConvert.SerializeObject(cntrs)}"; |
| | | var logs = $"货位:{loc},容器:{JsonConvert.SerializeObject(cntrs)}"; |
| | | try |
| | | { |
| | | var lcrList = db.Queryable<TN_Loc_Container>().Where(a => cntrs.Contains(a.S_CNTR_CODE) && a.S_LOC_CODE == loc).ToList(); |
| | | if (lcrList.Count == 0) { |
| | | LogHelper.Info($"货位无需解绑容器,在数据库中未找到{JsonConvert.SerializeObject(cntrs)}相关的货位容器关系表信息"); |
| | | LogHelper.Info($"货位无需解绑容器,在数据库中未找到{JsonConvert.SerializeObject(cntrs)}相关的货位容器关系表信息"); |
| | | } |
| | | cntrs = lcrList.Select(a => a.S_CNTR_CODE).ToList(); |
| | | |
| | |
| | | { |
| | | if (db.Deleteable<TN_Loc_Container>().Where(it => cntrs.Contains(it.S_CNTR_CODE) && it.S_LOC_CODE == loc).ExecuteCommand() > 0) |
| | | { |
| | | LogHelper.Info($"删除货位容器关系表成功,{log}"); |
| | | LogHelper.Info($"删除货位容器关系表成功,{log}"); |
| | | } |
| | | else |
| | | { |
| | | tran.RollbackTran(); |
| | | |
| | | LogHelper.Info($"删除货位容器关系表失败,{log}"); |
| | | LogHelper.Info($"删除货位容器关系表失败,{log}"); |
| | | |
| | | return "货位解绑容器失败," + logs; |
| | | return "货位解绑容器失败," + logs; |
| | | } |
| | | |
| | | log = JsonConvert.SerializeObject(location); |
| | | if (db.Updateable(location).UpdateColumns(it => new { it.N_CURRENT_NUM, it.S_LOCK_STATE, it.N_LOCK_STATE }).ExecuteCommand() > 0) { |
| | | tran.CommitTran(); |
| | | |
| | | LogHelper.Info($"更新货位表成功,{log}"); |
| | | LogHelper.Info($"更新货位表成功,{log}"); |
| | | } |
| | | else { |
| | | tran.RollbackTran(); |
| | | |
| | | LogHelper.Info($"更新货位表失败,{log}"); |
| | | LogHelper.Info($"更新货位表失败,{log}"); |
| | | |
| | | return "货位解绑容器失败," + logs; |
| | | return "货位解绑容器失败," + logs; |
| | | } |
| | | } |
| | | } |
| | | else |
| | | { |
| | | LogHelper.Info($"在数据库中未找到该货位,无需更新,货位:{loc}"); |
| | | LogHelper.Info($"在数据库中未找到该货位,无需更新,货位:{loc}"); |
| | | } |
| | | return "货位解绑容器成功," + logs; |
| | | return "货位解绑容器成功," + logs; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | LogHelper.Info($"发生了异常,货位解绑容器失败,{ex.Message}"); |
| | | return "货位绑定容器失败," + logs; |
| | | LogHelper.Info($"发生了异常,货位解绑容器失败,{ex.Message}"); |
| | | return "货位绑定容器失败," + logs; |
| | | } |
| | | } |
| | | |
| | |
| | | public static string BindingLoc(string loc, List<string> cntrs) |
| | | { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | var logs = $"货位:{loc},容器:{JsonConvert.SerializeObject(cntrs)}"; |
| | | var logs = $"货位:{loc},容器:{JsonConvert.SerializeObject(cntrs)}"; |
| | | try |
| | | { |
| | | // 删除已经绑定过的容器记录 |
| | |
| | | var cntr = db.Queryable<TN_Container>().Where(c => c.S_CODE == item).First(); |
| | | |
| | | if (cntr == null) { |
| | | LogHelper.Info($"货位解绑时,容器{item}没有在容器信息表中查到,不记录容器类型"); |
| | | LogHelper.Info($"货位解绑时,容器{item}没有在容器信息表中查到,不记录容器类型"); |
| | | bindLocCntList.Add(new TN_Loc_Container() { S_LOC_CODE = loc, S_CNTR_CODE = item }); |
| | | } |
| | | else { |
| | |
| | | { |
| | | if (db.Insertable(bindLocCntList).ExecuteCommand() <= 0) { |
| | | db.RollbackTran(); |
| | | LogHelper.Info($"插入货位容器关系表失败,{log}"); |
| | | return "货位绑定容器失败," + logs; |
| | | LogHelper.Info($"插入货位容器关系表失败,{log}"); |
| | | return "货位绑定容器失败," + logs; |
| | | } |
| | | LogHelper.Info($"插入货位容器关系表成功,{log}"); |
| | | LogHelper.Info($"插入货位容器关系表成功,{log}"); |
| | | |
| | | var location = db.Queryable<TN_Location>().First(a => a.S_CODE == loc); |
| | | if (location != null) |
| | |
| | | { |
| | | db.CommitTran(); |
| | | |
| | | LogHelper.Info($"更新货位表成功,{log}"); |
| | | LogHelper.Info($"更新货位表成功,{log}"); |
| | | } |
| | | else |
| | | { |
| | | db.RollbackTran(); |
| | | |
| | | LogHelper.Info($"更新货位表失败,{log}"); |
| | | LogHelper.Info($"更新货位表失败,{log}"); |
| | | |
| | | return "货位绑定容器失败," + logs; |
| | | return "货位绑定容器失败," + logs; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | db.RollbackTran(); |
| | | LogHelper.Info($"未找到该货位{loc},或者已锁定,{log}"); |
| | | LogHelper.Info($"未找到该货位{loc},或者已锁定,{log}"); |
| | | } |
| | | } |
| | | return "货位绑定容器成功," + logs; |
| | | return "货位绑定容器成功," + logs; |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | LogHelper.Info($"发生了异常,货位绑定容器失败,"); |
| | | return "货位绑定容器失败," + ex.Message; |
| | | LogHelper.Info($"发生了异常,货位绑定容器失败,"); |
| | | return "货位绑定容器失败," + ex.Message; |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 起点出库锁(强制赋值,不会检查loc!=null,锁状态=无,需要传参前确认) |
| | | /// ![[弃用|理由:不灵活,涉及业务过于具体]]检查容器类型是否正确 |
| | | /// </summary> |
| | | /// <param name="cntrCode"></param> |
| | | /// <param name="cntrType"></param> |
| | | /// <param name="errMsg"></param> |
| | | /// <returns></returns> |
| | | private static bool CheckCntrType(string cntrCode, string cntrType, out string errMsg) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | errMsg = string.Empty; |
| | | |
| | | var cntr = db.Queryable<TN_Container>().Where(c => c.S_CODE == cntrType).First(); |
| | | if (cntr == null) { |
| | | errMsg = $"容器'{cntrCode}'在[容器表]中不存在,请在前台页面中维护!"; |
| | | return false; |
| | | } |
| | | if (cntr.S_TYPE != cntrType) { |
| | | errMsg = $"容器'{cntrCode}'在[容器表]中的类型是'{cntr.S_TYPE},不是'{cntrType}'!"; |
| | | return false; |
| | | } |
| | | |
| | | return true; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 根据容器号,查询当前容器关联的[货位/容器/物料]信息(只查询1条) |
| | | /// </summary> |
| | | /// <param name="cntrCode">容器号</param> |
| | | /// <param name="skipCgDetail">是否跳过[物料表]的查询(当容器号来自[物料表]时)</param> |
| | | /// <returns></returns> |
| | | public static LocCntrCg GetLocCntrCg(string cntrCode, bool skipCgDetail = false) { |
| | | var db = new SqlHelper<object>().GetInstance(); |
| | | |
| | | TN_CG_Detail cgDetail = null; |
| | | if (!skipCgDetail) { |
| | | cgDetail = db.Queryable<TN_CG_Detail>().Where(d => d.S_CNTR_CODE == cntrCode).First(); |
| | | } |
| | | |
| | | var locCntrRel = db.Queryable<TN_Loc_Container>().Where(c => c.S_CNTR_CODE == cntrCode).First(); |
| | | |
| | | TN_Location location = null; |
| | | if (locCntrRel != null) { |
| | | location = db.Queryable<TN_Location>().Where(l => l.S_CODE == locCntrRel.S_LOC_CODE).First(); |
| | | if (location == null) { |
| | | LogHelper.Warn($""); |
| | | } |
| | | } |
| | | if (location != null) { |
| | | location.N_CURRENT_NUM = 0; |
| | | location.T_MODIFY = DateTime.Now; |
| | | } |
| | | |
| | | return new LocCntrCg { |
| | | CgDetail = cgDetail, |
| | | LocCntrRel = locCntrRel, |
| | | Location = location |
| | | }; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 绑定[货位-容器]信息 |
| | | /// </summary> |
| | | /// <param name="startLoc"></param> |
| | | /// <param name="cntrCode"></param> |
| | | /// <returns></returns> |
| | | public static TN_Loc_Container BindLocCntr(ref TN_Location startLoc, string cntrCode) { |
| | | var locCntrRel = new TN_Loc_Container { |
| | | S_LOC_CODE = startLoc.S_CODE, |
| | | S_CNTR_CODE = cntrCode, |
| | | }; |
| | | |
| | | startLoc.N_CURRENT_NUM = 1; |
| | | startLoc.T_MODIFY = DateTime.Now; |
| | | |
| | | return locCntrRel; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 起点出库锁 |
| | | /// </summary> |
| | | /// <param name="loc"></param> |
| | | /// <param name="lockSource"></param> |
| | | public static void LockStartLoc(ref TN_Location loc, string lockSource = "") { |
| | | if (loc == null) { |
| | | throw new ArgumentNullException(); // 接受货位loc为空时直接抛异常(通常不会发生) |
| | | } |
| | | |
| | | if (loc.N_LOCK_STATE != 0 || loc.S_LOCK_STATE != "无") { |
| | | LogHelper.Warn($"起点出库锁:程序正在尝试给当前[锁状态]不是'无'的货位上锁!货位='{loc.S_CODE}',锁状态=({loc.N_LOCK_STATE},{loc.S_LOCK_STATE})"); |
| | | } |
| | | |
| | | loc.N_LOCK_STATE = 2; // 起点出库锁 |
| | | loc.S_LOCK_STATE = TN_Location.GetLockStateStr(2); // 起点出库锁 |
| | | loc.S_LOCK_OP = lockSource; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 终点入库锁(强制赋值,不会检查loc!=null,锁状态=无,需要传参前确认) |
| | | /// 终点入库锁 |
| | | /// </summary> |
| | | /// <param name="loc"></param> |
| | | /// <param name="lockSource"></param> |
| | | public static void LockEndLoc(ref TN_Location loc, string lockSource = "") { |
| | | if (loc == null) { |
| | | throw new ArgumentNullException(); // 接受货位loc为空时直接抛异常(通常不会发生) |
| | | } |
| | | |
| | | if (loc.N_LOCK_STATE != 0 || loc.S_LOCK_STATE != "无") { |
| | | LogHelper.Warn($"起点出库锁:程序正在尝试给当前[锁状态]不是'无'的货位上锁!货位='{loc.S_CODE}',锁状态=({loc.N_LOCK_STATE},{loc.S_LOCK_STATE})"); |
| | | } |
| | | |
| | | loc.N_LOCK_STATE = 1; // 终点出库锁 |
| | | loc.S_LOCK_STATE = TN_Location.GetLockStateStr(1); // 终点出库锁 |
| | | loc.S_LOCK_OP = lockSource; |
| | | loc.T_MODIFY = System.DateTime.Now; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 创建任务 |
| | | /// </summary> |
| | | /// <param name="startLoc">起点货位:至少提供:S_CODE,S_AREA_CODE</param> |
| | | /// <param name="endLoc">终点货位:至少提供:S_CODE,S_AREA_CODE</param> |
| | | /// <param name="cntId">容器号</param> |
| | | /// <param name="type">任务类型(名称)</param> |
| | | /// <param name="pri">优先级</param> |
| | | /// <param name="agvType">AGV类型</param> |
| | | /// <returns></returns> |
| | | public static TN_Task BuildTask(TN_Location startLoc, TN_Location endLoc, string cntId, string type, int pri = 3, int agvType = 1) { |
| | | TN_Task TN_Task = new TN_Task() { |
| | | S_CODE = GenerateTaskNo(), |
| | |
| | | S_TYPE = type, |
| | | N_PRIORITY = pri, |
| | | N_SCHEDULE_TYPE = agvType, |
| | | N_B_STATE = 0, // 任务创建时,默认等待 |
| | | N_B_STATE = 0, // 任务创建时,默认等待 |
| | | S_CNTR_CODE = cntId, |
| | | }; |
| | | |
| | | return TN_Task; |
| | | } |
| | | |
| | | |
| | | internal static bool CheckActionRecordExist(string no, int code) { |
| | | var db = new SqlHelper<TN_Task_Action>().GetInstance(); |
| | |
| | | internal static void Fail(TN_Task task) { |
| | | var db = new SqlHelper<TN_Task>().GetInstance(); |
| | | if (task != null) { |
| | | //判断有没有取货完成,没有就变成失败。有取货完成默认完成了(跟据项目而定,有些项目人工拉走了也没有放到终点)。 |
| | | //判断有没有取货完成,没有就变成失败。有取货完成默认完成了 (跟据项目而定,有些项目人工拉走了也没有放到终点) 。 |
| | | task.N_B_STATE = 4; |
| | | task.S_B_STATE = TN_Task.GetStateStr(task.N_B_STATE); |
| | | db.Updateable(task).UpdateColumns(it => new { it.N_B_STATE, it.S_B_STATE }).ExecuteCommand(); |
| | |
| | | return db.Queryable<TN_Task>().Where(a => a.N_B_STATE == 0 && (a.S_B_STATE == "等待" || a.S_B_STATE == "待推送")).ToList(); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// [货位/容器/物料]信息 |
| | | /// </summary> |
| | | public class LocCntrCg { |
| | | public TN_CG_Detail CgDetail { get; set; } = null; |
| | | public TN_Loc_Container LocCntrRel { get; set; } = null; |
| | | public TN_Location Location { get; set; } = null; |
| | | } |
| | | } |