package seq import ( "fmt" "github.com/go-xorm/xorm" "leit.com/leit_seat_aps/common" "leit.com/leit_seat_aps/db" "leit.com/leit_seat_aps/glog" "leit.com/leit_seat_aps/service" "strings" "time" ) /** 基于已派工生产订单计算拣料单 基本逻辑: 1. 加载产线对应的拣料单模板 2. 循环加载派工生产订单,按产线和schedKey排序 3. 遍历生产订单零件列表 4. 遍历零件属性和生产订单对应产线的拣料单属性进行适配,满足则将该零件和数量添加到该拣料单中 5. 拣料单满,关闭拣料单并新建一个空拣料单 **/ // 拣料单服务 // 功能描述:基于排序产线对应的已下达的生产订单,通过属性匹配自动创建拣料单,并填充待拣料项,直至到达需求上限 // 拣料单创建初始状态 = 20 计划;填充完 = 26 下达; func RunPicker() (err error) { var ( pkordsn string pe service.PickingEngine bl_wolist []service.BL_WorkOrder bl_wline service.BL_Workline i int //pln db.Pln_custorder ) // 获取拣料单序列号 if pkordsn, err = service.GetSysStringParameter(2, "*", "JIS_PICKORDER_SN"); err != nil { return } if strings.TrimSpace(pkordsn) == "" { pkordsn = "PICKORDER" // 默认流水ID } fmt.Println("JIS_PICKORDER_SN = ", pkordsn) // 初始化 pe = service.PickingEngine{PickOrderSN: pkordsn} // 加载主数据 fmt.Println("准备开始加载主数据......") if err = pe.LoadMasterData(); err != nil { return } fmt.Println("完成主数据加载!") glog.InfoExtln("PickingTmpDict","PickingTmpDict:",pe.PickingTmpDict) // 循环服务 for { fmt.Println("循环服务开启......") //判断生成订单是否有未下达的,如果有的话,那么不往下进行 //data, err := pln.SelectTenArr() //if err != nil || len(data) > 0 { // //有未下达的,则等待五秒 // time.Sleep(5 * time.Second) // continue //} // 遍历产线 for _, bl_wline = range pe.WorklineDict { fmt.Println(" 遍历产线:", bl_wline.WorklineId) // 从数据库中循环读取指定产线已派工下达未拣料的排序订单 if bl_wolist, err = bl_wline.GetUnpickedWorkorderList(); err != nil { glog.InfoExtln("拣料单服务", "Failed to GetUnpickedWorkorderList:", err) continue } if len(bl_wolist) == 0{ //判断生成订单的长度 time.Sleep(5 * time.Second) continue } // 遍历产线上未拣料的生产订单并对它进行拣料 for i = 0; i < len(bl_wolist); i++ { if err = PickLineWorkorder(&bl_wline, &bl_wolist[i], &pe); err != nil { glog.InfoExtln("拣料单服务", "Failed to PickLineWorkorder:", err) continue } } } time.Sleep(10 * time.Second) } } // 对产线上的派工订单进行拣料 func PickLineWorkorder(bl_wline *service.BL_Workline, bl_wo *service.BL_WorkOrder, pe *service.PickingEngine) (err error) { var ( session *xorm.Session bl_wopart service.BL_WorkOrder_Part bl_part service.BL_Part bl_pktmp service.BL_PickingTemplate bl_pko service.BL_PickingOrder bl_ordmsg service.BL_Ordmsg pktmpattrtab db.Pln_picktemplate_attrlst pktmpparttab db.Pln_picktemplate_itemlst i,attrcode int pickorderid, picktmpid, partid, wonr string ok, bflag, matched, exist, released bool pkodict map[string]service.BL_PickingTemplate ) // 生产订单项目是否存在,如果不存在则不作处理 if _, ok = pe.Projectdict[bl_wo.Workordertab.Projnr]; !ok { return } session = db.G_DbEngine.NewSession() defer session.Close() if err = session.Begin(); err != nil { return } // 遍历订单零件列表 bflag = true pkodict = make(map[string]service.BL_PickingTemplate) for i = 0; i < len(bl_wo.Workordertab.Partlst); i++ { // 如果遍历零件不能存在则跳过 if bl_part, ok = pe.Projectdict[bl_wo.Projnr].Partdict[bl_wo.Workordertab.Partlst[i].Partid]; !ok { continue } if bl_wopart, ok = bl_wo.Bl_wopartdict[bl_wo.Workordertab.Partlst[i].Partid]; !ok { continue } bl_wopart.Workordertab = bl_wo.Workordertab bl_wopart.Parttab = bl_part.Parttab // 获取零件在当前产线的拣料单模板,如果适配 matched = false // 零件只能进入到一个匹配模板,因此要遍历产线上的所有拣料单模板,一旦适配则返回 for _, bl_pktmp = range bl_wline.PickTmpDict { // 基于不同的适配模式做属性或者零件的适配 switch bl_pktmp.Picktemplatetab.Adaptway { case common.PKT_ADAPT_BY_ATTR: // 比对零件属性是否在模板分配的属性中 for _, pktmpattrtab = range bl_pktmp.AssignAttrDict { if _, ok = bl_part.AtcodDict[pktmpattrtab.Attrcode]; ok { matched = true wonr = bl_wo.Workordertab.Workordernr attrcode = pktmpattrtab.Attrcode picktmpid = bl_pktmp.TemplateId break } } case common.PKT_ADAPT_BY_PART: // 比对订单零件和模板分配零件是否相同 for _, pktmpparttab = range bl_pktmp.AssignPartDict { if bl_wopart.Partid == pktmpparttab.Partid { matched = true wonr = bl_wo.Workordertab.Workordernr partid = bl_wo.Workordertab.Partlst[i].Partid picktmpid = bl_pktmp.TemplateId break } } default: continue } // 匹配成功,则该零件将不再进行对其它模板的匹配 if matched { break } } // 如果适配,则将该零件加入到开口拣料单 if matched { // 基于拣料单模板得到当前产线开口的拣料单 bl_pko.TemplateId = picktmpid if exist, pickorderid, err = pe.GetOpenPickOrderByTemplate(session, &bl_pko, wonr, attrcode, partid); err != nil { bflag = false break } if !exist { // 不存在开口拣料单则新建 if pickorderid, err = bl_pko.CreatePickOrder(session, pe, picktmpid); err != nil { bflag = false break } } // 将零件加入开口拣料单 if err = bl_pko.AddPickingPart(session, attrcode, bl_wopart, pickorderid); err != nil { bflag = false break } // 判断拣料单是否已满,满则下达并生成拣料单消息用于拣料单打印 if bl_pktmp.Picktemplatetab.Countmode == common.PKT_COUNT_MODE_BY_QTY { if released, err = bl_pko.TryToRelease(session, pickorderid, &bl_pktmp); err != nil { return } if released { // 生成用于打印的拣料单消息 bl_ordmsg = service.BL_Ordmsg{MsgType: common.MSG_TYPE_PICK, MsgObjid: pickorderid, MsgEvent: common.MSG_EVENT_PRINT} if err = bl_ordmsg.Create(session); err != nil { return } } } else { pkodict[pickorderid] = bl_pktmp } } } // 检查那些按工单计数的开口拣料单是否达到计数要求,如是则关闭这些拣料单 for pickorderid, bl_pktmp = range pkodict { if released, err = bl_pko.TryToRelease(session, pickorderid, &bl_pktmp); err != nil { return } if released { // 生成用于打印的拣料单消息 bl_ordmsg = service.BL_Ordmsg{MsgType: common.MSG_TYPE_PICK, MsgObjid: pickorderid, MsgEvent: common.MSG_EVENT_PRINT} if err = bl_ordmsg.Create(session); err != nil { return } } } // 完成工单所有零件的匹配,更新工单的拣料状态 if err = bl_wo.SetPickingStatus(session, 1); err != nil { bflag = false } if bflag { session.Commit() } else { session.Rollback() } session.Close() return }