using HH.WCS.Mobox3.pinggao.api; using HH.WCS.Mobox3.pinggao.models.other; using HH.WCS.Mobox3.pinggao.util; using Newtonsoft.Json; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.Remoting.Messaging; using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using static HH.WCS.Mobox3.pinggao.api.ApiModel; using static HH.WCS.Mobox3.pinggao.api.OtherModel; using static HH.WCS.Mobox3.pinggao.util.Settings; namespace HH.WCS.Mobox3.pinggao.wms { /// /// wms管到作业 /// internal class WMSHelper { internal static string GenerateTaskNo() { var id = SYSHelper.GetSerialNumber("作业号", "OP"); var date = DateTime.Now.ToString("yyMMdd"); return $"OP{date}{id.ToString().PadLeft(4, '0')}"; } internal static string GenerateCntrCodeNo() { var id = SYSHelper.GetSerialNumber("托盘号", "TP"); var date = DateTime.Now.ToString("yyMMdd"); return $"TP{date}{id.ToString().PadLeft(4, '0')}"; } internal static string GenerateSortingNo() { var id = SYSHelper.GetSerialNumber("分拣单", "SO"); var date = DateTime.Now.ToString("yyMMdd"); return $"SO{date}{id.ToString().PadLeft(4, '0')}"; } internal static string GenerateShippNo() { var id = SYSHelper.GetSerialNumber("出库单", "OU"); var date = DateTime.Now.ToString("yyMMdd"); return $"OU{date}{id.ToString().PadLeft(4, '0')}"; } internal static string GenerateDistrbutionCntrNo() { var id = SYSHelper.GetSerialNumber("配盘号", "DC"); var date = DateTime.Now.ToString("yyMMdd"); return $"DC{date}{id.ToString().PadLeft(4, '0')}"; } internal static List GetOperationListByState(string state) { var db = new SqlHelper().GetInstance(); return db.Queryable().Where(a => a.S_B_STATE == state).ToList(); } internal static List GetOperationListByState(int state) { var db = new SqlHelper().GetInstance(); return db.Queryable().Where(a => a.N_B_STATE == state).ToList(); } internal static List GetWaitingOperationList() { var db = new SqlHelper().GetInstance(); return db.Queryable().Where(a => a.N_B_STATE == 0 || a.N_B_STATE == 3).ToList(); } internal static PutawayOrder GetPutawayOrder(string no) { var db = new SqlHelper().GetInstance(); return db.Queryable().Where(a => a.S_NO == no).First(); } internal static bool CreatePutawayOrder(PutawayOrder model) { var db = new SqlHelper().GetInstance(); var result = db.Insertable(model).ExecuteCommand() > 0; db.Insertable(model.Details).ExecuteCommand(); return result; } internal static TN_Inbound_Detail GetInboundOrderDetail(string no, string item_code) { try { var db = new SqlHelper().GetInstance(); var inboud= db.Queryable().Where(a => a.S_IO_NO == no && a.S_ITEM_CODE == item_code).First(); return inboud; } catch (Exception ex) { throw; } } internal static void UpdateInboundOrderDetailQty(TN_Inbound_Detail model) { var db = new SqlHelper().GetInstance(); db.Updateable(model).UpdateColumns(it => new { it.F_ACC_B_QTY }).ExecuteCommand(); } internal static PutawayDetail GetPutawayOrderDetail(string no, string item_code) { var db = new SqlHelper().GetInstance(); return db.Queryable().Where(a => a.S_PUTAWAY_NO == no && a.S_ITEM_CODE == item_code).First(); } internal static PutawayDetail GetPutawayOrderDetail(string item_code) { var db = new SqlHelper().GetInstance(); return db.Queryable().Where(a => a.S_ITEM_CODE == item_code && a.F_QTY - a.F_ACC_B_QTY > 0).OrderByDescending(a => a.T_CREATE).First(); } internal static void UpdatePutawayOrderDetailQty(PutawayDetail model) { var db = new SqlHelper().GetInstance(); db.Updateable(model).UpdateColumns(it => new { it.F_ACC_B_QTY }).ExecuteCommand(); } internal static ShippingOrder GetShippingOrder(string no) { var db = new SqlHelper().GetInstance(); return db.Queryable().Includes(a => a.Details).Where(a => a.S_NO == no).First(); } internal static TN_Outbound_Order GetOutboundOrder(string no) { var db = new SqlHelper().GetInstance(); return db.Queryable().Includes(a => a.Details).Where(a => a.S_BS_NO == no).First(); } internal static TN_Inbound_Order GetInboundOrder(string no) { var db = new SqlHelper().GetInstance(); return db.Queryable().Includes(a => a.Details).Where(a => a.S_NO == no).First(); } internal static TN_Supplier GetGYSBMOrder(string no) { var db = new SqlHelper().GetInstance(); return db.Queryable().Includes(a => a.Details).Where(a => a.S_GYSBM == no).First(); } internal static TN_ASN_Order GetASNOrder(string no) { var db = new SqlHelper().GetInstance(); return db.Queryable().Includes(a => a.Details).Where(a => a.S_NO == no).First(); } internal static bool CreateShippingOrder(ShippingOrder model) { var db = new SqlHelper().GetInstance(); var result = db.Insertable(model).ExecuteCommand() > 0; db.Insertable(model.Details).ExecuteCommand(); return result; } internal static bool CreateOutboundOrder(TN_Outbound_Order model) { var db = new SqlHelper().GetInstance(); try { db.BeginTran(); var result = db.Insertable(model).ExecuteCommand() > 0; db.Insertable(model.Details).ExecuteCommand(); db.CommitTran(); return result; } catch (Exception) { db.RollbackTran(); throw; } } internal static bool CreateInboundOrder(TN_Inbound_Order model) { var db = new SqlHelper().GetInstance(); var result = db.Insertable(model).ExecuteCommand() > 0; db.Insertable(model.Details).ExecuteCommand(); return result; } internal static bool CreateASNOrder(TN_ASN_Order model) { LogHelper.Info($"子表长度{model.Details.Count} 数据{JsonConvert.SerializeObject(model.Details)}"); var db = new SqlHelper().GetInstance(); var result = db.Insertable(model).ExecuteCommand() > 0; db.Insertable(model.Details).ExecuteCommand(); return result; } internal static bool CreateSortingOrder(List list) { var res = false; //遍历获取发货单,然后判断库存,如果全都没库存,则不生成分拣单,如果有生成分拣单 //更新波次单,即使只有一个发货单也更新波次单 var db = new SqlHelper().GetInstance(); var sortingOrderNo = ""; SortingOrder sortingOrder = null; try { db.BeginTran(); list.ForEach(a => { var so = db.Queryable().Includes(s => s.Details).Where(s => s.S_NO == a).First(); //判断库存,只有已经入库的才可以计算,码盘的不算,入库后出库途中的也要计算,码盘后默认叫待入库,入库后叫正常 //生成出库任务,只有托盘位置在立库才需要创建出库任务(先写死立库) //只有全部分拣完成才允许回库(一个托盘可能对应多个分拣明细) //查找仓库量表和库区量表,出库单需要定位仓库和库区了,出库定位物理库区就行,入库可能物料库区还要区分逻辑库区 //暂时只查仓库量表(量表如何重置,查找所有查找C_ENABLE=N的,判断如果在仓库中,改成Y,然后统计) //生成分拣单时候增加仓库量表分配量,生成分拣单明细时候,增加库区量表分配量 if (so != null && so.Details.Count > 0) { var fail = true; for (int i = 0; i < so.Details.Count; i++) { var whi = db.Queryable().Where(w => w.S_ITEM_CODE == so.Details[i].S_ITEM_CODE).First(); if (whi != null && whi.F_QTY - whi.F_ALLOC_QTY > 0) { //有货就出 float qty = whi.F_QTY - whi.F_ALLOC_QTY > so.Details[i].F_QTY ? so.Details[i].F_QTY : whi.F_QTY - whi.F_ALLOC_QTY; fail = false; //有可用库存,生成分拣单 if (sortingOrderNo == "") { sortingOrderNo = GenerateSortingNo(); sortingOrder = new SortingOrder { S_NO = sortingOrderNo, S_TYPE = so.S_BS_TYPE, S_SHIPPING_NO = so.S_NO, Composes = new List() }; //创建分拣单 db.Insertable(sortingOrder).ExecuteCommand(); } else { //获取最新分拣单 sortingOrder = db.Queryable().Includes(s => s.Composes).Where(s => s.S_NO == sortingOrderNo).First(); //更新分拣单中的发货单单号 //sortingOrder.S_SHIPPING_NO = sortingOrder.S_SHIPPING_NO + ";" + so.S_NO; sortingOrder.T_MODIFY = DateTime.Now; db.Updateable(sortingOrder).UpdateColumns(it => new { it.S_SHIPPING_NO, it.T_MODIFY }).ExecuteCommand(); } Expression> expression = x => x.S_ITEM_CODE == so.Details[i].S_ITEM_CODE; expression.AndAlso(x => x.S_SORTING_NO == sortingOrder.S_NO); if (!string.IsNullOrEmpty(so.Details[i].S_BATCH_NO)) expression.AndAlso(x => x.S_BATCH_NO == so.Details[i].S_BATCH_NO); if (!string.IsNullOrEmpty(so.Details[i].S_FAC_CODE)) expression.AndAlso(x => x.S_FAC_CODE == so.Details[i].S_FAC_CODE); if (!string.IsNullOrEmpty(so.Details[i].S_ITEM_LOC)) expression.AndAlso(x => x.S_ITEM_LOC == so.Details[i].S_ITEM_LOC); //查询分拣单子表(正常情况还需要增加批次判断) var soc = db.Queryable() .Where(expression) .First(); if (soc == null) { soc = new SortingCompose { S_ITEM_CODE = so.Details[i].S_ITEM_CODE, S_SORTING_NO = sortingOrder.S_NO, F_QTY = qty, N_ROW_NO = sortingOrder.Composes.Count() + 1, S_BATCH_NO = so.Details[i].S_BATCH_NO, S_FAC_CODE = so.Details[i].S_FAC_CODE, S_ITEM_LOC = so.Details[i].S_ITEM_LOC }; //创建分拣单子表 db.Insertable(soc).ExecuteCommand(); } else { soc.F_QTY += qty; soc.T_MODIFY = DateTime.Now; //更新分拣单子表 db.Updateable(soc).UpdateColumns(it => new { it.F_QTY, it.T_MODIFY }).ExecuteCommand(); } //更新仓库量表分配量 //whi.F_ALLOC_QTY += qty; //whi.T_MODIFY = DateTime.Now; //db.Updateable(whi).UpdateColumns(it => new { it.F_ALLOC_QTY, it.T_MODIFY }).ExecuteCommand(); //跟新发货单子表配货数量 so.Details[i].F_ACC_D_QTY += qty; so.Details[i].T_MODIFY = DateTime.Now; db.Updateable(so.Details[i]).UpdateColumns(it => new { it.F_ACC_D_QTY, it.T_MODIFY }).ExecuteCommand(); } } //更新发货单状态 so.N_B_STATE = fail ? 5 : 1; if (fail) { so.S_NOTE = "没有库存"; } so.S_WAVE_CODE = sortingOrderNo; so.T_MODIFY = DateTime.Now; db.Updateable(so).UpdateColumns(it => new { it.N_B_STATE, it.T_MODIFY, it.S_WAVE_CODE, it.S_NOTE }).ExecuteCommand(); } //查找库区内托盘生成托盘明细(包括分拣中)怎么判断库内?查找货位绑定?还是托盘上加标识比较好,如果是整托出的,分拣确认后去掉分拣标识。 //1、只有码盘入库后的才需要加标识,分拣回的不用,分拣回的标识还在,没有变。写死码盘入的完成后加标识,整托分拣的去掉标识,防止后面重新码盘脏数据 //2、或者关联查询库内的,只给分拣出的加标识,每次分拣回再把标识清除了(如果不清除带标识的会很多,还不如全部加标识),整托的清除。 //综合选择还是方案1,这样创建分拣明细,只需要托盘物料两表查询就能定位托盘(如果信息不准,可以重置),方案2需要货位、托盘、物料三表联查 //暂时不计库区,标识用容器表 C_ENABLE 来判断,表示能不能出库 //执行分拣创建任务,遍历分拣明细中的托盘,如果在仓库就出库,如果不在就不用出库 }); //全部分拣单生成之后将分拣单状态设置为开始配货,波次号为发货单 sortingOrder = db.Queryable().Where(s => s.S_NO == sortingOrderNo).First(); sortingOrder.N_B_STATE = 1; sortingOrder.T_MODIFY = DateTime.Now; db.Updateable(sortingOrder).UpdateColumns(it => new { it.N_B_STATE, it.T_MODIFY }).ExecuteCommand(); db.CommitTran(); res = true; } catch (Exception ex) { Console.WriteLine(ex.Message); db.RollbackTran(); } return res; } internal static bool CreatOpenation(Location startLoc, Location endLoc, string trayNo, string Stype, int Ntype) { var res = false; var db = new SqlHelper().GetInstance(); var optask = new WMSTask { S_CODE = WMSHelper.GenerateTaskNo(), S_START_WH = startLoc.S_WH_CODE, S_START_AREA = startLoc.S_AREA_CODE, S_START_LOC = startLoc.S_CODE, S_END_LOC = endLoc.S_CODE, S_END_AREA = endLoc.S_AREA_CODE, S_END_WH = endLoc.S_WH_CODE, S_TYPE = GetType(Ntype), N_TYPE = Ntype, N_B_STATE = 0, S_CNTR_CODE = trayNo, S_OP_DEF_NAME = Stype }; res = db.Insertable(optask).ExecuteCommand() > 0; if (res) { LocationHelper.LockLoc(startLoc.S_CODE, 2); LocationHelper.LockLoc(endLoc.S_CODE, 1); } return res; } private static string GetType(int ntype) { string result = ""; switch (ntype) { case 1: result = "入库"; break; case 2: result = "出库"; break; case 3: result = "转运"; break; } return result; } internal static void OnShelves(WCSTask task, int action) { var db = new SqlHelper().GetInstance(); var s_action = ""; if (action == 1) { s_action = "上架"; } else { s_action = "下架"; } try { var itemlist = db.Queryable().Where(a => a.S_CNTR_CODE == task.S_CNTR_CODE).ToList(); if (itemlist.Count > 0) { foreach (var item in itemlist) { var info = new TN_OnOff_Shelves { S_NO = task.S_OP_CODE, N_ACTION = action, S_ACTION = s_action, S_ITEM_CODE = item.S_ITEM_CODE, S_ITEM_NAME = item.S_ITEM_NAME, S_LOC_CODE = task.S_END_LOC, S_AREA_CODE = task.S_END_AREA, S_CNTR_CODE = task.S_CNTR_CODE, S_BATCH_NO = item.S_BATCH_NO, S_SERIAL_NO = item.S_SERIAL_NO, //D_PRD_DATE = item.D_PRD_DATE, F_QTY = item.F_QTY }; db.Insertable(info).ExecuteCommand(); } } } catch (Exception ex) { LogHelper.Error($"上架记录添加异常 异常信息={ex.Message}", ex); } } internal static void addOnShelves(TN_Outbound_Order task,string cntr_code, int action) { var db = new SqlHelper().GetInstance(); var s_action = ""; if (action == 1) { s_action = "上架"; } else { s_action = "下架"; } try { var itemlist = db.Queryable().Where(a => a.S_CNTR_CODE == cntr_code).ToList(); if (itemlist.Count > 0) { foreach (var item in itemlist) { var info = new TN_OnOff_Shelves { S_NO = task.S_NO, N_ACTION = action, S_ACTION = s_action, S_ITEM_CODE = item.S_ITEM_CODE, S_ITEM_NAME = item.S_ITEM_NAME, S_LOC_CODE = task.S_END_LOC, S_AREA_CODE = task.S_END_AREA, S_CNTR_CODE = cntr_code, S_BATCH_NO = item.S_BATCH_NO, S_SERIAL_NO = item.S_SERIAL_NO, //D_PRD_DATE = item.D_PRD_DATE, F_QTY = item.F_QTY }; db.Insertable(info).ExecuteCommand(); } } } catch (Exception ex) { LogHelper.Error($"上架记录添加异常 异常信息={ex.Message}", ex); } } internal static void AddChange(WCSTask task) { var db = new SqlHelper().GetInstance(); db.Updateable().SetColumns(it => new Container { C_ENABLE = "Y" }).Where(it => it.S_CODE == task.S_CNTR_CODE).ExecuteCommand(); var result = true; try { var itemlist = db.Queryable().Where(a => a.S_CNTR_CODE == task.S_CNTR_CODE).ToList(); if (itemlist.Count > 0) { var url = Settings.MoboxSeverUrl + "inventory/AddChange"; //仓库量表升量 var req = new AddChangeModel { op_type = 5 }; //库区量表升量 var req2 = new AddChangeModel { op_type = 6 }; itemlist.ForEach(a => { LogHelper.Info($"填充数据"); LogHelper.Info($"添加仓库量表数据 仓库{task.S_END_WH} 物料编码{a.S_ITEM_CODE} 物料名称{a.S_ITEM_NAME} 数量{a.F_QTY}"); req.item_info.Add(new AddChangeModel.itemModel { wh_code = task.S_END_WH, item_code = a.S_ITEM_CODE, item_name = a.S_ITEM_NAME, qty = a.F_QTY }); LogHelper.Info($"添加库区量表数据 库区{task.S_END_AREA} 物料编码{a.S_ITEM_CODE} 物料名称{a.S_ITEM_NAME} 数量{a.F_QTY}"); req2.item_info.Add(new AddChangeModel.itemModel { wh_code = task.S_END_WH, area_code = task.S_END_AREA, item_code = a.S_ITEM_CODE, item_name = a.S_ITEM_NAME, qty = a.F_QTY }); }); var reqData = JsonConvert.SerializeObject(req); var AppKey = Settings.AppKey; var AppSecret = Settings.AppSecret; var ReqTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); //var ReqTime = GetTimeStamp(DateTime.Now.AddHours(-8), 1, 2); LogHelper.Info($"加密前 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime}"); var ReqVerify = GetMd5FromString(AppKey + AppSecret + ReqTime); LogHelper.Info($"加密后 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime} ReqVerify={ReqVerify} url={url} req={reqData}"); var res = new HttpHelper().WebPost(url, reqData, "application/json", AppKey, ReqTime, ReqVerify); if (!string.IsNullOrEmpty(res)) { LogHelper.Info($"mobox 仓库升量接口返回 {res}"); var moboxres = JsonConvert.DeserializeObject(res); if (moboxres.err_code != 0) { result = false; } } else { LogHelper.Info($"mobox 仓库升量接口返回为空"); result = false; } var reqData2 = JsonConvert.SerializeObject(req2); var ReqTime2 = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); //var ReqTime2 = GetTimeStamp(DateTime.Now.AddHours(-8), 1, 2); LogHelper.Info($"加密前 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime2}"); var ReqVerify2 = GetMd5FromString(AppKey + AppSecret + ReqTime2); LogHelper.Info($"加密后 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime2} ReqVerify={ReqVerify2} url={url} req={reqData2}"); var res2 = new HttpHelper().WebPost(url, reqData2, "application/json", AppKey, ReqTime2, ReqVerify2); if (!string.IsNullOrEmpty(res2)) { LogHelper.Info($"mobox 库区升量接口返回 {res2}"); var moboxres = JsonConvert.DeserializeObject(res); if (moboxres.err_code != 0) { result = false; } } else { LogHelper.Info($"mobox 库区升量接口返回为空"); result = false; } if (result) OnShelves(task, 1); } else LogHelper.Info($"托盘{task.S_CNTR_CODE} 在容器货品明细中找不到数据"); } catch (Exception ex) { LogHelper.Error($"仓库升量异常 异常信息={ex.Message}", ex); } } /// /// 起始仓库 库区 升量 /// /// internal static void AddChangeStart(WCSTask task) { var db = new SqlHelper().GetInstance(); var result = true; try { var itemlist = db.Queryable().Where(a => a.S_CNTR_CODE == task.S_CNTR_CODE).ToList(); if (itemlist.Count > 0) { var url = Settings.MoboxSeverUrl + "inventory/AddChange"; //仓库量表升量 var req = new AddChangeModel { op_type = 5 }; //库区量表升量 var req2 = new AddChangeModel { op_type = 6 }; itemlist.ForEach(a => { LogHelper.Info($"填充数据"); LogHelper.Info($"添加仓库量表数据 仓库{task.S_END_WH} 物料编码{a.S_ITEM_CODE} 物料名称{a.S_ITEM_NAME} 数量{a.F_QTY}"); req.item_info.Add(new AddChangeModel.itemModel { wh_code = task.S_END_WH, item_code = a.S_ITEM_CODE, item_name = a.S_ITEM_NAME, qty = a.F_QTY }); LogHelper.Info($"添加库区量表数据 库区{task.S_END_AREA} 物料编码{a.S_ITEM_CODE} 物料名称{a.S_ITEM_NAME} 数量{a.F_QTY}"); req2.item_info.Add(new AddChangeModel.itemModel { wh_code = task.S_END_WH, area_code = task.S_END_AREA, item_code = a.S_ITEM_CODE, item_name = a.S_ITEM_NAME, qty = a.F_QTY }); }); var reqData = JsonConvert.SerializeObject(req); var AppKey = Settings.AppKey; var AppSecret = Settings.AppSecret; var ReqTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); //var ReqTime = GetTimeStamp(DateTime.Now.AddHours(-8), 1, 2); LogHelper.Info($"加密前 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime}"); var ReqVerify = GetMd5FromString(AppKey + AppSecret + ReqTime); LogHelper.Info($"加密后 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime} ReqVerify={ReqVerify} url={url} req={reqData}"); var res = new HttpHelper().WebPost(url, reqData, "application/json", AppKey, ReqTime, ReqVerify); if (!string.IsNullOrEmpty(res)) { LogHelper.Info($"mobox 仓库升量接口返回 {res}"); var moboxres = JsonConvert.DeserializeObject(res); if (moboxres.err_code != 0) { result = false; } } else { LogHelper.Info($"mobox 仓库升量接口返回为空"); result = false; } var reqData2 = JsonConvert.SerializeObject(req2); var ReqTime2 = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); //var ReqTime2 = GetTimeStamp(DateTime.Now.AddHours(-8), 1, 2); LogHelper.Info($"加密前 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime2}"); var ReqVerify2 = GetMd5FromString(AppKey + AppSecret + ReqTime2); LogHelper.Info($"加密后 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime2} ReqVerify={ReqVerify2} url={url} req={reqData2}"); var res2 = new HttpHelper().WebPost(url, reqData2, "application/json", AppKey, ReqTime2, ReqVerify2); if (!string.IsNullOrEmpty(res2)) { LogHelper.Info($"mobox 库区升量接口返回 {res2}"); var moboxres = JsonConvert.DeserializeObject(res); if (moboxres.err_code != 0) { result = false; } } else { LogHelper.Info($"mobox 库区升量接口返回为空"); result = false; } if (result) OnShelves(task, 1); } else LogHelper.Info($"托盘{task.S_CNTR_CODE} 在容器货品明细中找不到数据"); } catch (Exception ex) { LogHelper.Error($"仓库升量异常 异常信息={ex.Message}", ex); } } internal static void DeleteChange(WCSTask task) { var db = new SqlHelper().GetInstance(); var result = true; try { var wmstask = db.Queryable().Where(a => a.S_CODE == task.S_OP_CODE).First(); if (wmstask != null) { var itemlist = db.Queryable().Where(a => a.S_CNTR_CODE == task.S_CNTR_CODE).ToList(); if (itemlist.Count > 0) { var url = Settings.MoboxSeverUrl + "inventory/AddChange"; //仓库量表升量 var req = new AddChangeModel { op_type = 4 }; //库区量表升量 var req2 = new AddChangeModel { op_type = 7 }; itemlist.ForEach(a => { LogHelper.Info($"填充数据"); LogHelper.Info($"减仓库量表数据 仓库{task.S_END_WH} 物料编码{a.S_ITEM_CODE} 物料名称{a.S_ITEM_NAME} 数量{a.F_QTY}"); req.item_info.Add(new AddChangeModel.itemModel { wh_code = wmstask.S_START_WH, item_code = a.S_ITEM_CODE, item_name = a.S_ITEM_NAME, qty = a.F_QTY }); LogHelper.Info($"减库区量表数据 库区{task.S_END_AREA} 物料编码{a.S_ITEM_CODE} 物料名称{a.S_ITEM_NAME} 数量{a.F_QTY}"); req2.item_info.Add(new AddChangeModel.itemModel { wh_code = wmstask.S_START_WH, area_code = wmstask.S_START_AREA, item_code = a.S_ITEM_CODE, item_name = a.S_ITEM_NAME, qty = a.F_QTY }); }); var reqData = JsonConvert.SerializeObject(req); var AppKey = Settings.AppKey; var AppSecret = Settings.AppSecret; var ReqTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); //var ReqTime = GetTimeStamp(DateTime.Now.AddHours(-8), 1, 2); LogHelper.Info($"加密前 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime}"); var ReqVerify = GetMd5FromString(AppKey + AppSecret + ReqTime); LogHelper.Info($"加密后 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime} ReqVerify={ReqVerify} url={url} req={reqData}"); var res = new HttpHelper().WebPost(url, reqData, "application/json", AppKey, ReqTime, ReqVerify); if (!string.IsNullOrEmpty(res)) { LogHelper.Info($"mobox 仓库降量接口返回 {res}"); var moboxres = JsonConvert.DeserializeObject(res); if (moboxres.err_code != 0) { result = false; } } else { LogHelper.Info($"mobox 仓库降量接口返回为空"); result = false; } var reqData2 = JsonConvert.SerializeObject(req2); var ReqTime2 = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); //var ReqTime2 = GetTimeStamp(DateTime.Now.AddHours(-8), 1, 2); LogHelper.Info($"加密前 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime2}"); var ReqVerify2 = GetMd5FromString(AppKey + AppSecret + ReqTime2); LogHelper.Info($"加密后 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime2} ReqVerify={ReqVerify2} url={url} req={reqData2}"); var res2 = new HttpHelper().WebPost(url, reqData2, "application/json", AppKey, ReqTime2, ReqVerify2); if (!string.IsNullOrEmpty(res2)) { LogHelper.Info($"mobox 库区降量接口返回 {res2}"); var moboxres = JsonConvert.DeserializeObject(res); if (moboxres.err_code != 0) { result = false; } } else { LogHelper.Info($"mobox 库区降量接口返回为空"); result = false; } if (result) OnShelves(task, 2); } else LogHelper.Info($"托盘{task.S_CNTR_CODE} 在容器货品明细中找不到数据"); } else LogHelper.Info($"未找到任务{task.S_CODE} 对应的作业"); } catch (Exception ex) { LogHelper.Error($"仓库江量异常 异常信息={ex.Message}", ex); } } internal static void QsDeleteChange(WCSTask task) { var db = new SqlHelper().GetInstance(); var result = true; try { var wmstask = db.Queryable().Where(a => a.S_CODE == task.S_OP_CODE).First(); if (wmstask != null) { var itemlist = db.Queryable().Where(a => a.S_CNTR_CODE == task.S_CNTR_CODE).ToList(); if (itemlist.Count > 0) { var url = Settings.MoboxSeverUrl + "inventory/AddChange"; //仓库量表升量 var req = new AddChangeModel { op_type = 4 }; //库区量表升量 var req2 = new AddChangeModel { op_type = 7 }; itemlist.ForEach(a => { LogHelper.Info($"填充数据"); LogHelper.Info($"减仓库量表数据 仓库{task.S_END_WH} 物料编码{a.S_ITEM_CODE} 物料名称{a.S_ITEM_NAME} 数量{a.F_QTY}"); req.item_info.Add(new AddChangeModel.itemModel { wh_code = "cangku", item_code = a.S_ITEM_CODE, item_name = a.S_ITEM_NAME, qty = a.F_QTY }); LogHelper.Info($"减库区量表数据 库区{task.S_END_AREA} 物料编码{a.S_ITEM_CODE} 物料名称{a.S_ITEM_NAME} 数量{a.F_QTY}"); req2.item_info.Add(new AddChangeModel.itemModel { wh_code = "cangku", area_code = "kuqu", item_code = a.S_ITEM_CODE, item_name = a.S_ITEM_NAME, qty = a.F_QTY }); }); var reqData = JsonConvert.SerializeObject(req); var AppKey = Settings.AppKey; var AppSecret = Settings.AppSecret; var ReqTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); //var ReqTime = GetTimeStamp(DateTime.Now.AddHours(-8), 1, 2); LogHelper.Info($"加密前 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime}"); var ReqVerify = GetMd5FromString(AppKey + AppSecret + ReqTime); LogHelper.Info($"加密后 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime} ReqVerify={ReqVerify} url={url} req={reqData}"); var res = new HttpHelper().WebPost(url, reqData, "application/json", AppKey, ReqTime, ReqVerify); if (!string.IsNullOrEmpty(res)) { LogHelper.Info($"mobox 仓库降量接口返回 {res}"); var moboxres = JsonConvert.DeserializeObject(res); if (moboxres.err_code != 0) { result = false; } } else { LogHelper.Info($"mobox 仓库降量接口返回为空"); result = false; } var reqData2 = JsonConvert.SerializeObject(req2); var ReqTime2 = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(); //var ReqTime2 = GetTimeStamp(DateTime.Now.AddHours(-8), 1, 2); LogHelper.Info($"加密前 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime2}"); var ReqVerify2 = GetMd5FromString(AppKey + AppSecret + ReqTime2); LogHelper.Info($"加密后 AppKey={AppKey} AppSecret={AppSecret} ReqTime={ReqTime2} ReqVerify={ReqVerify2} url={url} req={reqData2}"); var res2 = new HttpHelper().WebPost(url, reqData2, "application/json", AppKey, ReqTime2, ReqVerify2); if (!string.IsNullOrEmpty(res2)) { LogHelper.Info($"mobox 库区降量接口返回 {res2}"); var moboxres = JsonConvert.DeserializeObject(res); if (moboxres.err_code != 0) { result = false; } } else { LogHelper.Info($"mobox 库区降量接口返回为空"); result = false; } if (result) OnShelves(task, 2); } else LogHelper.Info($"托盘{task.S_CNTR_CODE} 在容器货品明细中找不到数据"); } else LogHelper.Info($"未找到任务{task.S_CODE} 对应的作业"); } catch (Exception ex) { LogHelper.Error($"仓库江量异常 异常信息={ex.Message}", ex); } } public class moboxres { public int err_code { get; set; } public string err_msg { get; set; } = ""; } /// /// 任务信息接口--获取时间戳 /// /// 数据位数:值:32|64 含义:32位|64位 /// 获取时间类型:值:1|2 含义:1-秒级 2-毫秒级 /// 获取时间Utc类型:值:1|2 含义:1-本地时间 2-Utc时间 /// public static string GetTimeStamp(DateTime dateTime, int DataBitType, int TimeType) { string timeStamp = ""; //时间戳打印 TimeSpan ts = dateTime - new DateTime(1970, 1, 1, 0, 0, 0, 0);//时间戳获取 double tsTime = TimeType == 1 ? ts.TotalSeconds : ts.TotalMilliseconds;//秒级|毫秒级时间获取 string TimeTypeInfo = TimeType == 1 ? "秒级" : "毫秒级"; timeStamp = DataBitType == 32 ? Convert.ToInt32(tsTime).ToString() : Convert.ToInt64(tsTime).ToString(); //double result = 0; //result = DataBitType == 32 ? Convert.ToInt32(tsTime) : Convert.ToInt64(tsTime); return timeStamp; } /// /// MD5加密 /// /// /// public static string GetMd5FromString(string sInput) { var lstData = Encoding.GetEncoding("utf-8").GetBytes(sInput); var lstHash = new MD5CryptoServiceProvider().ComputeHash(lstData); var result = new StringBuilder(32); for (int i = 0; i < lstHash.Length; i++) { result.Append(lstHash[i].ToString("x2").ToUpper()); } return result.ToString(); } public class AddChangeModel { /// /// 5 - 仓库加存储量,用于 入库完成 /// 6 - 库区加存储量,用于库区入库完成, /// 7 - 库区减存储、分配量,用于 库区出库完成 /// 8 - 仓库减存储量,9 - 库区减存储量 /// 10 - 仓库减分配量,用于 配货后取消, /// 11 - 库区减分配量,用于 配货后取消 /// public int op_type { get; set; } public List item_info { get; set; } = new List(); public class itemModel { public string wh_code { get; set; } = ""; public string area_code { get; set; } = ""; public string loc_code { get; set; } = ""; public string item_code { get; set; } public string item_name { get; set; } public float qty { get; set; } } } internal static void End(WCSTask task) { var db = new SqlHelper().GetInstance(); var wmsTask = db.Queryable().Where(a => a.S_CODE == task.S_OP_CODE).First(); //修改作业状态 重新启动 wmsTask.N_B_STATE = 2; WMSHelper.UpdateTaskState(wmsTask); WCSHelper.UpdateStorStatus(task.S_CNTR_CODE, 4); } internal static void Fail(WCSTask task) { var db = new SqlHelper().GetInstance(); var wmsTask = db.Queryable().Where(a => a.S_CODE == task.S_OP_CODE).First(); //修改作业状态 重新启动 wmsTask.N_B_STATE = 5; wmsTask.S_B_STATE = "取消"; WMSHelper.UpdateTaskState(wmsTask); //WCSHelper.UpdateStorStatus(task.S_CNTR_CODE, 4); } internal static void EndTn(string S_CNTR_CODE) { var db = new SqlHelper().GetInstance(); var item = db.Queryable().Where(a => a.S_CNTR_CODE == S_CNTR_CODE).First(); //修改作业状态 重新启动 item.N_B_STATE = 2; item.S_B_STATE = "作业完成"; db.Updateable(item).UpdateColumns(it => new { it.S_B_STATE, it.N_B_STATE }).ExecuteCommand(); } internal static List GetSortingDetailByCntr(string cntr) { var db = new SqlHelper().GetInstance(); var result = db.Queryable().Where(a => a.S_CNTR_CODE == cntr && a.N_B_STATE == 1).ToList(); return result; } internal static bool CreateWmsTask(WMSTask wmsTask) { try { var db = new SqlHelper().GetInstance(); return db.Insertable(wmsTask).ExecuteCommand() > 0; } catch (Exception ex) { Console.WriteLine(ex.Message); throw; } } public static bool CreateOpTask(string startLoc, string endLoc, string sType, string taskType, string trayCode) { bool result = false; int nType = sType == "入库" ? 1 : 2; var wmsTask = new WMSTask { S_CNTR_CODE = trayCode, S_CODE = WMSHelper.GenerateTaskNo(), S_START_LOC = startLoc, S_END_LOC = endLoc, N_TYPE = nType, S_TYPE = sType, S_OP_DEF_CODE = "", S_OP_DEF_NAME = taskType }; result = WMSHelper.CreateWmsTask(wmsTask); if (result) { LocationHelper.LockLoc(startLoc, 2); LocationHelper.LockLoc(endLoc, 1); LogHelper.Info($"创建作业成功,作业号{wmsTask.S_CODE}"); } return result; } internal static WMSTask GetWmsTaskByCntr(string cntr, bool active = true) { WMSTask result = null; var db = new SqlHelper().GetInstance(); if (active) { result = db.Queryable().Where(a => a.S_CNTR_CODE.Contains(cntr) && a.N_B_STATE < 2).First(); } else { result = db.Queryable().Where(a => a.S_CNTR_CODE.Contains(cntr)).First(); } return result; } internal static Location GetEnd(WMSTask a) { LogHelper.Info($"作业{a.S_CODE} 获取终点"); Location result = null; //try //{ var db = new SqlHelper().GetInstance(); var start = db.Queryable().Where(it => it.S_CODE == a.S_START_LOC).First(); if (!string.IsNullOrEmpty(a.S_END_LOC)) { LogHelper.Info($"作业终点有值 上锁"); result = db.Queryable().Where(it => it.S_CODE == a.S_END_LOC).First(); //这里可以作为提前上锁 //检查货位是否上过锁了 是否需要重新上锁 LocationHelper.LockLoc(a.S_END_LOC, 1); } else { //终点为空 选取终点库内位置 if (a.N_TYPE == 2) { LogHelper.Info($"作业终点不为接驳位 查找库区{a.S_END_AREA} 可用货位"); //其他库区 var endlist = db.Queryable() .Where(it => it.S_AREA_CODE == a.S_END_AREA && it.N_CURRENT_NUM < it.N_CAPACITY) .OrderBy(it => it.N_COL) .PartitionBy(it => it.N_ROW) .Take(1) .ToList(); LogHelper.Info($"符合条件的数量{endlist.Count}"); foreach (var item in endlist) { var lockinfo = db.Queryable().Where(it => it.N_LOCK_STATE != 0 && it.S_AREA_CODE == item.S_AREA_CODE && it.N_ROW == item.N_ROW).First(); if (lockinfo == null) { result = item; a.S_END_LOC = item.S_CODE; break; } else LogHelper.Info($"货位{lockinfo.S_CODE} 有锁 当前排不可使用"); } } else { LogHelper.Info($"入库任务 终点不为立库"); //终点不为立库的任务 //其他库区 var endlist = db.Queryable() .Where(it => it.S_AREA_CODE == a.S_END_AREA && it.N_CURRENT_NUM < it.N_CAPACITY) .OrderBy(it => it.N_COL) .PartitionBy(it => it.N_ROW) .Take(1) .ToList(); foreach (var item in endlist) { var lockinfo = db.Queryable().Where(it => it.N_LOCK_STATE != 0 && it.S_AREA_CODE == item.S_AREA_CODE && it.N_ROW == item.N_ROW).First(); if (lockinfo == null) { result = item; a.S_END_LOC = result.S_CODE; break; } } } } return result; } internal static Location GetStart(WMSTask a) { throw new NotImplementedException(); } internal static void UpdateTaskState(WMSTask task) { var db = new SqlHelper().GetInstance(); task.T_MODIFY = DateTime.Now; task.S_B_STATE = WMSTask.GetStateStr(task.N_B_STATE); db.Updateable(task).UpdateColumns(a => new { a.N_B_STATE, a.S_B_STATE, a.T_MODIFY }).ExecuteCommand(); } internal static bool UpdateTaskEnd(WMSTask a) { var db = new SqlHelper().GetInstance(); a.T_MODIFY = DateTime.Now; return db.Updateable(a).UpdateColumns(it => new { it.S_END_LOC, it.T_MODIFY }).ExecuteCommand() > 0; } internal static WMSTask GetWmsTask(string code) { var db = new SqlHelper().GetInstance(); return db.Queryable().Where(a => a.S_CODE == code).First(); } internal static void CreateSortingOrderDetail(string so_no) { //分拣单配货 var db = new SqlHelper().GetInstance(); var so = db.Queryable().Includes(a => a.Composes).Where(a => a.S_NO == so_no && (a.N_B_STATE == 1 || a.N_B_STATE == 20)).First();// if (so != null && so.Composes.Count > 0) { db.BeginTran(); try { int rowNo = 1; so.Composes.ForEach(a => { Expression> expression = x => x.S_ITEM_CODE == a.S_ITEM_CODE; expression.AndAlso(x => x.Cntr.C_ENABLE == "Y"); expression.AndAlso(x => (x.F_QTY - x.F_ALLOC_QTY) > (a.F_QTY - a.F_ACC_S_QTY)); expression.AndAlso(x => (x.F_QTY - x.F_ALLOC_QTY) / 2 < (a.F_QTY - a.F_ACC_S_QTY)); if (!string.IsNullOrEmpty(a.S_BATCH_NO)) expression.AndAlso(x => x.S_BATCH_NO == a.S_BATCH_NO); if (!string.IsNullOrEmpty(a.S_FAC_CODE)) expression.AndAlso(x => x.S_OWNER == a.S_FAC_CODE); //if (!string.IsNullOrEmpty(a.S_ITEM_LOC)) expression.AndAlso(x => x.S_ERP_WH_CODE == a.S_ITEM_LOC); var result = false; var fjlist = db.Queryable().Includes(c => c.Cntr) .Where(expression) .OrderBy(c => c.T_CREATE) .ToList(); for (int i = 0; i < fjlist.Count; i++) { //检测这个托盘物料是否单一 var cir = fjlist[i]; var isfj = db.Queryable().Where(c => c.S_CNTR_CODE == cir.S_CNTR_CODE && c.C_REVERSE == "Y" && c.N_B_STATE < 2).First(); if (isfj == null) { var itemlist = db.Queryable().Where(c => c.S_CNTR_CODE == cir.S_CNTR_CODE && c.F_QTY > 0).ToList(); if (itemlist.Count == 1) { result = true; var sd = new SortingDetail { N_ROW_NO = rowNo, S_BATCH_NO = a.S_BATCH_NO, S_ITEM_CODE = a.S_ITEM_CODE, S_CNTR_CODE = cir.S_CNTR_CODE, S_SORTING_NO = a.S_SORTING_NO, S_FAC_CODE = a.S_FAC_CODE, S_ITEM_LOC = a.S_ITEM_LOC, F_QTY = (itemlist[0].F_QTY - itemlist[0].F_ALLOC_QTY) - (a.F_QTY - a.F_ACC_S_QTY), C_REVERSE = "Y" }; db.Insertable(sd).ExecuteCommand(); rowNo++; //更新容器货品表分配量 cir.F_ALLOC_QTY += sd.F_QTY; cir.T_MODIFY = DateTime.Now; db.Updateable(cir).UpdateColumns(it => new { it.F_ALLOC_QTY, it.T_MODIFY }).ExecuteCommand(); //更新分拣单子表的量 a.F_ACC_S_QTY += a.F_QTY - a.F_ACC_S_QTY; a.T_MODIFY = DateTime.Now; db.Updateable(a).UpdateColumns(it => new { it.F_ACC_S_QTY, it.T_MODIFY }).ExecuteCommand(); var whi = db.Queryable().Where(it => it.S_ITEM_CODE == a.S_ITEM_CODE).First(); if (whi != null) { whi.F_ALLOC_QTY += a.F_QTY - a.F_ACC_S_QTY; whi.T_MODIFY = DateTime.Now; db.Updateable(whi).UpdateColumns(it => new { it.F_ALLOC_QTY, it.T_MODIFY }).ExecuteCommand(); } break; } } } Expression> expression1 = x => x.S_ITEM_CODE == a.S_ITEM_CODE; expression1.AndAlso(x => x.Cntr.C_ENABLE == "Y"); expression1.AndAlso(x => (x.F_QTY - x.F_ALLOC_QTY) > 0); if (!string.IsNullOrEmpty(a.S_BATCH_NO)) expression1.AndAlso(x => x.S_BATCH_NO == a.S_BATCH_NO); if (!string.IsNullOrEmpty(a.S_FAC_CODE)) expression1.AndAlso(x => x.S_OWNER == a.S_FAC_CODE); //if (!string.IsNullOrEmpty(a.S_ITEM_LOC)) expression1.AndAlso(x => x.S_ERP_WH_CODE == a.S_ITEM_LOC); if (!result) { //按分拣单子表去配货,查找可用托盘(先查所有符合的,后面再优化) var cirList = db.Queryable().Includes(c => c.Cntr) .Where(expression1) .OrderBy(c => c.T_CREATE) .ToList(); for (int i = 0; i < cirList.Count; i++) { var cir = cirList[i]; var isfj = db.Queryable().Where(c => c.S_CNTR_CODE == cir.S_CNTR_CODE && c.C_REVERSE == "Y" && c.N_B_STATE < 2).First(); if (isfj == null) { var sd = new SortingDetail { N_ROW_NO = rowNo, S_BATCH_NO = a.S_BATCH_NO, S_ITEM_CODE = a.S_ITEM_CODE, S_CNTR_CODE = cir.S_CNTR_CODE, S_FAC_CODE = a.S_FAC_CODE, S_ITEM_LOC = a.S_ITEM_LOC, S_SORTING_NO = a.S_SORTING_NO }; bool needBreak = false; if (cir.F_QTY - cir.F_ALLOC_QTY >= (a.F_QTY - a.F_ACC_S_QTY)) { sd.F_QTY = a.F_QTY - a.F_ACC_S_QTY; needBreak = true; } else { //生成分拣明细,继续创建 sd.F_QTY = cir.F_QTY - cir.F_ALLOC_QTY; } db.Insertable(sd).ExecuteCommand(); rowNo++; //更新容器货品表分配量 cir.F_ALLOC_QTY += sd.F_QTY; cir.T_MODIFY = DateTime.Now; db.Updateable(cir).UpdateColumns(it => new { it.F_ALLOC_QTY, it.T_MODIFY }).ExecuteCommand(); //更新分拣单子表的量 a.F_ACC_S_QTY += sd.F_QTY; a.T_MODIFY = DateTime.Now; db.Updateable(a).UpdateColumns(it => new { it.F_ACC_S_QTY, it.T_MODIFY }).ExecuteCommand(); var whi = db.Queryable().Where(it => it.S_ITEM_CODE == a.S_ITEM_CODE).First(); if (whi != null) { whi.F_ALLOC_QTY += sd.F_QTY; whi.T_MODIFY = DateTime.Now; db.Updateable(whi).UpdateColumns(it => new { it.F_ALLOC_QTY, it.T_MODIFY }).ExecuteCommand(); } if (needBreak) { break; } } } } }); //全部分拣单子表生成分拣明细,修改分拣单状态为配货完成(反正仓库的货能配的都配完了,除非数据有异常) so.N_B_STATE = 2; so.T_MODIFY = DateTime.Now; db.Updateable(so).UpdateColumns(it => new { it.N_B_STATE, it.T_MODIFY }).ExecuteCommand(); db.CommitTran(); } catch (Exception ex) { Console.WriteLine(ex.Message); db.RollbackTran(); } } } /// /// 获取开始配货的分拣单,一次性生成分拣明细,避免生成一半再生成,所以创建分拣明细的时候加上事务 /// /// internal static List GetWaitingSortingOrderList() { var db = new SqlHelper().GetInstance(); return db.Queryable().Includes(a => a.Composes).Where(a => a.N_B_STATE == 1 || a.N_B_STATE == 20).ToList(); } /// /// 获取配货完成的分拣单,每个分拣单单独创建分拣作业 /// /// internal static List GetWaitingSortingOperationList() { var db = new SqlHelper().GetInstance(); return db.Queryable().Where(a => a.N_B_STATE == 1 && a.S_BS_TYPE != "人工库出库").ToList(); } /// ///单个分拣单的分拣明细创建作业 /// internal static void CreateSortingOperation(SortingOrder so) { var list = so.Details.Where(a => a.N_B_STATE == 0).ToList(); var db = new SqlHelper().GetInstance(); if (list.Count > 0) { try { db.BeginTran(); list.GroupBy(g => g.S_CNTR_CODE).ToList().ForEach(g => { var cntr = g.Key; var sdList = g.ToList(); //查询托盘货位,查到了创建任务,查不到说明在别的分拣作业中,不创建任务,需要回库后重新创建 var lcr = db.Queryable().Where(c => c.S_CNTR_CODE == cntr).First(); if (lcr != null) { var area = db.Queryable().Where(c => c.S_CODE == lcr.S_LOC_CODE).First(); if (area != null) { //判断托盘是否已经创建任务了,可能多个分拣明细是同一个托盘,如果创建任务了,其它分拣的要稍后,只出一次人工会搞不清楚是哪个分拣单的 var wmsTask = db.Queryable().Where(op => op.S_CNTR_CODE.Contains(cntr) && op.N_B_STATE < 2).First(); if (wmsTask == null) { wmsTask = new WMSTask { S_CNTR_CODE = cntr, S_CODE = WMSHelper.GenerateTaskNo(), S_START_LOC = lcr.S_LOC_CODE, S_END_LOC = "", N_TYPE = 2, S_TYPE = WMSTask.GetTypeStr(2), //S_TYPE = so.S_TYPE, S_OP_DEF_CODE = "", S_OP_DEF_NAME = so.S_TYPE }; if (db.Insertable(wmsTask).ExecuteCommand() > 0) { LocationHelper.LockLoc(lcr.S_LOC_CODE, 2); } sdList.ForEach(a => { a.N_B_STATE = 1; a.T_MODIFY = DateTime.Now; db.Updateable(a).UpdateColumns(it => new { it.N_B_STATE, it.T_MODIFY }).ExecuteCommand(); }); } } } //修改分拣单状态为开始作业(不代表作业全部创建了,因为有的托盘可能已经被占用了) so.N_B_STATE = 3; //如果所有的作业都已经创建了,就设置为作业已经创建 if (so.Details.Count(s => s.N_B_STATE == 0) == 0) { so.N_B_STATE = 4; } so.T_MODIFY = DateTime.Now; db.Updateable(so).UpdateColumns(it => new { it.N_B_STATE, it.T_MODIFY }).ExecuteCommand(); }); db.CommitTran(); } catch (Exception ex) { Console.WriteLine(ex.Message); db.RollbackTran(); } } } internal static void SortingConfrim(List models) { if (models.Count > 0) { var db = new SqlHelper().GetInstance(); try { db.BeginTran(); //先查寻该分拣单所有执行中的分拣明细 var sdList = db.Queryable().Where(a => a.S_SORTING_NO == models[0].sortNo).ToList(); var soList = db.Queryable().Includes(a => a.Details).Where(a => a.S_WAVE_CODE == models[0].sortNo).ToList(); //查出所有关联的发货单 models.ForEach(a => { Expression> expression = x => x.S_ITEM_CODE == a.itemCode; if (!string.IsNullOrEmpty(a.batchNo)) expression.AndAlso(x => x.S_BATCH_NO == a.batchNo); if (!string.IsNullOrEmpty(a.factoryCode)) expression.AndAlso(x => x.S_FAC_CODE == a.factoryCode); if (!string.IsNullOrEmpty(a.stockLocation)) expression.AndAlso(x => x.S_ITEM_LOC == a.stockLocation); //根据条目修改累计分拣数量,添加分拣结果表,同时批分到发货单中 var sd = sdList.Where(expression.Compile()).First(); //简单一点,要求人工必须一次性分拣完,分拣数量和分拣明细中一致才创建分拣结果,不支持一条分拣明细多次分拣,多条分拣结果 //(sd.F_QTY - sd.F_ACC_SR_QTY) == a.qty if (sd != null && sd.F_QTY == a.qty) { //查询分拣结果是否已经存在,存在就累加 //分拣单结果 var sdr = new SortingResult { S_SORTING_NO = a.sortNo, F_QTY = a.qty, N_ROW_NO = sd.N_ROW_NO, S_ITEM_CODE = sd.S_ITEM_CODE, S_ITEM_NAME = sd.S_ITEM_NAME, S_BATCH_NO = sd.S_BATCH_NO, S_FAC_CODE = sd.S_FAC_CODE, S_ITEM_LOC = sd.S_ITEM_LOC, S_CNTR_CODE = a.cntrCode, C_REVERSE = sd.C_REVERSE, S_DEST_CNTR_CODE = a.targetcntrCode }; db.Insertable(sdr).ExecuteCommand(); //反拣对于备货托盘进行锁定 if (sdr.C_REVERSE == "Y") { db.Updateable().SetColumns(it => new Container { C_ENABLE = "N" }).Where(it => it.S_CODE == a.cntrCode).ExecuteCommand(); } else { db.Updateable().SetColumns(it => new Container { C_ENABLE = "N" }).Where(it => it.S_CODE == a.targetcntrCode).ExecuteCommand(); } //sd.F_ACC_SR_QTY += a.qty; sd.N_B_STATE = 2; sd.T_MODIFY = DateTime.Now; db.Updateable(sd).UpdateColumns(it => new { it.N_B_STATE, it.T_MODIFY }).ExecuteCommand(); //批分到发货单中 Expression> expression1 = x => x.S_ITEM_CODE == a.itemCode; expression1.AndAlso(x => x.S_CNTR_CODE == a.cntrCode); if (!string.IsNullOrEmpty(a.batchNo)) expression1.AndAlso(x => x.S_BATCH_NO == a.batchNo); if (!string.IsNullOrEmpty(a.factoryCode)) expression1.AndAlso(x => x.S_OWNER == a.factoryCode); //if (!string.IsNullOrEmpty(a.stockLocation)) expression1.AndAlso(x => x.S_ERP_WH_CODE == a.stockLocation); //更新托盘明细表 var cir = db.Queryable() .Where(expression1).First(); cir.F_QTY -= a.qty; cir.F_ALLOC_QTY -= a.qty; cir.T_MODIFY = DateTime.Now; db.Updateable(cir).UpdateColumns(it => new { it.F_QTY, it.F_ALLOC_QTY, it.T_MODIFY }).ExecuteCommand(); Expression> expression2 = x => x.S_ITEM_CODE == a.itemCode; expression2.AndAlso(x => x.S_CNTR_CODE == a.targetcntrCode); if (!string.IsNullOrEmpty(a.batchNo)) expression2.AndAlso(x => x.S_BATCH_NO == a.batchNo); if (!string.IsNullOrEmpty(a.factoryCode)) expression2.AndAlso(x => x.S_OWNER == a.factoryCode); //if (!string.IsNullOrEmpty(a.stockLocation)) expression2.AndAlso(x => x.S_ERP_WH_CODE == a.stockLocation); var cir1 = db.Queryable() .Where(expression2) .First(); if (cir1 != null) { cir1.F_QTY += a.qty; cir1.T_MODIFY = DateTime.Now; db.Updateable(cir).UpdateColumns(it => new { it.F_QTY, it.T_MODIFY }).ExecuteCommand(); } else { CntrItemRel item = new CntrItemRel { S_CNTR_CODE = a.targetcntrCode, S_ITEM_CODE = a.itemCode, S_BATCH_NO = a.batchNo, S_OWNER = a.factoryCode, //S_ERP_WH_CODE = a.stockLocation, F_QTY = a.qty, T_MODIFY = DateTime.Now }; db.Insertable(item).ExecuteCommand(); } if (sdr.C_REVERSE == "Y") { a.qty = cir.F_QTY; } //更新仓库量表和库区量表 //查询仓库量表 var wi = db.Queryable().Where(i => i.S_ITEM_CODE == a.itemCode).First(); if (wi != null) { wi.F_QTY -= a.qty; wi.F_ALLOC_QTY -= a.qty; wi.T_MODIFY = DateTime.Now; db.Updateable(wi).UpdateColumns(it => new { it.F_QTY, it.F_ALLOC_QTY, it.T_MODIFY }).ExecuteCommand(); } Expression> expression3 = x => x.S_ITEM_CODE == a.itemCode; expression3.AndAlso(x => (x.F_QTY - x.F_ACC_S_QTY) > 0); if (!string.IsNullOrEmpty(a.batchNo)) expression3.AndAlso(x => x.S_BATCH_NO == a.batchNo); if (!string.IsNullOrEmpty(a.factoryCode)) expression3.AndAlso(x => x.S_FAC_CODE == a.factoryCode); if (!string.IsNullOrEmpty(a.stockLocation)) expression3.AndAlso(x => x.S_ITEM_LOC == a.stockLocation); //分拣明细生成时 应该与发货单明细对应 var dList = soList.SelectMany(s => s.Details) .Where(expression3.Compile()) .ToList(); var qty = a.qty; for (int i = 0; i < dList.Count; i++) { var d = dList[i]; //发货信息中间表 //var dyo = new DayuanOut //{ // CN_S_BATCH_NO = sd.S_BATCH_NO, // CN_S_ITEM_CODE = sd.S_ITEM_CODE, // CN_S_OUT_NO = d.S_SHIPPING_NO, // //}; if (d.F_QTY - d.F_ACC_S_QTY >= a.qty) { //发货单数量超过托盘分拣数量,批分qty d.F_ACC_S_QTY += a.qty; //dyo.CN_F_QUANTITY = a.qty; qty = 0; } else { // 发货单数量小于托盘分拣数量 d.F_ACC_S_QTY = d.F_QTY; qty -= (d.F_QTY - d.F_ACC_S_QTY); //dyo.CN_F_QUANTITY = d.F_QTY - d.F_ACC_S_QTY; } d.T_MODIFY = DateTime.Now; db.Updateable(d).UpdateColumns(it => new { it.F_ACC_S_QTY, it.T_MODIFY }).ExecuteCommand(); //插入到大元出库中间表 //db.Insertable(dyo).ExecuteCommand(); if (qty == 0) { break; } } //麻烦了,分拣明细只记托盘,不记住起点,如果要统计库区量表,必须对托盘加标记,记录托盘的来源库区,托盘清空后再清除标记 //逻辑库区更不需要量表了,因为从一个逻辑库区出来,可能回其它逻辑库区,那就应该直接删除逻辑库区量表,后面再加到别的逻辑库区中 //但是会带来新的问题,就是分拣回的托盘不属于任何逻辑库区的量,只有回库了才能计算到 //var aziList = db.Queryable().Where(i => i.S_ITEM_CODE == a.itemCode).ToList(); } // }); //判断分拣单是否全部完成 if (sdList.Count(sd => sd.N_B_STATE != 2) == 0) { var spo = db.Queryable().Where(s => s.S_NO == models[0].sortNo).First(); if (spo != null) { spo.N_B_STATE = 10; spo.T_MODIFY = DateTime.Now; db.Updateable(spo).UpdateColumns(it => new { it.N_B_STATE, it.T_MODIFY }).ExecuteCommand(); } } //判断发货单配货是否分拣完成 soList.ForEach(s => { if (s.Details.Count > 0 && s.Details.Count(sd => sd.F_ACC_D_QTY != sd.F_ACC_S_QTY) == 0) { //配货单的数量等于分拣的数量,分拣完成 s.N_B_STATE = 3; s.T_MODIFY = DateTime.Now; db.Updateable(s).UpdateColumns(it => new { it.N_B_STATE, it.T_MODIFY }).ExecuteCommand(); } }); db.CommitTran(); } catch (Exception ex) { Console.WriteLine(ex.Message); db.RollbackTran(); } } } /// /// 立库入库算法 /// /// /// /// internal static Location GetLiKuLocationIn(string endArea, int roadway, string loctype = "", string IsLong = "0") { LogHelper.Info($"入库算法开始 终点库区={endArea} 巷道={roadway} 货位类型={loctype}"); Location endbit = null; var res = false; var loclist = new List(); var newendbitlist = new List(); var db = new SqlHelper().GetInstance(); //var endbitlist = new List<>(); //var ebitlist = new List(); //var endbitlist = db.Queryable() // .Where(a => a.S_AREA_CODE == endArea && a.IsDouble == isDouble) // .PartitionBy(a => a.N_ROADWAY) // .Select(a => new { sum = SqlFunc.AggregateSum(a.N_CURRENT_NUM), ROADWAY = a.N_ROADWAY }) // .MergeTable() // .OrderBy(a => a.sum) // .ToList(); if (roadway == 0) { var endbitlist = db.Queryable() .Where(a => a.S_AREA_CODE == endArea) .Select(a => new { sum = SqlFunc.AggregateSum(a.N_CURRENT_NUM), a.N_ROADWAY }) //.PartitionBy(a => a.N_ROADWAY) .GroupBy(a => a.N_ROADWAY) .MergeTable() .OrderBy(a => a.sum) .ToList(); LogHelper.Info($"获取各个巷道数据 巷道数量={endbitlist.Count()}"); endbitlist.ForEach(a => { //查找入库锁数量 加上去 var loc = db.Queryable() .Where(it => it.S_AREA_CODE == endArea && it.N_ROADWAY == a.N_ROADWAY && it.N_LOCK_STATE == 1) .ToList(); newendbitlist.Add(new summodel { sum = a.sum, roadway = a.N_ROADWAY, locksum = loc.Count }); }); newendbitlist = newendbitlist.OrderBy(a => a.sum).ToList(); newendbitlist = newendbitlist.OrderBy(a => a.locksum).ToList(); LogHelper.Info($"整合后数据 巷道数量={newendbitlist.Count()}"); foreach (var item in newendbitlist) { //if (DuiDuoBool(item.roadway)) //{ var exp = Expressionable.Create(); exp.And(a => a.S_AREA_CODE == endArea); exp.And(a => a.N_ROADWAY == item.roadway); exp.And(a => a.N_CURRENT_NUM == 0); exp.And(a => a.N_LOCK_STATE == 0); exp.AndIF(!string.IsNullOrEmpty(loctype), a => a.S_TYPE == loctype); res = true; if (IsLong == "0") { loclist = db.Queryable() .Where(exp.ToExpression()) .OrderByDescending(it => new { N_LAYER = SqlFunc.Asc(it.N_LAYER), N_COL = SqlFunc.Asc(it.N_COL), N_ROW = SqlFunc.Asc(it.N_ROW) }) .ToList(); } else { loclist = db.Queryable() .Where(exp.ToExpression()) .OrderByDescending(it => new { N_LAYER = SqlFunc.Asc(it.N_LAYER), N_COL = SqlFunc.Desc(it.N_COL), N_ROW = SqlFunc.Asc(it.N_ROW) }) .ToList(); } LogHelper.Info($"获取可用货位数量={loclist.Count}"); if (loclist.Count > 0) { endbit = loclist[0]; break; } } } else { var exp = Expressionable.Create(); exp.And(a => a.S_AREA_CODE == endArea); exp.And(a => a.N_ROADWAY == roadway); exp.And(a => a.N_CURRENT_NUM == 0); exp.And(a => a.N_LOCK_STATE == 0); exp.AndIF(!string.IsNullOrEmpty(loctype), a => a.S_TYPE == loctype); //if (DuiDuoBool(int.Parse(roadway))) //{ if (IsLong == "0") { loclist = db.Queryable() .Where(exp.ToExpression()) .OrderByDescending(it => new { N_LAYER = SqlFunc.Asc(it.N_LAYER), N_COL = SqlFunc.Asc(it.N_COL), N_ROW = SqlFunc.Asc(it.N_ROW) }) .ToList(); } else { loclist = db.Queryable() .Where(exp.ToExpression()) .OrderByDescending(it => new { N_LAYER = SqlFunc.Asc(it.N_LAYER), N_COL = SqlFunc.Desc(it.N_COL), N_ROW = SqlFunc.Asc(it.N_ROW) }) .ToList(); } if (loclist.Count > 0) { endbit = loclist[0]; } //} //else //{ // msg = $"巷道{roadway} 对应堆垛机不可用"; // return endbit; //} } LogHelper.Info($"入库算法结束 结果{endbit != null}"); return endbit; } public class summodel { public int sum { get; set; } public int locksum { get; set; } public int roadway { get; set; } } internal static bool CheckSortingWholeCntr(string cntr, bool autoSort) { var result = false; //判断分拣明细是不是只有一个托盘,如果是,判断容器货品明细是不是和分拣明细完全一样 var db = new SqlHelper().GetInstance(); var sdList = db.Queryable().Where(a => a.S_CNTR_CODE == cntr).ToList(); if (sdList.Count > 0) { var groups = sdList.GroupBy(a => a.S_SORTING_NO).ToList(); if (groups.Count == 1) { var list = groups.ToList(); //只有一个分拣单的情况下,分配量和托盘量都相同,表示是整托 var cirList = db.Queryable().Where(a => a.S_CNTR_CODE == cntr).ToList(); if (list.Count == cirList.Count && cirList.Count(c => c.F_QTY != c.F_ALLOC_QTY) == 0) { result = true; if (autoSort) { var data = sdList.Select(s => new SortingResultCheck { cntrCode = s.S_CNTR_CODE, itemCode = s.S_ITEM_CODE, qty = s.F_QTY, sortNo = s.S_SORTING_NO }).ToList(); SortingConfrim(data); } } } } return result; } } }