using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using HH.WCS.Mobox3.AnGang.dispatch; using HH.WCS.Mobox3.AnGang.models; using HH.WCS.Mobox3.AnGang.util; using HH.WCS.Mobox3.AnGang.wms; using Newtonsoft.Json; using Swashbuckle.Swagger; using static HH.WCS.Mobox3.AnGang.api.ApiModel; using static HH.WCS.Mobox3.AnGang.api.OtherModel; namespace HH.WCS.Mobox3.AnGang.api { public class ApiHelper { /// /// 产品入库(PDA) /// /// /// internal static SimpleResult Inbound(InboundInfo model) { var taskName = TaskName.产品入库; var db = new SqlHelper().GetInstance(); var startAreas = Settings.Areas[AreaIndex.Q取货区]; try { // 起点位置必须:为空、无锁、启用、属于收发区域 var startLoc = db.Queryable() .Where(a => a.S_CODE == model.StartLoc) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") .Where(a => a.N_CURRENT_NUM == 0) .Where(a => startAreas.Contains(a.S_AREA_CODE)) .First(); if (startLoc == null) { return BuildSimpleResult(1, $"起点位置{model.StartLoc}不存在或不满足要求:(1)没有锁状态 (2)属于取放货区"); } //var locCntrRelOld = db.Queryable() // .Where(c => c.S_LOC_CODE == model.StartLoc).First(); //// 产品入库:假定用户不会将新入库物料,放到已有物料的收发货区入库 //// 新产品入库时,如果存在旧的货位绑定数据(出库遗留项目)直接删除 //TN_CG_Detail cgDetailOld = null; //if (locCntrRelOld != null) { // cgDetailOld = db.Queryable() // .Where(d => d.S_CNTR_CODE == locCntrRelOld.S_CNTR_CODE).First(); //} // 容器 ID 和 物料 ID 未指定,由系统直接生成 //var cntId = Guid.NewGuid().ToString("D"); //var CgId = Guid.NewGuid().ToString("D"); var cntId = GenerateNo("容器号", "CN"); var cgId = GenerateNo("物料号", "CG"); // 首次入库:没有绑定信息,先将起点位置与容器绑定,容器与物料绑定 var locCntrRel = new TN_Loc_Container() { S_LOC_CODE = startLoc.S_CODE, S_CNTR_CODE = cntId, }; var cgDetail = new TN_CG_Detail() { S_ITEM_CODE = cgId, S_CNTR_CODE = cntId, S_LOC_CODE = startLoc.S_CODE, // ADD:补充针对PDA分拣 }; startLoc.N_CURRENT_NUM = 1; var endLocCode = "0"; // 假的默认终点地址 // 指定货位排号(不能为空、空字符串或空格) if (model.Row != null && model.Row.Trim() != "") { endLocCode = model.Row; // 用排号字符串当做假地址 if (!int.TryParse(model.Row.Trim(), out int row)) { return BuildSimpleResult(2, $"{model.Row} 不合法:无法转成整数类型"); } // 货架排号只能是 0 - 8(111-118) if (row <= 110 || row > 118) { return BuildSimpleResult(2, $"货架号 {model.Row} 必须是111-118之间的整数"); } } var task = WCSHelper.BuildInboundTask(startLoc, endLocCode, cntId); LocationHelper.LockLoc(ref startLoc, 2); // 起点出库锁 // 无论是否选择终点货架,都等到称重之后再计算终点货位 using (var tran = db.Ado.UseTran()) { //if (locCntrRelOld != null) { // if (db.Deleteable(locCntrRelOld).ExecuteCommand() <= 0) { // tran.RollbackTran(); // return BuildSimpleResult(500, // $"删除货位容器关系表失败:货位{locCntrRelOld.S_LOC_CODE},容器{locCntrRelOld.S_CNTR_CODE}"); // } //} //if (cgDetailOld != null) { // if (db.Deleteable(cgDetailOld).ExecuteCommand() <= 0) { // tran.RollbackTran(); // return BuildSimpleResult(500, // $"删除旧容器货品明细表失败:容器{cgDetailOld.S_CNTR_CODE},物料{cgDetailOld.S_ITEM_CODE}"); // } //} if (db.Insertable(locCntrRel).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildSimpleResult(500, $"插入货位容器关系表失败:货位{locCntrRel.S_LOC_CODE},容器{locCntrRel.S_CNTR_CODE}"); } if (db.Insertable(cgDetail).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildSimpleResult(500, $"插入容器货品明细表失败:容器{cgDetail.S_CNTR_CODE},物料{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 BuildSimpleResult(500, $"更新起点货位锁状态失败:起点货位{startLoc.S_CODE}"); } if (db.Insertable(task).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildSimpleResult(500, $"生成任务 {taskName} 失败:容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLocCode} ,终点货位未指定"); } tran.CommitTran(); return BuildSimpleResult(0, $"生成任务 {taskName} 成功:容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLocCode} ,终点货位未指定"); } } catch (Exception ex) { return BuildSimpleResult(1, $"发生了异常:{ex.Message}"); } } public static SimpleResult InboundData(InboundDataInfo model) { var taskName = TaskName.产品入库; var db = new SqlHelper().GetInstance(); var startAreas = Settings.Areas[AreaIndex.Q取货区]; try { // 起点位置必须:为空、无锁、启用、属于收发区域 var startLoc = db.Queryable() .Where(a => a.S_CODE == model.StartLoc) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") .Where(a => a.N_CURRENT_NUM == 0) .Where(a => startAreas.Contains(a.S_AREA_CODE)) .First(); if (startLoc == null) { return BuildSimpleResult(1, $"起点位置{model.StartLoc}不存在或不满足要求:(1)没有锁状态 (2)属于取放货区"); } //var locCntrRelOld = db.Queryable() // .Where(c => c.S_LOC_CODE == model.StartLoc).First(); //// 产品入库:假定用户不会将新入库物料,放到已有物料的收发货区入库 //// 新产品入库时,如果存在旧的货位绑定数据(出库遗留项目)直接删除 //TN_CG_Detail cgDetailOld = null; //if (locCntrRelOld != null) { // cgDetailOld = db.Queryable() // .Where(d => d.S_CNTR_CODE == locCntrRelOld.S_CNTR_CODE).First(); //} // 容器 ID 和 物料 ID 未指定,由系统直接生成 //var cntId = Guid.NewGuid().ToString("D"); //var CgId = Guid.NewGuid().ToString("D"); var cntId = GenerateNo("容器号", "CN"); //var cgId = GenerateNo("物料号", "CG"); var cgId = string.IsNullOrEmpty(model.ItemCode) ? GenerateNo("物料号", "CG") : model.ItemCode ; // 首次入库:绑定信息,先将起点位置与容器绑定,容器与物料绑定 var locCntrRel = new TN_Loc_Container() { S_LOC_CODE = startLoc.S_CODE, S_CNTR_CODE = cntId, N_LOCK_STATE = string.IsNullOrEmpty(model.ItemCode) ? 0 : 1, }; var cgDetail = new TN_CG_Detail() { S_ITEM_CODE = cgId, S_CNTR_CODE = cntId, //S_ITEM_NAME = model.ItemName, S_LOC_CODE = startLoc.S_CODE, // ADD:补充针对PDA分拣 }; startLoc.N_CURRENT_NUM = 1; var endLocCode = "0"; // 假的默认终点地址 // 指定货位排号(不能为空、空字符串或空格) if (model.Row != null && model.Row.Trim() != "") { endLocCode = model.Row; // 用排号字符串当做假地址 if (!int.TryParse(model.Row.Trim(), out int row)) { return BuildSimpleResult(2, $"{model.Row} 不合法:无法转成整数类型"); } // 货架排号只能是 0 - 8(111-118) if (row <= 110 || row > 118) { return BuildSimpleResult(2, $"货架号 {model.Row} 必须是111-118之间的整数"); } } var task = WCSHelper.BuildInboundTask(startLoc, endLocCode, cntId); LocationHelper.LockLoc(ref startLoc, 2); // 起点出库锁 // 无论是否选择终点货架,都等到称重之后再计算终点货位 using (var tran = db.Ado.UseTran()) { //if (locCntrRelOld != null) { // if (db.Deleteable(locCntrRelOld).ExecuteCommand() <= 0) { // tran.RollbackTran(); // return BuildSimpleResult(500, // $"删除货位容器关系表失败:货位{locCntrRelOld.S_LOC_CODE},容器{locCntrRelOld.S_CNTR_CODE}"); // } //} //if (cgDetailOld != null) { // if (db.Deleteable(cgDetailOld).ExecuteCommand() <= 0) { // tran.RollbackTran(); // return BuildSimpleResult(500, // $"删除旧容器货品明细表失败:容器{cgDetailOld.S_CNTR_CODE},物料{cgDetailOld.S_ITEM_CODE}"); // } //} if (db.Insertable(locCntrRel).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildSimpleResult(500, $"插入货位容器关系表失败:货位{locCntrRel.S_LOC_CODE},容器{locCntrRel.S_CNTR_CODE}"); } if (db.Insertable(cgDetail).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildSimpleResult(500, $"插入容器货品明细表失败:容器{cgDetail.S_CNTR_CODE},物料{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 BuildSimpleResult(500, $"更新起点货位锁状态失败:起点货位{startLoc.S_CODE}"); } if (db.Insertable(task).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildSimpleResult(500, $"生成任务 {taskName} 失败:容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLocCode} ,终点货位未指定"); } tran.CommitTran(); return BuildSimpleResult(0, $"生成任务 {taskName} 成功:容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLocCode} ,终点货位未指定"); } } catch (Exception ex) { return BuildSimpleResult(1, $"发生了异常:{ex.Message}"); } } internal static string GenerateNo(string snType, string prefix) { var id = SYSHelper.GetSerialNumber(snType, prefix); var date = DateTime.Now.ToString("yyMMdd"); return $"{prefix}{date}-{id.ToString().PadLeft(5, '0')}"; // 形如:CN250525-00011 } /// /// 兼容Inbound和PartInbound的功能,备用(问题:出库后无法自动清数据,导致入库后回库) /// /// /// public static SimpleResult InboundTwoWays(InboundInfo model) { var taskName = TaskName.产品入库; var db = new SqlHelper().GetInstance(); var startAreas = Settings.Areas[AreaIndex.Q取货区]; try { // 起点位置必须:为空、无锁、启用、属于收发区域 var startLoc = db.Queryable() .Where(a => a.S_CODE == model.StartLoc) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") //.Where(a => a.N_CURRENT_NUM == 0) .Where(a => startAreas.Contains(a.S_AREA_CODE)) .First(); if (startLoc == null) { return BuildSimpleResult(1, $"起点位置{model.StartLoc}不存在或不满足要求:(1)没有锁状态 (2)属于取放货区"); } // 容器 ID 和 物料 ID 未指定,由系统直接生成 //var cntId = Guid.NewGuid().ToString("D"); //var CgId = Guid.NewGuid().ToString("D"); var cntId = GenerateNo("容器号", "CN"); var cgId = GenerateNo("物料号", "CG"); var locCntrRel = db.Queryable() .Where(c => c.S_LOC_CODE == model.StartLoc).First(); // 只有首次入库(当前托盘未绑定在起点货位)时cgDetail设置值,并插入 // 否则,cgDetail为空,代表是回库作业(此前有绑定过起点) TN_CG_Detail cgDetail = null; if (locCntrRel == null) { // 首次入库:没有绑定信息,先将起点位置与容器绑定,容器与物料绑定 locCntrRel = new TN_Loc_Container() { S_LOC_CODE = startLoc.S_CODE, S_CNTR_CODE = cntId, }; cgDetail = new TN_CG_Detail() { S_ITEM_CODE = cgId, S_CNTR_CODE = cntId, }; } startLoc.N_CURRENT_NUM = 1; var endLocCode = "0"; // 假的默认终点地址 // 指定货位排号(不能为空、空字符串或空格) if (model.Row != null && model.Row.Trim() != "") { endLocCode = model.Row; // 用排号字符串当做假地址 if (!int.TryParse(model.Row.Trim(), out int row)) { return BuildSimpleResult(2, $"{model.Row} 不合法:无法转成整数类型"); } // 货架排号只能是 0 - 8(111-118) if (row <= 110 || row > 118) { return BuildSimpleResult(2, $"货架号 {model.Row} 必须是111-118之间的整数"); } } var task = WCSHelper.BuildInboundTask(startLoc, endLocCode, cntId); LocationHelper.LockLoc(ref startLoc, 2); // 起点出库锁 // 无论是否选择终点货架,都等到称重之后再计算终点货位 using (var tran = db.Ado.UseTran()) { if (cgDetail != null) { if (db.Insertable(locCntrRel).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildSimpleResult(500, $"插入货位容器关系表失败:货位{locCntrRel.S_LOC_CODE},容器{locCntrRel.S_CNTR_CODE}"); } if (db.Insertable(cgDetail).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildSimpleResult(500, $"插入容器货品明细表失败:容器{cgDetail.S_CNTR_CODE},物料{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 BuildSimpleResult(500, $"更新起点货位锁状态失败:起点货位{startLoc.S_CODE}"); } if (db.Insertable(task).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildSimpleResult(500, $"生成任务 {taskName} 失败:容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLocCode} ,终点货位未指定"); } tran.CommitTran(); return BuildSimpleResult(0, $"生成任务 {taskName} 成功:容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLocCode} ,终点货位未指定"); } } catch (Exception ex) { return BuildSimpleResult(1, $"发生了异常:{ex.Message}"); } } /// /// PDA选择终点货位 /// /// /// internal static SimpleResult SelectLocation(SelectLocationInfo model) { var db = new SqlHelper().GetInstance(); var endAreas = Settings.Areas[AreaIndex.H货架区]; try { // 任务号存在:终点货架和终点位置为空,且任务为产品入库(PDA) var task = db.Queryable() .Where(a => a.S_CODE == model.TaskNo) .Where(a => a.S_B_STATE == "取货完成" && a.S_TYPE == TaskName.产品入库) .OrderBy(a => a.T_CREATE, SqlSugar.OrderByType.Desc).First(); if (task == null) { return BuildSimpleResult(2, $"当前不存在状态为 取货完成 的 产品入库 任务"); } if (task.S_END_LOC != null && task.S_END_LOC != "0") { return BuildSimpleResult(3, $"该任务已有终点"); } var cgDetail = db.Queryable() .Where(a => a.S_CNTR_CODE == task.S_CNTR_CODE).First(); if (cgDetail == null) { return BuildSimpleResult(4, $"托盘物料不存在"); } var endLoc = new TN_Location(); if (cgDetail.F_QTY > 2000) { // 重量超过2t,报错 if (GZRobot.TryGetInteractionInfoId(task.S_CODE, out var id1)) { if (GZRobot.UpdateInteractInfo(new UpdateInteractInfo { type_name = "GET_DST", interaction_info_id = id1, info_status = "error", })) { LogHelper.Info($"国自AGV接受超重取消信息成功", "HosttoagvTask"); } else { LogHelper.Info($"国自AGV接受超重取消信息失败", "HosttoagvTask"); //return BuildSimpleResult(7, $"国自AGV接受终点信息失败"); } } else { //return BuildSimpleResult(7, $"获取任务{task.S_CODE}的agv interaction_info_id失败!"); LogHelper.Info($"AGV:获取任务{task.S_CODE}的interaction_info_id失败!", "HosttoagvTask"); //return BuildSimpleResult(8, $"国自AGV接受终点信息失败"); } return BuildSimpleResult(8, $"物料重量{cgDetail.F_QTY}超过2t"); } else if (cgDetail.F_QTY > 1500) { // 重量超过1.5t,需要选择1-2层货架 endLoc = db.Queryable() .Where(a => a.S_CODE == model.EndLoc) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") .Where(a => a.N_CURRENT_NUM == 0) .Where(a => endAreas.Contains(a.S_AREA_CODE)) .Where(a => a.N_LAYER <= 2) .First(); } else if (cgDetail.F_QTY > 0) { endLoc = db.Queryable() .Where(a => a.S_CODE == model.EndLoc) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") .Where(a => a.N_CURRENT_NUM == 0) .Where(a => endAreas.Contains(a.S_AREA_CODE)) .OrderBy(a => a.N_LAYER > 2 ? 0 : 1) // 优先取大于2的 //.Where(a => a.N_LAYER <= 3) .First(); } else { return BuildSimpleResult(5, $"物料重量信息不合法:{cgDetail.F_QTY}"); } // 没有符合条件的货位 if (endLoc == null) { return BuildSimpleResult(6, $"货位{model.EndLoc}不存在,或不满足称重放置要求"); } // 修改任务终点为PDA指定终点 task.S_END_LOC = endLoc.S_CODE; LocationHelper.LockLoc(ref endLoc, 1); // 终点入库锁 if (GZRobot.TryGetInteractionInfoId(task.S_CODE, out var id2)) { if (GZRobot.UpdateInteractInfo(new UpdateInteractInfo { type_name = "GET_DST", interaction_info_id = id2, info_status = "invalid", return_value = LocationHelper.GetAgvSite(task.S_END_LOC), // 目前使用agvsite })) { LogHelper.Info($"国自AGV接受终点信息成功", "HosttoagvTask"); } else { LogHelper.Info($"国自AGV接受终点信息失败", "HosttoagvTask"); return BuildSimpleResult(7, $"国自AGV接受终点信息失败"); } } else { LogHelper.Info($"AGV:获取任务{task.S_CODE}的interaction_info_id失败!", "HosttoagvTask"); return BuildSimpleResult(8, $"国自AGV接受终点信息失败"); } using (var tran = db.Ado.UseTran()) { if (db.Updateable(task).UpdateColumns(a => a.S_END_LOC).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildSimpleResult(500, $"任务{task.S_CODE}修改失败,修改终点位置为{endLoc.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 BuildSimpleResult(500, $"任务{task.S_CODE}修改失败,修改终点位置为{endLoc.S_CODE}"); } tran.CommitTran(); return BuildSimpleResult(0, $"任务{task.S_CODE}修改成功,修改终点位置为{endLoc.S_CODE}"); } } catch (Exception ex) { return BuildSimpleResult(1, $"发生了异常:{ex.Message}"); } } /// /// 产品部分出库 /// /// /// internal static SimpleResult PartOutbound(PartOutboundInfo model) { var taskName = TaskName.产品部分出库; var db = new SqlHelper().GetInstance(); var startAreas = Settings.Areas[AreaIndex.H货架区]; var endAreas = Settings.Areas[AreaIndex.X卸货区]; try { // 起点位置:货架(有货、没有锁、已启用) var startLoc = db.Queryable() .Where(a => a.S_CODE == model.startLoc) .Where(a => a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y") .Where(a => startAreas.Contains(a.S_AREA_CODE)) .Where(a => a.N_CURRENT_NUM == 1) .First(); if (startLoc == null) { return BuildSimpleResult(2, $"起点位置 {model.startLoc} 不存在或不具备取货要求!"); } var locCntrRel = db.Queryable().First(a => a.S_LOC_CODE == model.startLoc); if (locCntrRel == null) { return BuildSimpleResult(3, $"起点位置 {model.startLoc} 没有绑定容器,无可出库的物料!"); } if (locCntrRel.N_LOCK_STATE == 0) { return BuildSimpleResult(5, $"起点位置'{model.startLoc}'的货位,货位容器关系上锁,物料信息尚未传递,无法出库!"); } var endLoc = db.Queryable().First(a => a.S_CODE == model.endLoc && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && endAreas.Contains(a.S_AREA_CODE)); if (endLoc == null) { return BuildSimpleResult(4, $"终点位置 {model.endLoc} 不具备放货条件"); } var cntId = locCntrRel.S_CNTR_CODE; var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); LocationHelper.LockLoc(ref startLoc, 2); // 起点出库锁 LocationHelper.LockLoc(ref endLoc, 1); // 终点入库锁 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 }).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.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 BuildSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } if (db.Insertable(task).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } tran.CommitTran(); return BuildSimpleResult(0, $"生成 {taskName} 成功,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } } catch (Exception ex) { return BuildSimpleResult(1, $"发生了异常:{ex.Message}"); } } /// /// 产品部分回库 /// /// /// internal static SimpleResult PartInbound(PartInboundInfo model) { var taskName = TaskName.产品部分回库; var db = new SqlHelper().GetInstance(); var startAreas = Settings.Areas[AreaIndex.X卸货区]; var endAreas = Settings.Areas[AreaIndex.H货架区]; try { // 起点位置:取放货区(有货物、没有锁、已启用) var startLoc = db.Queryable().First(a => a.S_CODE == model.startLoc && a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && startAreas.Contains(a.S_AREA_CODE)); if (startLoc == null) { return BuildSimpleResult(2, $"起点位置 {model.startLoc} 不符合回库条件"); } var locCntrRel = db.Queryable().First(a => a.S_LOC_CODE == model.startLoc); if (locCntrRel == null) { return BuildSimpleResult(3, $"起点位置 {model.startLoc} 没有绑定容器,无可回库的物料"); } // 终点位置:货架(没有货物,没有锁) var endLoc = db.Queryable().First(a => a.S_CODE == model.endLoc && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && endAreas.Contains(a.S_AREA_CODE)); if (endLoc == null) { return BuildSimpleResult(4, $"终点位置 {model.endLoc} 不具备放货条件"); } var cntId = locCntrRel.S_CNTR_CODE; var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); LocationHelper.LockLoc(ref startLoc, 2); // 起点出库锁 LocationHelper.LockLoc(ref endLoc, 1); // 终点入库锁 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 }).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.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 BuildSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } if (db.Insertable(task).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } tran.CommitTran(); return BuildSimpleResult(0, $"生成 {taskName} 成功,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } } catch (Exception ex) { return BuildSimpleResult(1, $"发生了异常:{ex.Message}"); } } /// /// 产品部分回库(不指定终点,备用) /// /// /// internal static SimpleResult PartInboundAuto(PartInboundInfo model) { var taskName = TaskName.产品部分回库; var db = new SqlHelper().GetInstance(); var startAreas = Settings.Areas[AreaIndex.X卸货区]; var endAreas = Settings.Areas[AreaIndex.H货架区]; try { // 起点位置:取放货区(有货物、没有锁、已启用) var startLoc = db.Queryable().First(a => a.S_CODE == model.startLoc && a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && startAreas.Contains(a.S_AREA_CODE)); if (startLoc == null) { return BuildSimpleResult(2, $"起点位置 {model.startLoc} 不符合回库条件"); } var locCntrRel = db.Queryable().First(a => a.S_LOC_CODE == model.startLoc); if (locCntrRel == null) { return BuildSimpleResult(3, $"起点位置 {model.startLoc} 没有绑定容器,无可回库的物料"); } // 终点位置:货架(没有货物,没有锁) var endLoc = db.Queryable().First(a => a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.S_LOCK_STATE == "无" && a.C_ENABLE == "Y" && endAreas.Contains(a.S_AREA_CODE)); if (endLoc == null) { return BuildSimpleResult(4, $"没有找到合适的终点货位"); } var cntId = locCntrRel.S_CNTR_CODE; var task = WCSHelper.BuildTask(startLoc, endLoc, cntId, taskName); LocationHelper.LockLoc(ref startLoc, 2); // 起点出库锁 LocationHelper.LockLoc(ref endLoc, 1); // 终点入库锁 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 }).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货位 {endLoc.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 BuildSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } if (db.Insertable(task).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildSimpleResult(500, $"生成 {taskName} 失败,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } tran.CommitTran(); return BuildSimpleResult(0, $"生成 {taskName} 成功,容器号 {cntId} ,起点 {startLoc.S_CODE} ,终点货架 {endLoc.S_CODE}"); } } catch (Exception ex) { return BuildSimpleResult(1, $"发生了异常:{ex.Message}"); } } public static SimpleResult CancelTask(CancelTaskInfo model) { var db = new SqlHelper().GetInstance(); var info = ""; try { var task = db.Queryable() .Where(a => a.S_CODE == model.TaskNo) .First(); if (task == null) { return BuildSimpleResult(2, $"任务号{model.TaskNo}不存在"); } // 等待 或 已推送 时,可以取消任务 //if (task.N_B_STATE == 0 && task.S_B_STATE == TN_Task.GetStateStr(0) // || task.N_B_STATE == 1 && task.S_B_STATE == TN_Task.GetStateStr(1)) { if (task.N_B_STATE == 0 || task.N_B_STATE == 1) { var startloc = db.Queryable().First(a => a.S_CODE == task.S_START_LOC); var endloc = db.Queryable().First(a => a.S_CODE == task.S_END_LOC); //var locCnt = db.Queryable().First(a => a.S_CNTR_CODE == task.S_CNTR_CODE); //var cg = db.Queryable().First(a => a.S_CNTR_CODE == task.S_CNTR_CODE); if (startloc != null) { startloc.N_LOCK_STATE = 0; startloc.S_LOCK_STATE = "无"; //starloc.N_CURRENT_NUM = 0; startloc.T_MODIFY = System.DateTime.Now; } if (endloc != null) { endloc.N_LOCK_STATE = 0; endloc.S_LOCK_STATE = "无"; //endloc.N_CURRENT_NUM = 0; endloc.T_MODIFY = System.DateTime.Now; } if (task.N_B_STATE == 1) { if (!int.TryParse(task.S_EQ_TASK_CODE, out var code)) { LogHelper.Info($"当前任务{task.S_CODE}没有找到对应的国自AGV orderId!"); } else { var res = GZRobot.CancelGZOrder(code); if (!res) { LogHelper.Info($"国自AGV取消任务失败!", "HosttoagvTask"); } else { LogHelper.Info($"国自AGV取消任务成功!", "HosttoagvTask"); } } } task.N_B_STATE = 4; task.S_B_STATE = "取消"; using (var tran = db.Ado.UseTran()) { if (db.Updateable(startloc).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"任务{task.S_CODE}取消失败:修改起点货位锁状态失败"; return BuildSimpleResult(500, info); } if (endloc != null) { if (db.Updateable(endloc).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"任务{task.S_CODE}取消失败:修改终点货位锁状态失败"; return BuildSimpleResult(500, info); } } if (db.Updateable(task).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"任务{task.S_CODE}取消失败"; return BuildSimpleResult(500, info); } tran.CommitTran(); info = $"任务{task.S_CODE}取消成功"; return BuildSimpleResult(0, info); } } else { //return BuildSimpleResult(3, $"只有任务号状态为 等待 或 已推送 的任务才能取消"); return CancelTaskIfForced(model, task); // 备用函数,如果甲方要求任务执行中也取消,再调用 } } catch (Exception ex) { return BuildSimpleResult(1, $"发生了异常:{ex.Message}"); } } public static SimpleResult CancelTaskIfForced(CancelTaskInfo model, TN_Task task) { var db = new SqlHelper().GetInstance(); var info = ""; try { var startloc = db.Queryable().First(a => a.S_CODE == task.S_START_LOC); var endloc = db.Queryable().First(a => a.S_CODE == task.S_END_LOC); //var locCnt = db.Queryable().First(a => a.S_CNTR_CODE == task.S_CNTR_CODE); //var cg = db.Queryable().First(a => a.S_CNTR_CODE == task.S_CNTR_CODE); if (startloc != null) { startloc.N_LOCK_STATE = 0; startloc.S_LOCK_STATE = "无"; //starloc.N_CURRENT_NUM = 0; startloc.T_MODIFY = System.DateTime.Now; } if (endloc != null) { endloc.N_LOCK_STATE = 0; endloc.S_LOCK_STATE = "无"; //endloc.N_CURRENT_NUM = 0; endloc.T_MODIFY = System.DateTime.Now; } if (task.N_B_STATE == 1) { if (!int.TryParse(task.S_EQ_TASK_CODE, out var code)) { LogHelper.Info($"当前任务{task.S_CODE}没有找到对应的国自AGV orderId!"); } else { var res = GZRobot.CancelGZOrder(code); if (!res) { LogHelper.Info($"国自AGV取消任务失败!", "HosttoagvTask"); } else { LogHelper.Info($"国自AGV取消任务成功!", "HosttoagvTask"); } } } task.N_B_STATE = 4; task.S_B_STATE = "取消"; // 前面锁状态的部分不需要修改:无论有没有恢复,都强制恢复,最终结果都是无锁状态 // 已执行:需要添加的逻辑:针对解锁/绑定的货位容器表(好像不需要关心,先不做任何操作) using (var tran = db.Ado.UseTran()) { if (db.Updateable(startloc).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"任务{task.S_CODE}取消失败:修改起点货位锁状态失败"; return BuildSimpleResult(500, info); } if (endloc != null) { if (db.Updateable(endloc).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"任务{task.S_CODE}取消失败:修改终点货位锁状态失败"; return BuildSimpleResult(500, info); } } if (db.Updateable(task).ExecuteCommand() <= 0) { tran.RollbackTran(); info = $"任务{task.S_CODE}取消失败"; return BuildSimpleResult(500, info); } tran.CommitTran(); info = $"任务{task.S_CODE}取消成功"; return BuildSimpleResult(0, info); } } catch (Exception) { throw; // 外部catch } //return BuildSimpleResult(3, $"只有任务号状态为 等待 或 已推送 的任务才能取消"); } public static ErpResult InboundDataSync(InboundDataSyncInfo model) { //return BuildErpResult(1, "测试"); var db = new SqlHelper().GetInstance(); try { if (model.stockTransactions == null && model.stockTransactions.Count == 0) { return BuildErpResult(400, "不能传入空的数据列表"); } //var info = ""; //var cgDetailList = new List(); var insetRecordList = new List(); var deleteRecordOldList = new List (); //var errList = new List(); foreach (var transaction in model.stockTransactions) { var recordOld = db.Queryable() .Where(r => r.S_LOCATION_CODE == "HJQ-" + transaction.locationCode.Trim()).First(); if (recordOld != null) { deleteRecordOldList.Add(recordOld); //errList.Add(recordOld); //continue; } // 写入记录表 var record = new TN_Inbound_DataRecord { S_LOCATION_CODE = "HJQ-" + transaction.locationCode.Trim(), S_STOCK_TRANS = transaction.stockTransactionId, S_ITEM_CODE = transaction.itemCode, S_ITEM_NAME = transaction.itemName, S_ITEM_SHORT_DESC = transaction.itemShortDesc, S_STOCK_QUANTITY = transaction.stockQuantity, // 库存数量 S_IN_QUANTITY = transaction.inQuantity, // 入库数量 S_TOTAL_PRICE = transaction.totalPrice, S_STOCK_IN_TIME = transaction.stockInTime, S_STORE_KEEPER = transaction.storeKeeper, S_LINE_CODE = transaction.lineCode, S_DELIVERY_ITEM_NO = transaction.deliveryItemNo, S_SUPPLIER_NAME = transaction.supplierName, S_INVENTORY_MAN = transaction.inventoryManager }; insetRecordList.Add(record); //// 查询对应物料 //var cgDetail = db.Queryable // ((l, c, d) => l.S_CODE == c.S_LOC_CODE && c.S_CNTR_CODE == d.S_CNTR_CODE) // .Where(l => l.S_CODE == transaction.locationCode) // .Select((l, c, d) => d) // .First(); //if (cgDetail == null) { // err += $"储位码{transaction.locationCode}对应的货位物料不存在!"; // continue; //} //cgDetail.S_ITEM_CODE = transaction.itemCode; //cgDetail.S_ITEM_NAME = transaction.itemName; //cgDetailList.Add(cgDetail); } using (var tran = db.Ado.UseTran()) { if (deleteRecordOldList.Count != 0 && db.Deleteable(deleteRecordOldList).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildErpResult(500, $"删除旧入库记录数据失败:{JsonConvert.SerializeObject(deleteRecordOldList)}"); } if (db.Insertable(insetRecordList).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildErpResult(500, $"写入入库记录表失败!"); } //if (db.Updateable(cgDetailList).ExecuteCommand() <= 0) { // tran.RollbackTran(); // return BuildErpResult(500, $"更改物料信息失败!待更新物料信息数量={cgDetailList.Count}"); //} tran.CommitTran(); return BuildErpResult(0, $"写入入库记录表成功!"); } //if (err != "") { // return BuildErpResult(2, err + "其他信息正常已写入"); //} //return BuildErpResult(0, $"更改物料信息成功"); // NOTE:暂时不检查,万一ERP发错了,可以选择重发 //if (errList.Count > 0) { // info = "更改物料信息部分成功,部分失败,原因:当前货位已经给过物料信息"; //} //else { // info = "更改物料信息成功!"; //} } catch (Exception ex) { return BuildErpResult(1, $"发生了异常:{ex.Message}"); } } public static ErpResult OutboundDataSync(OutboundDataSyncInfo model) { //return BuildErpResult(1, "测试"); var db = new SqlHelper().GetInstance(); try { if (model.materialIssues == null || model.materialIssues.Count == 0) { return BuildErpResult(400, "不能传入空的数据列表"); } //var err = ""; //var cgDetailList = new List(); //var recordList = new List(); var insetRecordList = new List(); var deleteRecordOldList = new List(); foreach (var issue in model.materialIssues) { var recordOld = db.Queryable() .Where(r => r.S_LOCATION_CODE == "HJQ-" + issue.locationCode.Trim()).First(); if (recordOld != null) { deleteRecordOldList.Add(recordOld); //errList.Add(recordOld); //continue; } // 写入记录表 var record = new TN_Outbound_DataRecord { S_LOCATION_CODE = "HJQ-" + issue.locationCode.Trim(), S_ORDER_NO = issue.withdrawalOrderNo, S_ITEM_CODE = issue.itemCode, S_ITEM_NAME = issue.itemName, S_SHORT_DESC = issue.itemShortDesc, S_ACTUAL_QTY = issue.actualIssuedQty, // 实发数量 S_ISSUED_AMOUNT = issue.issuedAmount, S_SUPPLIER_NAME = issue.supplierName, S_ISSUER = issue.issuer, S_ISSUE_DATE = issue.issueDate, S_STORE_KEEPER = issue.storeKeeper, S_LINE_CODE = issue.lineCode, S_BATCH_NO = issue.batchNo }; insetRecordList.Add(record); //// 查询对应物料 //var cgDetail = db.Queryable // ((l, c, d) => l.S_CODE == c.S_LOC_CODE && c.S_CNTR_CODE == d.S_CNTR_CODE) // .Where(l => l.S_CODE == issue.locationCode) // .Select((l, c, d) => d) // .First(); //if (cgDetail == null) { // err += $"储位码{issue.locationCode}对应的货位物料不存在!"; // continue; //} //cgDetail.S_ITEM_CODE = issue.itemCode; //cgDetail.S_ITEM_NAME = issue.itemName; //cgDetailList.Add(cgDetail); } using (var tran = db.Ado.UseTran()) { if (deleteRecordOldList.Count != 0 && db.Deleteable(deleteRecordOldList).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildErpResult(500, $"删除旧出库记录数据失败:{JsonConvert.SerializeObject(deleteRecordOldList)}"); } if (db.Insertable(insetRecordList).ExecuteCommand() <= 0) { tran.RollbackTran(); return BuildErpResult(500, $"写入出库记录表失败"); } //if (db.Updateable(cgDetailList).ExecuteCommand() <= 0) { // tran.RollbackTran(); // return BuildErpResult(500, $"更改物料信息失败"); //} tran.CommitTran(); return BuildErpResult(0, $"写入出库记录表成功!"); } //if (err != "") { // return BuildErpResult(2, err + "其他信息正常已写入"); //} //return BuildErpResult(0, $"更改物料信息成功"); } catch (Exception ex) { return BuildErpResult(1, $"发生了异常:{ex.Message}"); } } } }