kazelee
15 小时以前 fc6dd85a865c4cadae0b9a07d56e2988d2262f10
优化数据库事务帮助类 , 查询/日志生成类
2个文件已添加
7个文件已修改
725 ■■■■ 已修改文件
HH.WCS.Mobox3.DSZSH.csproj 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
api/ApiHelper.cs 315 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
api/DebugController.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
core/WCSCore.cs 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
models/TN_Task.cs 45 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
wms/DbTranHelper.cs 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
wms/LogBuilder.cs 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
wms/QueryHelper.cs 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
wms/WCSHelper.cs 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3.DSZSH.csproj
@@ -273,6 +273,8 @@
    <Compile Include="util\WebHelper.cs" />
    <Compile Include="wms\DbTranHelper.cs" />
    <Compile Include="wms\LocationHelper.cs" />
    <Compile Include="wms\LogBuilder.cs" />
    <Compile Include="wms\QueryHelper.cs" />
    <Compile Include="wms\SYSHelper.cs" />
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
api/ApiHelper.cs
@@ -26,6 +26,7 @@
        /// <returns></returns>
        public static SimpleResult GoodpackOffline(GoodpackOfflineInfo model) {
            var db = new SqlHelper<object>().GetInstance();
            var taskInfo = ETask.M满箱下线入库.Info();
            const string preLog = "API:满箱下线入库:";
            const string cntrType = "好运箱";
@@ -43,7 +44,7 @@
                }
                // 查询起点货位:数量=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();
                var startLoc = QueryHelper.GetLoc(db, 0, model.StartLoc, taskInfo.StartAreas, 0).First();
                if (startLoc == null) {
                    return NewSimpleResult(2, preLog + $"没有找到起点货位'{model.StartLoc}'!要求:锁状态='无',当前容器数量=0,所在库区={LogObject(taskInfo.StartAreas)}");
                }
@@ -52,7 +53,7 @@
                var old = WCSHelper.GetLocCntrCg(cgDetail.S_CNTR_CODE, skipCgDetail: true);
                // 绑定货位容器,起点货位当前数量=1
                var locCntrRel = WCSHelper.BindLocCntr(ref startLoc, cgDetail.S_CNTR_CODE);
                var locCntrRel = WCSHelper.BindLocCntr(startLoc, cgDetail.S_CNTR_CODE);
                locCntrRel.S_CNTR_TYPE = cntrType;
                // 查询终点货位
