/// ///LOGIC CLASS FOR TABLE t_wmsOutPickPort ///By wm with codesmith. ///on 06/17/2020 /// using System; using System.Collections.Generic; using System.Linq; using System.Text; using DeiNiu.wms.Data.Model; using System.Data; using System.Transactions; using DeiNiu.Utils; namespace DeiNiu.wms.Logical { [Serializable] public class lWmsOutPickPort :lbase { WmsOutPickPort _obj; public lWmsOutPickPort() { initialize(); } public WmsOutPickPort getWmsOutPickPort { get { if (_obj == null) { _obj = new WmsOutPickPort(); } _obj.operater = operId; return _obj; } } public lWmsOutPickPort(int operId) : base(operId) { initialize(); } WmsWave _wmsWave ; WmsWave wmsWave { get { if (_wmsWave == null) { _wmsWave = new WmsWave(); } _wmsWave.operater = operId; return _wmsWave; } } /// /// get all data /// public DataSet getAllData() { return _obj.Query(); } /// /// get all data /// public DataSet getAllActiveData() { return _obj.QueryActived(); } /// /// get a record by id /// public void initialize(int id) { _obj = id != 0 ? new WmsOutPickPort(id) : new WmsOutPickPort(); } /// /// get a record by id 0 /// public void initialize() { initialize(0); } /// /// get a record by id /// public void initialize(DataRow dr) { _obj = new WmsOutPickPort(dr); } protected override DeiNiu.Data.BaseObject.BaseModel getModel() { return _obj; } //begin cust db operation, query, excute sql etc. internal int add(WmsOutPickPort obj) { return obj.Add(); } static bool isCreatingWaves =false; internal DataSet getWaveDetails(string waveNo, int rowStart, int rowEnd) { return _obj.getWaveDetails(waveNo, rowStart, rowEnd); } internal DataTable getWaveDetails(string waveNo) { return _obj.getWaveDetails(waveNo ); } internal DataSet getWavePages(int state, int rowStart, int rowEnd) { return wmsWave.queryPages(state, rowStart, rowEnd); } internal DataTable getPickInfo(string waveNo, int volType) { return _obj.getPickInfo(waveNo, volType); } internal DataTable getPickInfo(string waveNo) { return _obj.getPickInfo(waveNo ); } internal DataTable getPickSummary(string waveNo, int volType) { return _obj.getPickSummary(waveNo, volType); } // to move to lStockOutPort /// /// 出库分拣任务 /// 按相同的集货区域的拣货单合并拣货 /// 同一个波次按拣货区域划分为不同的任务 /// 每个任务有一个或多个拣货明细 /// 每个任务考虑作为播种亮灯的播种单号 /// /// public bool createPickWaves() { if (isCreatingWaves) { // return false; LogHelper.debug("lWmsOutPickPort", "wave is creating in ????? "); } isCreatingWaves = true; DataTable dt = getWmsOutPickPort.getNewPickTasks(new WaveRule().getCurrentActiveRule(enumWaveRuleType.普通波次)); if (dt.Rows.Count == 0) { isCreatingWaves = false; return false; } int lastTranArea = -100, lastPartion = -100, lastVolType = -100, lastOrderType = -100; ; string lastPickRequest = "", waveNo = "", jobNo = "",lastWaveNo=""; bool isNewWave = false, isNewJob = false; Dictionary waveJobs = new Dictionary(); int waveSize = 0; int maxSize = WmsConstants.WAVE_ORDERS_CNT; int jobMax = WmsConstants.WAVE_TASK_MAX_CNT; LogHelper.debug("lWmsOutPickPort", "start to process new waves...count:" + dt.Rows.Count); int jobcnt = 0; bool isCreateFlowTask = WmsConstants.OUT_LIGHT_ENABLE ? WmsConstants.DPS_TASK_GENERATION :true ; WmsFlow wmsflow; using (TransactionScope scope = new TransactionScope()) { foreach (DataRow dr in dt.Rows) { _obj = new WmsOutPickPort(dr); if (lastTranArea == -100) { lastTranArea = _obj.tranArea; } if (lastPartion == -100) { lastPartion = _obj.partion; } if (lastVolType == -100) { lastVolType = _obj.volType; } /* if (lastOrderType == -100) { lastOrderType = _obj.or; } */ if (lastPickRequest != _obj.pickOrderNo) { waveSize++; //TODO:更新拣货状态 1. 整库拣货状态 2. 零库拣货状态 if (String.IsNullOrEmpty(lastPickRequest)) { lastPickRequest = _obj.pickOrderNo; } WmsOutPickRequest pr = new WmsOutPickRequest(lastPickRequest); pr.state = (int)enumOutStockRequestStatus.正在分拣; pr.Update(); } isNewWave = String.IsNullOrEmpty(waveNo) || lastTranArea != _obj.tranArea //集货目的地不同,开新波次 || waveSize == maxSize; //达到波次最大订单数,开新波次 if (isNewWave) { /*if (!string.IsNullOrEmpty(waveNo) && waveJobs.ContainsKey(lastPartion)) { WmsFlow wmsflow = new WmsFlow(jobNo, waveNo); if(wmsflow.ID>0){ wmsflow.taskCnt = jobcnt; wmsflow.Update(); } }*/ lastWaveNo = waveNo; waveNo = Util.getOrderNo(enumCreateOrderType.waveOrder, _obj.getNextSeq(enumCreateOrderType.waveOrder)); waveJobs = new Dictionary(); waveSize = 0; WmsWave wave = new WmsWave(); wave.waveNo = waveNo; wave.type = _obj.recType; wave.operater = operId; wave.Add(); } isNewJob = isNewWave || lastPartion != _obj.partion || jobcnt >= jobMax || !waveJobs.ContainsKey(_obj.partion); if (jobcnt >= maxSize) { } if (isNewJob) { isCreateFlowTask = WmsConstants.OUT_LIGHT_ENABLE ? WmsConstants.DPS_TASK_GENERATION : true ; isCreateFlowTask = isCreateFlowTask || lastVolType > 0; // LogHelper.WriteLog(typeof(lWmsOutPickPort), string.Format("1 isCreateFlowTask: {0},lastVolType {1}", isCreateFlowTask, lastVolType)); if (isCreateFlowTask && !string.IsNullOrEmpty(jobNo) ) { wmsflow = new WmsFlow(jobNo); if (wmsflow.ID > 0) { wmsflow.taskCnt = jobcnt;// waveJobs[lastPartion].Length; wmsflow.Update(); } } jobcnt = 0; jobNo = Util.getOrderNo(enumCreateOrderType.pickJobNo, _obj.getNextSeq(enumCreateOrderType.pickJobNo)); waveJobs[_obj.partion] = jobNo; isCreateFlowTask = WmsConstants.OUT_LIGHT_ENABLE ? WmsConstants.DPS_TASK_GENERATION :true ; isCreateFlowTask = isCreateFlowTask || _obj.volType > 0; // LogHelper.WriteLog(typeof(lWmsOutPickPort), string.Format("2 isCreateFlowTask: {0},_obj.volType {1}", isCreateFlowTask, _obj.volType)); if (isCreateFlowTask) { wmsflow = new WmsFlow(); wmsflow.operater = operId; wmsflow.orderNo = waveNo; wmsflow.type = (int)Util.getTaskType(_obj.recType); wmsflow.task = jobNo; wmsflow.fromPartion = _obj.partion; wmsflow.toPartion = _obj.tranArea; wmsflow.taskPartion = _obj.partion; wmsflow.Add(); } } else { jobNo = waveJobs[_obj.partion]; } jobcnt++; _obj.waveOrder = waveNo; _obj.jobNo = jobNo; _obj.operater = operId; _obj.Update(); lastTranArea = _obj.tranArea; lastPickRequest = _obj.pickOrderNo; lastPartion = _obj.partion; lastVolType = _obj.volType; } if (!string.IsNullOrEmpty(waveNo) ) { wmsflow = new WmsFlow(jobNo ); if (wmsflow.ID > 0) { wmsflow.taskCnt = jobcnt; wmsflow.Update(); } } scope.Complete(); } LogHelper.debug("lWmsOutPickPort", "end process new waves..."); isCreatingWaves = false; return true; } WmsOutDesk _desk; WmsOutDesk desk { get { if (_desk == null) { _desk = new WmsOutDesk(); _desk.operater = operId; } return _desk; } } WmsOutDesk _seedsDesk; WmsOutDesk seedsDesk { get { if (_seedsDesk == null) { _seedsDesk = new WmsOutDesk(); } return _seedsDesk; } } static List lblist = new List(); static Dictionary comLables = new Dictionary(); void initialDebugSetting() { DataTable dt = new Node().QueryByFlag(10001); foreach (DataRow dr in dt.Rows) { Node node = new Node(dr); if (!node.isOn) { continue; } try { string labels = node.description; string[] lbs = labels.Split(','); foreach (string s in lbs) { comLables[Convert.ToInt16(s.Trim())] = Convert.ToInt16(node.name.Trim()); lblist.Add(Convert.ToInt16(s.Trim())); } } catch { continue; } } } private string waveOrder = ""; public void newBulkDPSPickWave() { if (!WmsConstants.OUT_LIGHT_ENABLE) { return; } //播种筛选, //适合播种的客户订单合并成一个、多个大订单,统一捡出后进行播种操作 //1. 单个订单的品种少 、数量少 //2. 订单数量多 //只处理订单零货部分 //加入播种选项,所有订单零货部分使用摘取+播种方式 //1.播种点数量可配置, 分别用不同颜色区分 //2.每个播种点可分播客户的数量配置, 即每个播种点处理零货订单数量( 例如配置成6个,一次捡6个客户的订单零货部分,送由一个播种点播种) //3.波次和播种点的对应关系,一个波次只摘取一个播种点的零货,还是多个播种点的数据? //4. //一个波次可以摘取订单数 = 空闲分播台数量*每个分播台可分播客户数, 分播台的订单用颜色区分 // LogHelper.debug(typeof(lWmsOutPickPort), "开始新波次。。。。。。。。。。。。。。。。。。"); DataTable dtPorts = getWmsOutPickPort.getNewPickTasks(new WaveRule().getCurrentActiveRule(enumWaveRuleType.DPS灯光波次)); LogHelper.debug(typeof(lWmsOutPickPort), string.Format("待处理任务数量:{0}", dtPorts.Rows.Count)); if (dtPorts.Rows.Count == 0) { LogHelper.debug(typeof(lWmsOutPickPort), string.Format("无订单需要处理,波次结束")); new lWmsOutPickRequest(this.operId).checkRepAndNoStockOrders(); return; } desk.restDeskStatus(enumDeskState.空闲); desk.restDeskStatus(enumDeskState.空闲, enumDeskType.播种); //播种台状态复位到空闲,是不是可以由播种员实际播种任务进度控制? _seedsDesk = desk.getRandomDesk(enumDeskState.空闲, enumDeskType.播种); ; _desk = desk.getRandomDesk(enumDeskState.空闲, enumDeskType.复核); int labelMaxInWave = WmsConstants.MAX_LABEL_DATA_IN_A_WAVE; //一个标签一个波次只能存储40条数据 #if DEBUG // if (lblist.Count == 0) { lblist.Clear(); initialDebugSetting(); } lblist.Sort(); #endif // List strecs = null; waveOrder = Util.getOrderNo(enumCreateOrderType.dpsOrder, _obj.getNextSeq(enumCreateOrderType.dpsOrder)); //waveOrder = "WV" + System.DateTime.Now.ToString("yyyyMMddHHmmss"); Dictionary labelCnt = new Dictionary(); Dictionary comCnt = new Dictionary(); Dictionary tmplabelCnt = new Dictionary(); Dictionary tmpcomCnt = new Dictionary(); bool isReachLimit = false; int waveSize = 0; //List lstPort; List lstLabel; List lstBulk; LogHelper.debug(typeof(lWmsOutPickRequest), string.Format("waveNo {0}", waveOrder)); //播种常量,达不到最小订单摘取需求的合并成大订单先统一摘取再分播 bool isSeedsEnabled = WmsConstants.OUT_BULK_SEEDS_PICK_ON; int pickGoodsTypeMin = WmsConstants.OUT_MAX_SEEDS_GOODSTYPE_CNT; //单独摘取订单 最少货物类型 int pickGoodsCountMin = WmsConstants.OUT_MAX_SEEDS_BULK_CNT_SUM; // 单独摘取订单 最少货物数量 int seedsCount = seedsDesk.seedsCount; //播种台一次播种订单数量 decimal sumBulkCnt = 0; bool isSeedPickInSameWave = true; // bool canSeedPickLessThanseedsCount = false; //单个播种拣选单数量不可少于播种能力 List seedsRequests = new List(); Dictionary seedsBulks = new Dictionary(); if (desk.ID == 0) // no free pick desk { if (isSeedsEnabled) { _seedsDesk = desk.getRandomDesk(enumDeskState.空闲, enumDeskType.播种); if (seedsDesk.ID == 0) { return; } } else { return; } } int bulkCnt = 0; int requestCnt = 0; //开始处理有零货的订单 DateTime d0 = DateTime.Now; double totoalTime = 0d; string lastAddress = ""; // foreach (WmsOutPickRequest request in requests) WmsOutPickPort wopp; string lastPickOrder = ""; List lstPort = new List(); lstBulk = new List(); int elebleId = 0, port = 0; WmsOutPickRequest request; List taskRequests = new List(); Dictionary> tasks = new Dictionary>(); Dictionary> portTasks = new Dictionary>(); foreach (DataRow dr in dtPorts.Rows) { DateTime d00 = DateTime.Now; wopp = new WmsOutPickPort(dr); if (lastPickOrder != wopp.pickOrderNo) { lastPickOrder = wopp.pickOrderNo; _desk = desk.getRandomDesk(enumDeskState.空闲, enumDeskType.复核); if (_desk.ID > 0) { request = new WmsOutPickRequest(lastPickOrder); request.desk = _desk.color; desk.state = (int)enumDeskState.任务中; desk.Update(); taskRequests.Add(request); } else { break; } } if (!tasks.Keys.Contains(lastPickOrder)) { tasks[lastPickOrder] = new List(); } if (!portTasks.Keys.Contains(lastPickOrder)) { portTasks[lastPickOrder] = new List(); } tasks[lastPickOrder].Add(new WmsStockRecord(dr)); portTasks[lastPickOrder].Add(wopp); } #region savedata foreach (WmsOutPickRequest pickRequest in taskRequests) { int lastId = 0; LogHelper.debug(typeof(lWmsOutPickRequest), " 摘果式 保存整货和零货出库分拣数据"); lstLabel = new List(); WmsOutPickLable_tmp wpl; foreach (WmsStockRecord rec in tasks[pickRequest.pickOrderNo]) { // if (rec.count == 0) if (rec.count + rec.countOuting < 1) //不支持小数 { continue; } if (lblist.Count > 0) { int id = new Random().Next(lblist.Count); //#if DEBUG rec.location.elabId = lblist[id]; //new Random().Next(minId, maxId + 1); //测试。。。随机分配标签id 为 1-3 while (lblist.Count > 1 && lastId == rec.location.elabId) { id = new Random().Next(lblist.Count); rec.location.elabId = lblist[id]; } lastId = rec.location.elabId; //#endif } wpl = new WmsOutPickLable_tmp(); wpl.pickOrderNo = pickRequest.pickOrderNo; wpl.recordId = rec.ID; wpl.color = pickRequest.desk; wpl.count = rec.count + rec.countOuting; wpl.locationId = rec.locationId; wpl.elabAddress = rec.location.elabAddress; wpl.elabId = rec.location.elabId; wpl.port = rec.location.port; wpl.orderDetailId = rec.orderDetailId; //#if DEBUG try { if (comLables.Count > 0) { wpl.port = comLables[wpl.elabId]; //rec.location.elabId < 4 ?5 :3; //测试。。。 分配标签端口为3 } } catch { } //#endif wpl.dpsOrder = waveOrder; wpl.operater = this.operId; lstLabel.Add(wpl); } //保存整货和零货出库分拣数据 try { using (TransactionScope scope1 = new TransactionScope()) { foreach (WmsOutPickLable_tmp wp in lstLabel) //建立电子拣选临时数据 { wp.Add(); } foreach (WmsOutPickPort pt in portTasks[pickRequest.pickOrderNo]) { pt.dpsOrder = waveOrder; pt.Update(); } if (lstLabel.Count > 0) { pickRequest.waveOrder = waveOrder; pickRequest.state = (int)enumOutStockRequestStatus.正在分拣; pickRequest.waveStart = pickRequest.getDateTime(); pickRequest.operater = this.operId; pickRequest.updateBulkPickStatus(pickRequest.pickOrderNo, enumOutStockPickStatus.正在分拣, operId); // pickRequest.state = pickRequest.Update(); } waveSize++; scope1.Complete(); } } catch (Exception e) { LogHelper.WriteLog(typeof(lWmsOutPickRequest), e); desk.restDeskStatus(enumDeskState.空闲); throw e; } } #endregion // totoalTime += ts00.TotalSeconds; //建立零库电子拣选临时数据 new WmsOutPickRequest().saveTempData4Validation(waveOrder); WmsConstants.WAVE_CURRENT_PICK_STATUS.Clear(); WmsConstants.WAVE_CURRENT_ORDER = waveOrder; WmsConstants.WAVE_LAST_TIME = DateTime.Now; //检查待补货出货单状态 new lWmsOutPickRequest(this.operId).checkRepAndNoStockOrders(); } /* * 分配拣货任务 */ public void taskAssign(int taskBy,int partion,int lineId,int maxLocCnt=0,int maxBoxs=0, bool batchOnly=true,enumOutOrderType orderType = enumOutOrderType.销售出库) { maxLocCnt = maxLocCnt<=0?WmsConstants.MAX_PICK_LOT_CNT:maxLocCnt; maxBoxs = maxBoxs <= 0 ? WmsConstants.MAX_PICK_BOX_CNT : maxBoxs; int lotcnt = 0,boxcnt=0; WmsOutPickPort wop; DataTable dt = getWmsOutPickPort.getAssignedTasks(taskBy, -1, -1, batchOnly,orderType); lotcnt = dt.Rows.Count; if (lotcnt >= maxLocCnt) { LogHelper.debug("lWmsOutPickPort", " user " + taskBy + "no more task assign, task lotcnt :" + lotcnt); return; } foreach (DataRow dr in dt.Rows) { wop = new WmsOutPickPort(dr); try { boxcnt += Convert.ToInt32(dr["boxcnt"].ToString()); } catch { } if (boxcnt >=maxBoxs ) { LogHelper.debug("lWmsOutPickPort", " user " + taskBy + "no more task assign, task Assigned box cnt :" + boxcnt); return; } // wop.operater = operId; } dt = getWmsOutPickPort.getFreeTasks(partion, lineId, batchOnly,orderType,taskBy); lWmsStock lstk = new lWmsStock(operId); using (TransactionScope scope = new TransactionScope()) { foreach (DataRow dr in dt.Rows) { wop = new WmsOutPickPort(dr); lotcnt++; boxcnt += Convert.ToInt16(dr["boxcnt"].ToString()); if (lotcnt > maxLocCnt || boxcnt >maxBoxs ) { break; } wop.takeBy = taskBy; // wop.operater = operId; wop.Update(); LogHelper.debug("lWmsOutPickPort", " user " + taskBy + " task Assign :" + wop.ID); if (wop.recType != (int)enumStockRecordType.补零出库) { continue; } //to create inport data int skuId = Convert.ToInt32(dr["skuId"].ToString()); string goodsId =dr["goodsId"].ToString(); string batch =dr["batch"].ToString(); string skucode = dr["skucode"].ToString(); string prdtime = dr["productDate"].ToString(); string vltime = dr["validDate"].ToString(); DataTable dtBulkLocs = lstk.getBulkLocations(skuId, "",goodsId , batch, wop.count); foreach (DataRow dr1 in dtBulkLocs.Rows) { //todo: to add stock record WmsInUpPort wip = new WmsInUpPort(); wip.locationId = dr1[0].ToString(); wip.count =Convert.ToDecimal( dr1[1].ToString()); wip.orderNo = wop.pickOrderNo; wip.skuId = skuId; wip.skuCode = skucode; wip.batch = batch; wip.goodsId = goodsId; wip.detailId = wop.pickDetailId; wip.recType = (int)enumStockRecordType.补零入库; wip.recordId = wop.recordId; wip.productDate = prdtime; wip.validDate = vltime; wip.flowNo = "0"; WmsLocation loc = new WmsLocation(wip.locationId); Node nd = new Node( loc.part); if (nd.ID > 0) { wip.partion = nd.flag; } wip.Add(); //create stock,lock the location WmsStock newStk = new WmsStock(wip.locationId, skuId); if (newStk.ID == 0) //new one { newStk.countIn = wip.count; newStk.skuCode = skucode; newStk.goodsId = goodsId; newStk.skuId = skuId; newStk.locationId = wip.locationId ; newStk.batch = batch; newStk.productDate = wip.productDate; newStk.validDate = wip.validDate; newStk.maintainDate = newStk.getDateTime(); newStk.Add(); } } } scope.Complete(); } } /// /// 取总播种操作 /// /// 取总板号 /// 销售明细id /// 分播数量 /// 周转箱号 /// internal enumRepResult seedsPickOut(string flowNo,string batch, int outDetailId, decimal seedCnt,string toFlowNo) { WmsOutDetail wod = new WmsOutDetail(outDetailId); WmsOutRequest wor = new WmsOutRequest(wod.orderNo); wod.pickCount += seedCnt; // pickport with flowno can be multi records, update the finished seeds count in loop DataTable dt = getWmsOutPickPort.getFlowNoDetails(flowNo,wod.goodsId,batch); List lst = new List(); decimal tmpCnt = seedCnt; foreach(DataRow dr in dt.Rows) { WmsOutPickPort wop = new WmsOutPickPort(dr); if (wop.state == 1) { if (wop.seedsOutCount + tmpCnt <= wop.pickCount) { wop.seedsOutCount += tmpCnt; lst.Add(wop); tmpCnt= 0; break; } else { tmpCnt -= wop.pickCount - wop.seedsOutCount; wop.seedsOutCount = wop.pickCount; wop.state = (int)enumPickState.已分播; lst.Add(wop); } } } if(tmpCnt > 0) { return enumRepResult.分播数量大于剩余数量; } using (TransactionScope scope = new TransactionScope()) { wod.Update(); WmsStockRecord wsr = new WmsStockRecord(); wsr.orderNo = wod.orderNo; wsr.orderDetailId = wod.ID; wsr.goodsId =wod.goodsId; wsr.count = seedCnt; wsr.locationId = flowNo; wsr.Add(); WmsOutPickPort wop = new WmsOutPickPort(); wop.recordId = wsr.ID; wop.pickBy = operId; wop.pickTime = wop.getDateTime(); wop.pickCount = seedCnt; wop.pickOrderNo = wor.pickOrderNo; wop.state = (int)enumPickState.已分播; wop.recType = (int)enumStockRecordType.销售出库; wop.seedsFromFlowNo = flowNo; wop.flowNo = toFlowNo; wop.Add(); foreach(WmsOutPickPort tmp in lst) { tmp.Update(); } scope.Complete(); } return enumRepResult.成功; } internal DataTable getSeedsPickDetail(string flowNo, bool isOrderByCust) { return getWmsOutPickPort.getSeedsPickDetail(flowNo, isOrderByCust); } /* * 取消拣货任务 * */ public int taskRessign(int taskBy, int partion, int lineId, bool batchOnly = true, enumOutOrderType orderType = enumOutOrderType.销售出库) { DataTable dt = getWmsOutPickPort.getAssignedTasks(taskBy, partion, lineId, batchOnly,orderType); int i=0; WmsOutPickPort wop; using (TransactionScope scope = new TransactionScope()) { foreach (DataRow dr in dt.Rows) { wop = new WmsOutPickPort(dr); wop.takeBy = 0; // wop.operater = operId; if (wop.state == (int)enumPickState.未拣) { wop.Update(); i++; LogHelper.debug("lWmsOutPickPort", " user " + taskBy + " task resign:" + wop.ID); } } scope.Complete(); } return i; } public DataTable getAssignedTasks4Wince(int taskBy, int partion = 0, int lineId = -1, bool batchOnly = true,enumOutOrderType orderType = enumOutOrderType.销售出库) { return getWmsOutPickPort.getAssignedTasks4Wince(taskBy, partion, lineId, batchOnly, orderType); } public DataTable getAssignedOutTasks(int taskBy, int partion = 0, int lineId = -1, bool batchOnly = true, enumOutOrderType orderType = enumOutOrderType.销售出库) { return getWmsOutPickPort.getAssignedTasks(taskBy, partion, lineId, batchOnly, orderType); } public DataTable getPartions(int userID) { return getWmsOutPickPort.getPartions(userID); } internal DataTable getRepTasks(int takeBy, int taskPartion ) { return getWmsOutPickPort.getRepTasks(takeBy, taskPartion ); } } }