package service import ( "errors" "fmt" "github.com/go-xorm/xorm" "leit.com/leit_seat_aps/common" "leit.com/leit_seat_aps/db" "time" ) // 拣料单模板 type BL_PickingTemplate struct { TemplateId string // 拣料单模板ID WorklineId string // 产线 PrinterId string // 打印机 AdaptWay string // A = 属性 ; P = 零件 AssignAttrDict map[int]db.Pln_picktemplate_attrlst // 分配的属性 AssignPartDict map[string]db.Pln_picktemplate_itemlst // 分配的零件号 Picktemplatetab db.Pln_picktemplate } // 拣料单 type BL_PickingOrder struct { OrderNr string TemplateId string PlanQty int FilledTotalQty int FilledOrderDict map[string]string // 已填充的工单 FillAttrDict map[int]int // 分配的属性 FillItemDict map[string]int // 分配的零件号 Pickordertab db.Pln_pickorder } // 拣料单零件数据对象 type PickingItemData struct { PartId string Qty int OemSeq int Attrcode int Workordernr string Wotab db.Pln_workorder } // 基于拣料单模板创建拣料单 func (bl_pko *BL_PickingOrder) CreatePickOrder(session *xorm.Session, pe *PickingEngine, picktmpid string) (pickorderid string, err error) { var ( pkordtab db.Pln_pickorder bl_pktmp BL_PickingTemplate ok bool ) // 查找拣料单模板是否存在 if bl_pktmp, ok = pe.PickingTmpDict[picktmpid]; !ok { err = errors.New("The specified picking template: " + picktmpid + " is not existing in the global mdata!") return } // 创建拣料单头 if pickorderid, err = SN_GetNextSnrBySession(pe.PickOrderSN, session); err != nil { return } pkordtab = db.Pln_pickorder{} pkordtab.Finr = db.G_FINR pkordtab.Pickorderid = pickorderid pkordtab.Picktemplateid = picktmpid pkordtab.Status = common.PKO_STATUS_PLANNED pkordtab.Worklineid = bl_pktmp.WorklineId pkordtab.Printerid = bl_pktmp.PrinterId pkordtab.Planqty = bl_pktmp.Picktemplatetab.Planqty pkordtab.Lastuser = "service" pkordtab.Credatuz = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss") if err = pkordtab.Insert(session); err != nil { return } bl_pko.OrderNr = pkordtab.Pickorderid bl_pko.TemplateId = picktmpid bl_pko.PlanQty = pkordtab.Planqty bl_pko.Pickordertab = pkordtab return } // 刷新拣料单当前已拣料信息, 属性字典/零件字典记录当前已填充属性或零件的总数 func (bl_pko *BL_PickingOrder) RefreshPickingStatus(bl_pktmp *BL_PickingTemplate) { var ( ok bool i, fillqty int ) // 计数模式 switch bl_pktmp.Picktemplatetab.Countmode { case common.PKT_COUNT_MODE_BY_WO: // 工单计数模式,收集所有已填充工单 bl_pko.FilledOrderDict = make(map[string]string) bl_pko.FilledTotalQty = 0 for i = 0; i < len(bl_pko.Pickordertab.Itemlst); i++ { bl_pko.FilledOrderDict[bl_pko.Pickordertab.Itemlst[i].Serialno] = bl_pko.Pickordertab.Itemlst[i].Serialno bl_pko.FilledTotalQty = bl_pko.FilledTotalQty + bl_pko.Pickordertab.Itemlst[i].Fillqty } case common.PKT_COUNT_MODE_BY_QTY: // 零件数量计数模式,收集所有零件总数 bl_pko.FilledTotalQty = 0 for i = 0; i < len(bl_pko.Pickordertab.Itemlst); i++ { bl_pko.FilledTotalQty = bl_pko.FilledTotalQty + bl_pko.Pickordertab.Itemlst[i].Fillqty } } // 判断模板适配类型并初始化字典而后填充 switch bl_pktmp.Picktemplatetab.Adaptway { case common.PKT_ADAPT_BY_ATTR: bl_pko.FillAttrDict = make(map[int]int) for i = 0; i < len(bl_pktmp.Picktemplatetab.Attrlst); i++ { bl_pko.FillAttrDict[bl_pktmp.Picktemplatetab.Attrlst[i].Attrcode] = 0 } // 遍历拣料单的已拣料项,计算各属性已填充数量 for i = 0; i < len(bl_pko.Pickordertab.Itemlst); i++ { if fillqty, ok = bl_pko.FillAttrDict[bl_pko.Pickordertab.Itemlst[i].Attrcode]; !ok { continue } fillqty = fillqty + bl_pko.Pickordertab.Itemlst[i].Fillqty bl_pko.FillAttrDict[bl_pko.Pickordertab.Itemlst[i].Attrcode] = fillqty } case common.PKT_ADAPT_BY_PART: bl_pko.FillItemDict = make(map[string]int) for i = 0; i < len(bl_pktmp.Picktemplatetab.Itemlst); i++ { bl_pko.FillItemDict[bl_pktmp.Picktemplatetab.Itemlst[i].Partid] = 0 } // 遍历拣料单的已拣料项,计算各零件已填充数量 for i = 0; i < len(bl_pko.Pickordertab.Itemlst); i++ { if fillqty, ok = bl_pko.FillItemDict[bl_pko.Pickordertab.Itemlst[i].Partid]; !ok { continue } fillqty = fillqty + bl_pko.Pickordertab.Itemlst[i].Fillqty bl_pko.FillItemDict[bl_pko.Pickordertab.Itemlst[i].Partid] = fillqty } } return } // 基于拣料单的已拣料状态判断是否可继续填充指定的属性或零件 func (bl_pko *BL_PickingOrder) IsFillable(wonr string, attrcode int, partid string, bl_pktmp *BL_PickingTemplate) (fillable bool, err error) { var ( ok bool ipos, fillqty int ) // 基于模板适配类型判断已填充数是否已到上限 fillable = true switch bl_pktmp.Picktemplatetab.Countmode { case common.PKT_COUNT_MODE_BY_WO: // 基于订单数 if len(bl_pko.FilledOrderDict) >= bl_pktmp.Picktemplatetab.Planqty { if _, ok = bl_pko.FilledOrderDict[wonr]; !ok { // 订单数满足的情况下,不可填充 fillable = false fmt.Println(" PKT_COUNT_MODE_BY_WO 不可填充 ") return } } case common.PKT_COUNT_MODE_BY_QTY: // 基于零件总数 if bl_pko.FilledTotalQty == bl_pktmp.Picktemplatetab.Planqty { // 总数已满足的情况下,不可填充 fillable = false fmt.Println(" PKT_COUNT_MODE_BY_QTY 不可填充 ") return } } // 订单数不满足的情况下,看该属性或零件数量是否已达标 switch bl_pktmp.Picktemplatetab.Adaptway { case common.PKT_ADAPT_BY_ATTR: ipos = bl_pktmp.Picktemplatetab.GetAttributePos(attrcode) if ipos < 0 { fillable = false // 属性不匹配,不可填充 fmt.Println(ipos, " 属性不存在模板中!") } else { if fillqty, ok = bl_pko.FillAttrDict[attrcode]; ok { if fillqty >= bl_pktmp.Picktemplatetab.Attrlst[ipos].Planqty { fillable = false fmt.Println(" 已填充数量>=计划数量", fillqty, bl_pktmp.Picktemplatetab.Attrlst[ipos].Planqty) } } } fmt.Println(" PKT_ADAPT_BY_ATTR 填充?= ", fillable) return case common.PKT_ADAPT_BY_PART: ipos = bl_pktmp.Picktemplatetab.GetPartPos(partid) if ipos < 0 { fillable = false // 属性不匹配,不可填充 } else { if fillqty, ok = bl_pko.FillItemDict[partid]; !ok { fillable = false } else { if bl_pktmp.Picktemplatetab.Itemlst[ipos].Planqty > fillqty { fillable = true } else { fillable = false } } } fmt.Println(" PKT_ADAPT_BY_PART 填充?= ", fillable) return } return } // 基于拣料单模板查找开口的拣料单(未下达的),如果存在多个,则返回最早新建的 func (bl_pko *BL_PickingOrder) GetOpenPickOrderByTemplate(session *xorm.Session, picktmpid string, attrcode int) (exist bool, pickorderid string, err error) { var ( i int pkordtab db.Pln_pickorder pkordtablst []db.Pln_pickorder ) exist = false // 获取最新创建已计划未下达的包装单 pkordtab = db.Pln_pickorder{} if exist, pkordtablst, err = pkordtab.GetOpenOrdersForTemplateBySession(session, picktmpid); err != nil { return } // 遍历开口拣料单适配 for i = 0; i < len(pkordtablst); i++ { bl_pko.OrderNr = pkordtablst[i].Pickorderid bl_pko.TemplateId = picktmpid bl_pko.PlanQty = pkordtablst[i].Planqty bl_pko.Pickordertab = pkordtablst[i] } if exist { pickorderid = pkordtab.Pickorderid } else { pickorderid = "" } return } // 将零件添加到开口包装单内 func (bl_pko *BL_PickingOrder) AddPickingPart(session *xorm.Session, attrcode int, bl_wopart BL_WorkOrder_Part, pickorderid string) (err error) { var ( pickordtab db.Pln_pickorder pickorditemtab db.Pln_pickorder_itemlst pos, ilen, i, iqty int ) // 获取拣料单完整数据,检查拣料单状态是否满足 pickordtab = db.Pln_pickorder{Pickorderid: pickorderid} if pickordtab, err = pickordtab.SelectOneBySession(session); err != nil { return } // 遍历拣料单子项,获取Pos,并将零件添加到拣料单 ilen = len(pickordtab.Itemlst) if ilen <= 0 { pos = 1 } else { pos = pickordtab.Itemlst[ilen-1].Pos + 1 } pickorditemtab = db.Pln_pickorder_itemlst{} pickorditemtab.Finr = db.G_FINR pickorditemtab.Pickorderid = pickorderid pickorditemtab.Pos = pos pickorditemtab.Partid = bl_wopart.Partid pickorditemtab.Descr1 = bl_wopart.Parttab.Descr1 pickorditemtab.Descr2 = bl_wopart.Parttab.Descr2 pickorditemtab.Planqty = bl_wopart.Qty pickorditemtab.Fillqty = bl_wopart.Qty pickorditemtab.Actqty = 0 pickorditemtab.Oemseq = bl_wopart.Workordertab.Oemseq pickorditemtab.Attrcode = attrcode pickorditemtab.Serialno = bl_wopart.Workordertab.Workordernr pickorditemtab.Status = common.PKO_STATUS_RELEASED pickorditemtab.Lastuser = "service" pickorditemtab.Credatuz = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss") if err = pickorditemtab.Insert(session); err != nil { return } // 更新拣料单: 填充数量和更新时间 pickordtab.Itemlst = append(pickordtab.Itemlst, pickorditemtab) iqty = 0 for i = 0; i < len(pickordtab.Itemlst); i++ { iqty = pickordtab.Itemlst[i].Fillqty + iqty } pickordtab.Pickorderid = pickorderid pickordtab.Fillqty = iqty pickordtab.Lastmodif = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss") if err = pickordtab.UpdateFields(session, "fillqty, lastmodif"); err != nil { return } return } // 尝试下达拣料单 func (bl_pko *BL_PickingOrder) TryToRelease(session *xorm.Session, pickorderid string, bl_pktmp *BL_PickingTemplate) (released bool, err error) { var ( pickordtab db.Pln_pickorder i, fillqty int releasable, ok bool ) pickordtab = db.Pln_pickorder{Pickorderid: pickorderid} if pickordtab, err = pickordtab.SelectOneBySession(session); err != nil { return } bl_pko.Pickordertab = pickordtab bl_pko.RefreshPickingStatus(bl_pktmp) releasable = true switch bl_pktmp.Picktemplatetab.Countmode { case common.PKT_COUNT_MODE_BY_QTY: // 逻辑1: 以填充数量是否达到计数总量为标准 if bl_pko.FilledTotalQty >= bl_pko.Pickordertab.Planqty { switch bl_pktmp.Picktemplatetab.Adaptway { case common.PKT_ADAPT_BY_ATTR: for i = 0; i < len(bl_pktmp.Picktemplatetab.Attrlst); i++ { if bl_pktmp.Picktemplatetab.Attrlst[i].Mandatory <= 0 { continue } // 强制属性的数量校验 if fillqty, ok = bl_pko.FillAttrDict[bl_pktmp.Picktemplatetab.Attrlst[i].Attrcode]; !ok { releasable = false break } else { if fillqty < bl_pktmp.Picktemplatetab.Attrlst[i].Planqty { releasable = false break } } } case common.PKT_ADAPT_BY_PART: for i = 0; i < len(bl_pktmp.Picktemplatetab.Itemlst); i++ { if bl_pktmp.Picktemplatetab.Itemlst[i].Mandatory <= 0 { continue } // 强制属性的数量校验 if fillqty, ok = bl_pko.FillItemDict[bl_pktmp.Picktemplatetab.Itemlst[i].Partid]; !ok { releasable = false break } else { if fillqty < bl_pktmp.Picktemplatetab.Itemlst[i].Planqty { releasable = false break } } } default: releasable = false } } else { // 总量未到达不可下达 releasable = false } case common.PKT_COUNT_MODE_BY_WO: if len(bl_pko.FilledOrderDict) >= bl_pko.Pickordertab.Planqty { switch bl_pktmp.Picktemplatetab.Adaptway { case common.PKT_ADAPT_BY_ATTR: for i = 0; i < len(bl_pktmp.Picktemplatetab.Attrlst); i++ { if bl_pktmp.Picktemplatetab.Attrlst[i].Mandatory <= 0 { continue } // 强制属性的数量校验 if fillqty, ok = bl_pko.FillAttrDict[bl_pktmp.Picktemplatetab.Attrlst[i].Attrcode]; !ok { releasable = false break } else { if fillqty < bl_pktmp.Picktemplatetab.Attrlst[i].Planqty { releasable = false break } } } case common.PKT_ADAPT_BY_PART: for i = 0; i < len(bl_pktmp.Picktemplatetab.Itemlst); i++ { if bl_pktmp.Picktemplatetab.Itemlst[i].Mandatory <= 0 { continue } // 强制属性的数量校验 if fillqty, ok = bl_pko.FillItemDict[bl_pktmp.Picktemplatetab.Itemlst[i].Partid]; !ok { releasable = false break } else { if fillqty < bl_pktmp.Picktemplatetab.Itemlst[i].Planqty { releasable = false break } } } default: releasable = false } } else { releasable = false } } if releasable { pickordtab.Fillqty = bl_pko.FilledTotalQty pickordtab.Status = common.PKO_STATUS_RELEASED pickordtab.Lastuser = "service" pickordtab.Lastmodif = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss") if err = pickordtab.UpdateFields(session, "fillqty, status, lastuser, lastmodif"); err != nil { return } released = true return } return } // 下达拣料单 func (bl_pko *BL_PickingOrder) Release(session *xorm.Session) (err error) { var i int if bl_pko.Pickordertab.Status < common.PKO_STATUS_RELEASED { // 遍历子项看是否有未下达的 for i = 0; i < len(bl_pko.Pickordertab.Itemlst); i++ { if bl_pko.Pickordertab.Itemlst[i].Status < common.PKO_STATUS_RELEASED { err = errors.New(fmt.Sprintf("Pickorder %s item %s status is %d,not allow to release!", bl_pko.Pickordertab.Pickorderid, bl_pko.Pickordertab.Itemlst[i].Partid, bl_pko.Pickordertab.Itemlst[i].Status)) return } } // 更新拣料单头的状态为下达状态 bl_pko.Pickordertab.Status = common.PKO_STATUS_RELEASED bl_pko.Pickordertab.Lastuser = "service" bl_pko.Pickordertab.Lastmodif = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss") if err = bl_pko.Pickordertab.UpdateFields(session, "actqty, status, lastuser, lastmodif"); err != nil { return } } return }