@@ -62,44 +63,16 @@
                    return NewSimpleResult(3, preLog + $"没有找到合适的终点货位!要求:锁状态='无',当前容器数量=0,所在库区={LogObject(taskInfo.EndAreas)}");
                }
                // 更新[起点/终点]锁状态,创建任务
                var task = WCSHelper.BuildTaskWithLocLock(startLoc, endLoc, locCntrRel.S_CNTR_CODE, taskInfo.TaskName);
                using (var tran = db.Ado.UseTran()) {
                    // 删除/更新旧[货位/容器/物料]信息
                    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)}");
                    }
                    // 更新[起点/终点]锁状态,创建任务
                    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}',锁状态=>'出库锁'");
                    }
                    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}',锁状态=>'入库锁'");
                    }
                    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}");
                    }
                    // 提交数据库更改
                    tran.CommitTran();
                    return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}");
                }
                var (ok, msg) = DbTranHelper.CreateTask(new CreateTaskObj {
                    Old = old,
                    New = new LocCntrCg { LocCntrRel = locCntrRel },
                    StartLocToUpdate = startLoc,
                    EndLocToUpdate = endLoc,
                    TaskToInsert = task,
                });
                return NewSimpleResult(ok ? 0 : 500, preLog + msg);
            }
            catch (Exception ex) {
                return NewSimpleResult(ex, preLog);
@@ -113,6 +86,7 @@
        /// <returns></returns>
        public static SimpleResult EmptyInboundPallet(EmptyInboundInfo model) {
            var db = new SqlHelper<object>().GetInstance();
            var taskInfo = ETask.K空托入库.Info();
            const string preLog = "API:空托入库:";
            const string cntrType = "托盘";
@@ -137,7 +111,7 @@
                var old = WCSHelper.GetLocCntrCg(model.CntrCode);
                // 绑定货位容器,起点货位当前数量=1
                var locCntrRel = WCSHelper.BindLocCntr(ref startLoc, cntr.S_CODE);
                var locCntrRel = WCSHelper.BindLocCntr(startLoc, cntr.S_CODE);
                locCntrRel.S_CNTR_TYPE = cntrType;
                // 查询终点货位
@@ -150,45 +124,14 @@
                // 起点终点上锁,创建任务
                var task = WCSHelper.BuildTaskWithLocLock(startLoc, endLoc, locCntrRel.S_CNTR_CODE, taskInfo.TaskName);
                using (var tran = db.Ado.UseTran()) {
                    if (old.CgDetail != null && db.Deleteable(old.CgDetail).ExecuteCommand() <= 0) {
                        tran.RollbackTran();
                        return NewSimpleResult(500, preLog + $"删除[旧物料信息]失败!数据:{LogObject(old.CgDetail)}");
                    }
                    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)}");
                    }
                    // 更新[起点/终点]锁状态,创建任务
                    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}',锁状态=>'出库锁'");
                    }
                    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}',锁状态=>'入库锁'");
                    }
                    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}");
                    }
                    // 提交数据库更改
                    tran.CommitTran();
                    return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}");
                }
                var (ok, msg) = DbTranHelper.CreateTask(new CreateTaskObj {
                    Old = old,
                    New = new LocCntrCg { LocCntrRel = locCntrRel },
                    StartLocToUpdate = startLoc,
                    EndLocToUpdate = endLoc,
                    TaskToInsert = task,
                });
                return NewSimpleResult(ok ? 0 : 500, preLog + msg);
            }
            catch (Exception ex) {
                return NewSimpleResult(ex, preLog);
@@ -201,6 +144,7 @@
        /// <returns></returns>
        public static SimpleResult EmptyInboundGoodpack(EmptyInboundInfo model) {
            var db = new SqlHelper<object>().GetInstance();
            var taskInfo = ETask.K空箱入库.Info();
            const string preLog = "API:空箱入库:";
            const string cntrType = "好运箱";
@@ -225,7 +169,7 @@
                var old = WCSHelper.GetLocCntrCg(model.CntrCode);
                // 绑定货位容器,起点货位当前数量=1
                var locCntrRel = WCSHelper.BindLocCntr(ref startLoc, model.CntrCode);
                var locCntrRel = WCSHelper.BindLocCntr(startLoc, model.CntrCode);
                locCntrRel.S_CNTR_TYPE = cntrType;
                // 查询终点货位
@@ -237,43 +181,14 @@
                var task = WCSHelper.BuildTaskWithLocLock(startLoc, endLoc, locCntrRel.S_CNTR_CODE, taskInfo.TaskName);
                using (var tran = db.Ado.UseTran()) {
                    if (old.CgDetail != null && db.Deleteable(old.CgDetail).ExecuteCommand() <= 0) {
                        tran.RollbackTran();
                        return NewSimpleResult(500, preLog + $"删除[旧物料信息]失败!数据:{LogObject(old.CgDetail)}");
                    }
                    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));
                    }
                    // 更新[起点/终点]锁状态,创建任务
                    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}',锁状态=>'出库锁'");
                    }
                    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}',锁状态=>'入库锁'");
                    }
                    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}");
                    }
                    // 提交数据库更改
                    tran.CommitTran();
                    return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}");
                }
                var (ok, msg) = DbTranHelper.CreateTask(new CreateTaskObj {
                    Old = old,
                    New = new LocCntrCg { LocCntrRel = locCntrRel },
                    StartLocToUpdate = startLoc,
                    EndLocToUpdate = endLoc,
                    TaskToInsert = task,
                });
                return NewSimpleResult(ok ? 0 : 500, preLog + msg);
            }
            catch (Exception ex) {
                return NewSimpleResult(ex, preLog);
@@ -287,6 +202,7 @@
        /// <returns></returns>
        public static SimpleResult EmptyOnlinePallet(EmptyOnlinePalletInfo model) {
            var db = new SqlHelper<object>().GetInstance();
            var taskInfo = ETask.K空托上线出库.Info();
            const string preLog = "API:空托上线出库:";
            const string cntrType = "托盘";
@@ -327,32 +243,21 @@
                var task = WCSHelper.BuildTaskWithLocLock(startLoc, endLoc, model.CntId, taskInfo.TaskName);
                cntr.S_SOURCE = task.S_CODE; // 用任务号作为容器更新的依据
                cntr.T_MODIFY = DateTime.Now;
                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)}");
                    }
                    // 更新[起点/终点]锁状态,创建任务
                    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}',锁状态=>'出库锁'");
                    }
                    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}',锁状态=>'入库锁'");
                    }
                    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}");
                    }
                    // 提交数据库更改
                    tran.CommitTran();
                    return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}");
                if (needUpdateContainer) {
                    cntr.S_SOURCE = task.S_CODE; // 用任务号作为容器更新的依据
                    cntr.T_MODIFY = DateTime.Now;
                }
                else {
                    cntr = null;
                }
                var (ok, msg) = DbTranHelper.CreateTask(new CreateTaskObj {
                    ContainerToUpdate = cntr,
                    StartLocToUpdate = startLoc,
                    EndLocToUpdate = endLoc,
                    TaskToInsert = task,
                });
                return NewSimpleResult(ok ? 0 : 500, preLog + msg);
            }
            catch (Exception ex) {
                return NewSimpleResult(ex, preLog);
@@ -366,6 +271,7 @@
        /// <returns></returns>
        public static SimpleResult EmptyOnlineGoodpack(EmptyOnlineGoodpackInfo model) {
            var db = new SqlHelper<object>().GetInstance();
            var taskInfo = ETask.K空箱上线出库.Info();
            const string preLog = "API:空箱上线出库:";
            const string cntrType = "好运箱";
@@ -392,25 +298,12 @@
                var task = WCSHelper.BuildTaskWithLocLock(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}',锁状态=>'出库锁'");
                    }
                    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}',锁状态=>'入库锁'");
                    }
                    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}");
                    }
                    // 提交数据库更改
                    tran.CommitTran();
                    return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}");
                }
                var (ok, msg) = DbTranHelper.CreateTask(new CreateTaskObj {
                    StartLocToUpdate = startLoc,
                    EndLocToUpdate = endLoc,
                    TaskToInsert = task,
                });
                return NewSimpleResult(ok ? 0 : 500, preLog + msg);
            }
            catch (Exception ex) {
                return NewSimpleResult(ex, preLog);
@@ -424,6 +317,7 @@
        /// <returns></returns>
        public static SimpleResult QualifiedBack(QualifiedBackInfo model) {
            var db = new SqlHelper<object>().GetInstance();
            var taskInfo = ETask.C抽检合格回库.Info();
            const string preLog = "API:抽检合格回库";
@@ -457,30 +351,13 @@
                var cntId = locCntrRel.S_CNTR_CODE;
                var task = WCSHelper.BuildTaskWithLocLock(startLoc, endLoc, cntId, taskInfo.TaskName);
                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}',物料状态=>'合格'");
                    }
                    // 更新[起点/终点]锁状态,创建任务
                    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}',锁状态=>'出库锁'");
                    }
                    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}',锁状态=>'入库锁'");
                    }
                    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}");
                    }
                    // 提交数据库更改
                    tran.CommitTran();
                    return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}");
                }
                var (ok, msg) = DbTranHelper.CreateTask(new CreateTaskObj {
                    CgDetailToUpdate = cgDetail,
                    StartLocToUpdate = startLoc,
                    EndLocToUpdate = endLoc,
                    TaskToInsert = task,
                });
                return NewSimpleResult(ok ? 0 : 500, preLog + msg);
            }
            catch (Exception ex) {
                return NewSimpleResult(ex, preLog);
@@ -494,6 +371,7 @@
        /// <returns></returns>
        public static SimpleResult UnqualifiedShift(UnqualifiedShiftInfo model) {
            var db = new SqlHelper<object>().GetInstance();
            var taskInfo = ETask.C抽检不合格移库.Info();
            const string preLog = "API:抽检不合格移库:";
@@ -529,30 +407,13 @@
                var task = WCSHelper.BuildTaskWithLocLock(startLoc, endLoc, locCntrRel.S_CNTR_CODE, taskInfo.TaskName);
                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}'");
                    }
                    // 更新[起点/终点]锁状态,创建任务
                    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}',锁状态=>'出库锁'");
                    }
                    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}',锁状态=>'入库锁'");
                    }
                    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}");
                    }
                    // 提交数据库更改
                    tran.CommitTran();
                    return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}");
                }
                var (ok, msg) = DbTranHelper.CreateTask(new CreateTaskObj {
                    CgDetailToUpdate = cgDetail,
                    StartLocToUpdate = startLoc,
                    EndLocToUpdate = endLoc,
                    TaskToInsert = task,
                });
                return NewSimpleResult(ok ? 0 : 500, preLog + msg);
            }
            catch (Exception ex) {
                return NewSimpleResult(ex, preLog);
@@ -566,6 +427,7 @@
        /// <returns></returns>
        public static SimpleResult RestBack(RestBackInfo model) {
            var db = new SqlHelper<object>().GetInstance();
            var taskInfo = ETask.W尾料回库.Info();
            const string preLog = "API:尾料回库:";
            
@@ -586,34 +448,14 @@
                    return NewSimpleResult(3, preLog + $"没有找到合适的终点货位!要求:锁状态='无',当前容器数量=0,所在库区={LogObject(endAreas)}");
                }
                var cntId = locCntrRel.S_CNTR_CODE;
                var task = WCSHelper.BuildTaskWithLocLock(startLoc, endLoc, locCntrRel.S_CNTR_CODE, taskInfo.TaskName);
                var task = WCSHelper.BuildTaskWithLocLock(startLoc, endLoc, cntId, taskInfo.TaskName);
                using (var tran = db.Ado.UseTran()) {
                    //if (db.Insertable(locCntrRel).ExecuteCommand() <= 0) {
                    //    tran.RollbackTran();
                    //    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}',锁状态=>'出库锁'");
                    }
                    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}',锁状态=>'入库锁'");
                    }
                    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}");
                    }
                    // 提交数据库更改
                    tran.CommitTran();
                    return NewSimpleResult(0, preLog + $"生成任务'{task.S_TYPE}'成功!任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}");
                }
                var (ok, msg) = DbTranHelper.CreateTask(new CreateTaskObj {
                    StartLocToUpdate = startLoc,
                    EndLocToUpdate = endLoc,
                    TaskToInsert = task,
                });
                return NewSimpleResult(ok ? 0 : 500, preLog + msg);
            }
            catch (Exception ex) {
                return NewSimpleResult(ex, preLog);
@@ -627,6 +469,7 @@
        /// <returns></returns>
        public static SimpleResult FinishedOutbound(FinishedOutboundInfo model) {
            var db = new SqlHelper<object>().GetInstance();
            var taskInfo = ETask.C成品胶出库.Info();
            const string preLog = "API:成品胶出库:";
@@ -687,6 +530,8 @@
        /// <returns></returns>
        public static SimpleResult FinishedOutboundForce(FinishedOutboundInfo model) {
            var db = new SqlHelper<object>().GetInstance();
            var (ok, msg) = (false, string.Empty);
            var taskInfo = ETask.C成品胶出库.Info();
            const string preLog = "API:成品胶出库:";
api/DebugController.cs
@@ -96,7 +96,7 @@
        [HttpPost]
        [Route("AddInboundTask")]
        public string AddInboundTask(AddInboundTaskInfo model) {
            return WCSCore.CreateInboundTask(model.StartLoc, model.CntrCode).Content;
            return WCSCore.CreateInboundTask(model.StartLoc, model.CntrCode).Item2;
        }
        /// <summary>
core/WCSCore.cs
@@ -445,6 +445,8 @@
        public static void HandleClientRequest(System.Net.Sockets.TcpClient client) {
            var db = new SqlHelper<object>().GetInstance();
            var (ok, msg) = (false, string.Empty);
            using (client)
            using (NetworkStream stream = client.GetStream()) {
                try {
@@ -466,10 +468,11 @@
                    // B. 如果是每条产线各一个客户端,更简单,直接根据IP地址确定终点货位
                    // TODO 具体逻辑待后续确定时补完
                    var success = CreateInboundTask(startLocCode, message.CntrCode).Value;
                    (ok, msg) = CreateInboundTask(startLocCode, message.CntrCode);
                    LogHelper.Info(msg);
                    // 发送响应
                    string response = success ? "ACK: 机器人已调度" : "NAK: 调度失败";
                    string response = ok ? "ACK: 机器人已调度" : "NAK: 调度失败";
                    byte[] responseData = Encoding.UTF8.GetBytes(response);
                    stream.Write(responseData, 0, responseData.Length);
                }
@@ -485,7 +488,7 @@
        /// <param name="startLocCode"></param>
        /// <param name="cntrCode"></param>
        /// <returns></returns>
        public static Result<bool> CreateInboundTask(string startLocCode, string cntrCode) {
        public static (bool, string) CreateInboundTask(string startLocCode, string cntrCode) {
            var db = new SqlHelper<object>().GetInstance();
            var taskInfo = Settings.GetTaskInfo(ETask.M满托下线入库);
@@ -501,9 +504,9 @@
                .Where(l => l.N_LOCK_STATE == 0 && l.S_LOCK_STATE == "无" && l.C_ENABLE == "Y")
                //.Where(l => l.N_CURRENT_NUM == 0) // 绑定前
                .First();
                if (startLoc == null) {
                    return NewResult(false, $"没有找到起点货位'{startLocCode}',或不满足要求:未上锁,当前容器数量=0");
                    return (false, $"没有找到起点货位'{startLocCode}'!!要求:未上锁,当前容器数量=0");
                }
                var locCntrRelOld = db.Queryable<TN_Loc_Container>()
@@ -524,58 +527,50 @@
                    .Where(a => a.N_CURRENT_NUM == 0) // 筛选:空货位
                    .OrderBy(l => l.N_LAYER)
                    .First();
                if (endLoc == null) {
                    return NewResult(false, $"没有找到合适的【终点货位】,需要满足要求:未上锁,当前容器数量=0");
                    return (false, $"没有找到合适的[终点货位]!!要求:未上锁,当前容器数量=0");
                }
                var cntId = locCntrRel.S_CNTR_CODE;
                var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName);
                WCSHelper.LockStartLoc(startLoc); // 起点出库锁
                WCSHelper.LockEndLoc(endLoc); // 终点入库锁
                var task = WCSHelper.BuildTaskWithLocLock(startLoc, endLoc, cntId, 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 NewResult(false, $"删除旧货位容器关系表失败:货位编码{locCntrRelOld.S_LOC_CODE},容器编码{locCntrRelOld.S_CNTR_CODE}");
                            return (false, $"删除旧货位容器关系表失败:货位编码{locCntrRelOld.S_LOC_CODE},容器编码{locCntrRelOld.S_CNTR_CODE}");
                        }
                    }
                    if (db.Insertable(locCntrRel).ExecuteCommand() <= 0) {
                        tran.RollbackTran();
                        return NewResult(false, $"插入货位容器关系表失败:货位编码{locCntrRel.S_LOC_CODE},容器编码{locCntrRel.S_CNTR_CODE}");
                        return (false, $"插入货位容器关系表失败:货位编码{locCntrRel.S_LOC_CODE},容器编码{locCntrRel.S_CNTR_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 NewResult(false, $"生成任务'{taskName}'失败:更新起点货位{startLoc.S_CODE}锁状态失败");
                        return (false, $"生成任务'{taskName}'失败:更新起点货位{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 NewResult(false, $"生成任务'{taskName}'失败:更新终点货位{endLoc.S_CODE}锁状态失败");
                        return (false, $"生成任务'{taskName}'失败:更新终点货位{endLoc.S_CODE}锁状态失败");
                    }
                    if (db.Insertable(task).ExecuteCommand() <= 0) {
                        tran.RollbackTran();
                        return NewResult(false, $"生成任务'{taskName}'失败,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}");
                        return (false, $"生成任务'{taskName}'失败,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}");
                    }
                    tran.CommitTran();
                    return NewResult(true, $"生成任务'{taskName}'成功,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}");
                    return (true, $"生成任务'{taskName}'成功,任务号={task.S_CODE},容器号={cntId},起点={startLoc.S_CODE},终点={endLoc.S_CODE}");
                }
            }
            catch (Exception ex) {
                return NewResult(false, ex.Message);
                return (false, ex.Message);
            }
        }
        private static Result<bool> NewResult(bool res, string msg, bool log = true) {
            if (log) { LogHelper.Info(msg); }
            return new Result<bool>(res, msg);
        }
    }
@@ -585,15 +580,5 @@
        //public string ItemCode { get; set; }
        //public string BatchNo { get; set; }
        public string CntrCode { get; set; }
    }
    public class Result<T> {
        public T Value { get; set; }
        public string Content { get; set; }
        public Result(T value, string content) {
            Value = value;
            Content = content;
        }
    }
}
models/TN_Task.cs
@@ -3,51 +3,16 @@
using SqlSugar;
namespace HH.WCS.Mobox3.DSZSH.models {
    /// <summary>
    /// 【框架】任务表
    /// </summary>
    [SugarTable("TN_Task")]
    public class TN_Task : BaseModel {
        /// <summary>
        /// 任务号
        /// </summary>
        public string S_CODE { get; set; }
        /// <summary>
        /// 任务类型/名称
        /// </summary>
        public string S_TYPE { get; set; }
        /// <summary>
        /// 起始货区
        /// </summary>
        public string S_START_AREA { get; set; }
        /// <summary>
        /// 终点货区
        /// </summary>
        public string S_END_AREA { get; set; }
        /// <summary>
        /// 起始货位
        /// </summary>
        public string S_START_LOC { get; set; }
        /// <summary>
        /// 终点货位
        /// </summary>
        public string S_END_LOC { get; set; }
        /// <summary>
        /// 开始时间
        /// </summary>
        public DateTime? T_START_TIME { get; set; }
        /// <summary>
        /// 完成时间
        /// </summary>
        [SugarColumn(IsNullable = true)]
        public DateTime? T_END_TIME { get; set; }
        public DateTime T_START_TIME { get; set; }
        public DateTime T_END_TIME { get; set; }
        /// <summary>
        /// AGV 车号  
@@ -55,14 +20,14 @@
        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 int N_B_STATE { get; set; } = 0;
   
        /// <summary>
        /// 0无 1NDC 2天目 3国自 4PLC 5杭奥
wms/DbTranHelper.cs
@@ -19,59 +19,75 @@
        /// <summary>
        /// 数据库事务处理 ( 创建任务 )
        /// </summary>
        /// <remarks>要求: obj != null</remarks>
        /// <remarks><b>[ 要求 ]</b> obj ≠ null<br/>
        /// <b>[ 注意 ]</b> 所有的数据库操作 , 都会在对象 = null 时选择跳过 , 且不会报错 , 除了 TaskToInsert ;
        /// <br/>如果存在某个必须完成的数据库操作 , 需在调用时确保该对象 ≠ null</remarks>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static (bool Success, string Message) DoDbTranTask(DbTranTaskObj obj) {
        public static (bool, string) CreateTask(CreateTaskObj obj) {
            var db = new SqlHelper<object>().GetInstance();
            try {
                using (var tran = db.Ado.UseTran()) {
                    // 存在[旧]容器关联信息:删除[旧][容器货品明细][货位容器关系],更新[货位][容器数量]
                    // 更新[容器表](业务需要)
                    if (obj.ContainerToUpdate != null && db.Updateable(obj.ContainerToUpdate).UpdateColumns(c => new { c.S_SPEC, c.S_SOURCE, c.T_MODIFY }).ExecuteCommand() <= 0) {
                        return (false, $"更新[容器][规格(物料编码)]失败!!数据:\n\n{JsonConvert.SerializeObject(obj.ContainerToUpdate)}\n");
                    }
                    // 更新[容器货品明细](业务需要)
                    if (obj.CgDetailToUpdate != null && db.Updateable(obj.CgDetailToUpdate).UpdateColumns(it => new { it.N_ITEM_STATE, it.S_ITEM_STATE, it.T_MODIFY }).ExecuteCommand() <= 0) {
                        tran.RollbackTran();
                        return (false, $"更新[容器货品明细][物料状态]失败!!物料号='{obj.CgDetailToUpdate}',物料状态=>'{obj.CgDetailToUpdate.S_ITEM_STATE}'");
                    }
                    #region 删除[旧]容器绑定信息
                    if (obj.Old != null) {
                        if (obj.Old.CgDetail != null && db.Deleteable(obj.Old.CgDetail).ExecuteCommand() <= 0) {
                            tran.RollbackTran();
                            return (false, $"删除[旧物料信息]失败!!数据:\n\n{JsonConvert.SerializeObject(obj.Old.CgDetail)}\n");
                            return (false, $"删除[旧容器货品明细]失败!!数据:\n\n{JsonConvert.SerializeObject(obj.Old.CgDetail)}\n");
                        }
                        if (obj.Old.LocCntrRel != null && db.Deleteable(obj.Old.LocCntrRel).ExecuteCommand() <= 0) {
                            tran.RollbackTran();
                            return (false, $"删除[旧货位容器关系]失败!!数据:\n\n{JsonConvert.SerializeObject(obj.Old.LocCntrRel)}\n");
                            return (false, $"删除[旧货位容器绑定]失败!!数据:\n\n{JsonConvert.SerializeObject(obj.Old.LocCntrRel)}\n");
                        }
                        if (obj.Old.Location != null && db.Updateable(obj.Old.Location).UpdateColumns(l => new { l.N_CURRENT_NUM, l.T_MODIFY }).ExecuteCommand() <= 0) {
                            tran.RollbackTran();
                            return (false, $"更新[旧货位][当前容器数量]失败!!货位='{obj.Old.Location.S_CODE}',数量=>{obj.Old.Location.N_CURRENT_NUM}");
                        }
                    }
                    #endregion
                    // 更新[容器表](业务需要)
                    if (obj.ContainerToUpdate != null && db.Updateable(obj.ContainerToUpdate).UpdateColumns(c => new { c.S_SPEC, c.S_SOURCE, c.T_MODIFY }).ExecuteCommand() <= 0) {
                        return (false, $"更新[容器表]失败!!数据:\n\n{JsonConvert.SerializeObject(obj.ContainerToUpdate)}\n");
                    #region 添加[新]容器绑定信息
                    if (obj.New != null) {
                        if (obj.New.CgDetail != null && db.Insertable(obj.New.CgDetail).ExecuteCommand() <= 0) {
                            tran.RollbackTran();
                            return (false, $"插入[新容器货品明细]失败!!数据:\n\n{JsonConvert.SerializeObject(obj.New.CgDetail)}\n");
                        }
                        if (obj.New.LocCntrRel != null && db.Insertable(obj.New.LocCntrRel).ExecuteCommand() <= 0) {
                            tran.RollbackTran();
                            return (false, $"插入[旧货位容器绑定]失败!!数据:\n\n{JsonConvert.SerializeObject(obj.New.LocCntrRel)}\n");
                        }
                        // 新货位信息通常就是 StartLoc , 在 StartLocToUpdate 中处理即可
                    }
                    #endregion
                    // 更新[容器货品明细](业务需要)
                    if (obj.CgDetailToUpdate != null && db.Updateable(obj.CgDetailToUpdate).UpdateColumns(it => new { it.N_ITEM_STATE, it.S_ITEM_STATE, it.T_MODIFY }).ExecuteCommand() <= 0) {
                        tran.RollbackTran();
                        return (false, $"更新[物料明细表]失败!!物料号='{obj.CgDetailToUpdate}',物料状态=>'{obj.CgDetailToUpdate.S_ITEM_STATE}'");
                    }
                    // 存在[新][货位容器绑定关系]:插入[货位容器关系表]
                    if (obj.LocCntrRelToInsert != null && db.Insertable(obj.LocCntrRelToInsert).ExecuteCommand() <= 0) {
                        tran.RollbackTran();
                        return (false, $"插入[容器货位绑定表]失败!!数据:\n\n{JsonConvert.SerializeObject(obj.LocCntrRelToInsert)}\n");
                    }
                    // 更新[起点][终点][锁状态],创建[任务]
                    #region 创建任务 + 货位锁
                    if (obj.StartLocToUpdate != null && db.Updateable(obj.StartLocToUpdate).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 (false, $"更新[起点货位锁状态]失败!!起点='{obj.StartLocToUpdate.S_CODE}',锁状态=>'{obj.StartLocToUpdate.S_LOCK_STATE}'");
                        return (false, $"更新[起点货位][锁状态]失败!!起点='{obj.StartLocToUpdate.S_CODE}',锁状态=>'{obj.StartLocToUpdate.S_LOCK_STATE}'");
                    }
                    if (obj.EndLocToUpdate != null && db.Updateable(obj.EndLocToUpdate).UpdateColumns(it => new { it.N_LOCK_STATE, it.S_LOCK_STATE, it.S_LOCK_OP, it.T_MODIFY, }).ExecuteCommand() <= 0) {
                        tran.RollbackTran();
                        return (false, $"更新[终点货位锁状态]失败!!终点='{obj.EndLocToUpdate.S_CODE}',锁状态=>'{obj.EndLocToUpdate.S_LOCK_STATE}'");
                        return (false, $"更新[终点货位][锁状态]失败!!终点='{obj.EndLocToUpdate.S_CODE}',锁状态=>'{obj.EndLocToUpdate.S_LOCK_STATE}'");
                    }
                    if (obj.TaskToInsert != null && db.Insertable(obj.TaskToInsert).ExecuteCommand() <= 0) {
                    if (obj.TaskToInsert == null) {
                        tran.RollbackTran();
                        throw new ArgumentException("数据库事务处理:待插入的[任务]为空!!"); // 待插入的任务不存在,直接抛出异常
                    }
                    if (db.Insertable(obj.TaskToInsert).ExecuteCommand() <= 0) {
                        tran.RollbackTran();
                        return (false, $"生成任务'{obj.TaskToInsert.S_TYPE}'失败!!任务号='{obj.TaskToInsert.S_CODE}',容器号='{obj.TaskToInsert.S_CNTR_CODE}',起点='{obj.TaskToInsert.S_START_LOC}',终点='{obj.TaskToInsert.S_END_LOC}'");
                    }
                    #endregion
                    // 提交数据库更改
                    tran.CommitTran();
@@ -84,14 +100,27 @@
        }
    }
    public class DbTranTaskObj {
        public LocCntrCg Old { get; set; } = null;
        public TN_Container ContainerToUpdate { get; set; } = null;
        public TN_CG_Detail CgDetailToUpdate { get; set; } = null;
        public TN_Loc_Container LocCntrRelToInsert { get; set; } = null;
    public class CreateTaskObj {
        #region 起点货位 / 终点货位 / 任务
        public TN_Location StartLocToUpdate { get; set; } = null;
        public TN_Location EndLocToUpdate { get; set; } = null;
        public TN_Task TaskToInsert { get; set; } = null;
        #endregion
        #region 容器绑定信息 ( 旧 / 新 )
        /// <summary>
        /// [ 旧 ] 容器绑定信息 ( 货位 / 货位容器 / 容器货品 )
        /// </summary>
        public LocCntrCg Old { get; set; } = null;
        /// <summary>
        /// [ 新 ] 容器绑定信息 ( 货位 / 货位容器 / 容器货品 )
        /// </summary>
        public LocCntrCg New { get; set; } = null;
        #endregion
        public TN_Container ContainerToUpdate { get; set; } = null;
        public TN_CG_Detail CgDetailToUpdate { get; set; } = null;
    }
}
wms/LogBuilder.cs
New file
@@ -0,0 +1,119 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HH.WCS.Mobox3.DSZSH.models;
using Newtonsoft.Json;
namespace HH.WCS.Mobox3.DSZSH.util {
    /// <summary>
    /// 打印日志内容构造器
    /// </summary>
    public static class LogBuilder {
        /// <summary>
        /// 没有找到起点货位
        /// </summary>
        /// <remarks>
        /// <b>lockState</b> - 锁状态,默认为0,小于0时忽略<br/>
        /// <b>curNum</b> - 当前数量,默认为-1,小于0时忽略<br/>
        /// <b>areas</b> - 所在库区列表,默认为null,为null或为空时忽略<br/>
        /// <b>name</b> - 货位名称,默认为null,为null或为空时忽略
        /// </remarks>
        /// <param name="lock">锁状态,默认为0,小于0时忽略</param>
        /// <param name="curNum">当前数量,默认为-1,小于0时忽略</param>
        /// <param name="areas">所在库区列表,默认为null,为null或为空时忽略</param>
        /// <param name="name">货位名称,默认为null,为null或为空时忽略</param>
        /// <param name="pre"></param>
        /// <returns></returns>
        public static string StartLocNotFound(int @lock = 0, int curNum = -1, List<string> areas = null, string name = null, string pre = "") {
            var res = string.Empty;
            if (string.IsNullOrEmpty(name)) { res = $"没有找到合适的起点货位!"; }
            else { res = $"没有找到起点货位'{name}'!"; }
            var req = "";
            if (@lock >= 0) { req += $"锁状态='{TN_Location.GetLockStateStr(@lock)}';"; }
            if (curNum >= 0) { req += $"当前容器数量={curNum};"; }
            if (areas != null && areas.Count != 0) { req += $"所在库区=['{string.Join("','", areas)}'];"; }
            if (req != "") { res += "要求:" + req; }
            return pre + res;
        }
        /// <summary>
        /// 没有找到终点货位
        /// </summary>
        /// <remarks>
        /// <b>lockState</b> - 锁状态,默认为0,小于0时忽略<br/>
        /// <b>curNum</b> - 当前数量,默认为-1,小于0时忽略<br/>
        /// <b>areas</b> - 所在库区列表,默认为null,为null或为空时忽略<br/>
        /// <b>name</b> - 货位名称,默认为null,为null或为空时忽略
        /// </remarks>
        /// <param name="lock">锁状态,默认为0,小于0时忽略</param>
        /// <param name="curNum">当前数量,默认为-1,小于0时忽略</param>
        /// <param name="areas">所在库区列表,默认为null,为null或为空时忽略</param>
        /// <param name="name">货位名称,默认为null,为null或为空时忽略</param>
        /// <param name="pre"></param>
        /// <returns></returns>
        public static string EndLocNotFound(int @lock = 0, int curNum = -1, List<string> areas = null, string name = null, string pre = "") {
            var res = string.Empty;
            if (string.IsNullOrEmpty(name)) { res = $"没有找到合适的终点货位!"; }
            else { res = $"没有找到终点货位'{name}'!"; }
            var req = "";
            if (@lock >= 0) { req += $"锁状态='{TN_Location.GetLockStateStr(@lock)}';"; }
            if (curNum >= 0) { req += $"当前容器数量={curNum};"; }
            if (areas != null && areas.Count != 0) { req += $"所在库区=['{string.Join("','", areas)}'];"; }
            if (req != "") { res += "要求:" + req; }
            return pre + res;
        }
        public static string CreateTaskSuccess(TN_Task task, string pre = "") {
            var res = $"生成任务'{task.S_TYPE}'成功!" +
                $"任务号='{task.S_CODE}',容器号='{task.S_CNTR_CODE}',起点='{task.S_START_LOC}',终点='{task.S_END_LOC}'";
            return pre + res;
        }
        public static string CreateTaskFail(TN_Task task, string pre = "") {
            var res = $"生成任务'{task.S_TYPE}'失败!" +
                $"任务号={task.S_CODE},容器号={task.S_CNTR_CODE},起点={task.S_START_LOC},终点={task.S_END_LOC}";
            return pre + res;
        }
        public static string InsertLocCntrRelFail(TN_Loc_Container locCntrRel, string pre = "") {
            var res = $"插入[容器货位绑定表]失败!" + JsonConvert.SerializeObject(locCntrRel);
            return pre + res;
        }
        public static string InsertFail(string itemName, object item, string pre = "") {
            var res = $"插入[{itemName}]失败!" + JsonConvert.SerializeObject(item);
            return pre + res;
        }
        public static string DeleteFail(string itemName, object item, string pre = "") {
            var res = $"删除[{itemName}]失败!" + JsonConvert.SerializeObject(item);
            return pre + res;
        }
        public static string UpdateStartLocLockFail(TN_Location startLoc, string pre = "") {
            var res = $"更新[起点货位锁状态]失败!起点='{startLoc.S_CODE}',锁状态待修改为'{startLoc.S_LOCK_STATE}'";
            return pre + res;
        }
        public static string UpdateEndLocLockFail(TN_Location endLoc, string pre = "") {
            var res = $"更新[终点货位锁状态]失败!终点='{endLoc.S_CODE}',锁状态待修改为'{endLoc.S_LOCK_STATE}'";
            return pre + res;
        }
        public static string UpdateFail(string itemName, object item, string pre = "") {
            var res = $"更新[{itemName}]失败!" + JsonConvert.SerializeObject(item);
            return pre + res;
        }
        public static string LogEx(Exception ex, string pre = "") {
            var res = $"发生了异常:{ex.Message}";
            return pre + res;
        }
    }
}
wms/QueryHelper.cs
New file
@@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using HH.WCS.Mobox3.DSZSH.models;
using SqlSugar;
namespace HH.WCS.Mobox3.DSZSH.wms {
    public class QueryHelper {
        /// <summary>
        /// 构建货位查询表达式:当前锁状态、数量、货区、名称(默认筛选已启用货位)
        /// </summary>
        /// <param name="db">调用区域的数据库Client</param>
        /// <param name="lock"></param>
        /// <param name="name"></param>
        /// <param name="areas"></param>
        /// <param name="curNum"></param>
        /// <param name="expr"></param>
        /// <returns></returns>
        public static ISugarQueryable<TN_Location> GetLoc(SqlSugarClient db, int @lock, string name, List<string> areas, int curNum, Expression<Func<TN_Location, bool>> expr = null) {
            var query = db.Queryable<TN_Location>().Where(l => l.C_ENABLE == "Y"); // 已启用
            if (@lock >= 0) {
                query = query.Where(l => l.N_LOCK_STATE == @lock && l.S_LOCK_STATE == TN_Location.GetLockStateStr(@lock));
            }
            if (!string.IsNullOrEmpty(name)) {
                query = query.Where(l => l.S_CODE == name);
            }
            if (areas != null && areas.Count == 0) {
                query = query.Where(l => areas.Contains(l.S_AREA_CODE));
            }
            if (curNum >= 0) {
                query = query.Where(l => l.N_CURRENT_NUM == curNum);
            }
            if (expr != null) {
                query = query.Where(expr);
            }
            return query;
        }
    }
}
wms/WCSHelper.cs
@@ -77,10 +77,10 @@
        }
        /// <summary>
        /// 根据容器号,查询当前容器关联的[货位/容器/物料]信息(只查询1条)
        /// 根据 [ 容器号 ] , 查询当前容器关联的 [ 货位 ] [ 货位容器 ] [ 容器货品 ] 信息 ( 只查询 1 条 )
        /// </summary>
        /// <param name="cntrCode">容器号</param>
        /// <param name="skipCgDetail">是否跳过[物料表]的查询(当容器号来自[物料表]时)</param>
        /// <param name="skipCgDetail">是否跳过 [ 容器货品 ] 的查询 ( 当容器号来自 [ 容器货品 ] 时 )</param>
        /// <returns></returns>
        public static LocCntrCg GetLocCntrCg(string cntrCode, bool skipCgDetail = false) {
            var db = new SqlHelper<object>().GetInstance();
@@ -112,19 +112,20 @@
        }
        /// <summary>
        /// [绑定[货位-容器]信息](设置货位数量为1;不会检查loc是否为null)
        /// 绑定 [ 货位容器 ] 信息 ( 设置 [ 货位数量 ] = 1 )
        /// </summary>
        /// <remarks><b>[ 注意 ]</b> 不会检查 loc ≠ null</remarks>
        /// <param name="loc"></param>
        /// <param name="cntrCode"></param>
        /// <returns></returns>
        public static TN_Loc_Container BindLocCntr(ref TN_Location loc, string cntrCode) {
        public static TN_Loc_Container BindLocCntr(TN_Location loc, string cntrCode) {
            var locCntrRel = new TN_Loc_Container {
                S_LOC_CODE = loc.S_CODE,
                S_CNTR_CODE = cntrCode,
            };
            if (loc.N_CURRENT_NUM != 0) {
                LogHelper.Warn($"绑定货位容器:程序正在尝试给[容器数量]不是0的货位,设置[容器数量]为1!货位='{loc.S_CODE}',容器数量={loc.N_CURRENT_NUM}");
                LogHelper.Warn($"绑定货位容器:程序正在尝试给[容器数量]不是0的货位,设置[容器数量]为1!!货位='{loc.S_CODE}',容器数量={loc.N_CURRENT_NUM}");
            }
            loc.N_CURRENT_NUM = 1;
@@ -133,14 +134,20 @@
            return locCntrRel;
        }
        public static TN_Loc_Container BindLocCntrs(ref TN_Location loc, List<string> cntrCodes) {
        /// <summary>
        /// 绑定 [ 货位容器 ] 信息 ( 设置 [ 货位数量 ] + list.Count )
        /// </summary>
        /// <param name="loc"></param>
        /// <param name="cntrCodes"></param>
        /// <returns></returns>
        public static TN_Loc_Container BindLocCntrs(TN_Location loc, List<string> cntrCodes) {
            var locCntrRel = new TN_Loc_Container {
                S_LOC_CODE = loc.S_CODE,
                S_CNTR_CODE = string.Join(",", cntrCodes)
            };
            if (loc.N_CURRENT_NUM != 0) {
                LogHelper.Warn($"绑定货位容器:程序正在尝试给[容器数量]不是0的货位,设置[容器数量]为1!货位='{loc.S_CODE}',容器数量={loc.N_CURRENT_NUM}");
                LogHelper.Warn($"绑定货位容器:程序正在尝试给[容器数量]不是0的货位,设置[容器数量]为1!!货位='{loc.S_CODE}',容器数量={loc.N_CURRENT_NUM}");
            }
            loc.N_CURRENT_NUM = 1;
@@ -171,7 +178,7 @@
        /// <summary>
        /// 终点入库锁
        /// </summary>
        /// <remarks>要求: loc != null; 锁状态='无';</remarks>
        /// <remarks>要求 : loc ≠ null ; 锁状态='无' ;</remarks>
        /// <param name="loc"></param>
        /// <param name="lockSource"></param>
        public static void LockEndLoc(TN_Location loc, string lockSource = "") {
@@ -188,8 +195,9 @@
        }
        /// <summary>
        /// [创建任务](需确保startLoc/endLoc不为null;不会检查货位S_CODE,S_AREA_CODE属性是否合法)
        /// 创建任务
        /// </summary>
        /// <remarks>要求 : <br/>(1) startLoc / endLoc ≠ null<br/>(2) startLoc / endLoc 存在 S_CODE , S_AREA_CODE 字段</remarks>
        /// <param name="startLoc">起点货位:至少提供:S_CODE,S_AREA_CODE</param>
        /// <param name="endLoc">终点货位:至少提供:S_CODE,S_AREA_CODE</param>
        /// <param name="cntId">容器号</param>
@@ -198,7 +206,7 @@
        /// <param name="agv">AGV类型</param>
        /// <returns></returns>
        public static TN_Task BuildTask(TN_Location startLoc, TN_Location endLoc, string cntId, string type, int pri = 3, int agv = 1) {
            TN_Task TN_Task = new TN_Task() {
            TN_Task task = new TN_Task() {
                S_CODE = GenerateTaskNo(),
                S_START_AREA = startLoc.S_AREA_CODE,
                S_END_AREA = endLoc.S_AREA_CODE,
@@ -211,15 +219,15 @@
                N_B_STATE = 0, // 任务创建时,默认等待
            };
            LogHelper.Info($"创建任务:任务号='{TN_Task.S_CODE}'");
            LogHelper.Info($"创建任务:任务号='{task.S_CODE}',起点货位='',终点货位='',容器号='',任务类型");
            return TN_Task;
            return task;
        }
        /// <summary>
        /// [ 创建任务,并上锁 ] ( 需确保startLoc/endLoc不为null ; 不会检查货位S_CODE,S_AREA_CODE属性是否合法 )
        /// 创建任务 + 货位锁
        /// </summary>
        /// <remarks>要求 : (1) startLoc / endLoc ≠ null<br/>(2) startLoc / endLoc 存在 S_CODE , S_AREA_CODE</remarks>
        /// <remarks>要求 : <br/>(1) startLoc / endLoc ≠ null<br/>(2) startLoc / endLoc 存在 S_CODE , S_AREA_CODE 字段</remarks>
        /// <param name="startLoc">起点货位 : 至少提供 : S_CODE , S_AREA_CODE</param>
        /// <param name="endLoc">终点货位 : 至少提供 : S_CODE , S_AREA_CODE</param>
        /// <param name="cntId">容器号</param>
@@ -228,25 +236,11 @@
        /// <param name="agv">AGV类型</param>
        /// <returns></returns>
        public static TN_Task BuildTaskWithLocLock(TN_Location startLoc, TN_Location endLoc, string cntId, string type, int pri = 3, int agv = 1) {
            TN_Task TN_Task = new TN_Task() {
                S_CODE = GenerateTaskNo(),
                S_START_AREA = startLoc.S_AREA_CODE,
                S_END_AREA = endLoc.S_AREA_CODE,
                S_START_LOC = startLoc.S_CODE,
                S_END_LOC = endLoc.S_CODE,
                S_CNTR_CODE = cntId,
                S_TYPE = type,
                N_PRIORITY = pri,
                N_SCHEDULE_TYPE = agv,
                N_B_STATE = 0, // 任务创建时,默认等待
            };
            var task = BuildTask(startLoc, endLoc, cntId, type, pri);
            LockStartLoc(startLoc, task.S_CODE);
            LockEndLoc(endLoc, task.S_CODE);
            LogHelper.Info($"创建任务:任务号='{TN_Task.S_CODE}'");
            LockStartLoc(startLoc, TN_Task.S_CODE);
            LockEndLoc(endLoc, TN_Task.S_CODE);
            return TN_Task;
            return task;
        }
        internal static bool CheckActionRecordExist(string no, int code) {