package service import ( "errors" "fmt" "github.com/go-xorm/xorm" "leit.com/leit_seat_aps/common" "leit.com/leit_seat_aps/db" "leit.com/leit_seat_aps/glog" "strings" "time" ) // 用于生产包装的项目主数据对象 type ProdProject struct { Projectid string Projecttab db.Prod_project // 项目表 Packtmpldict map[string]BL_ProdPackTmp // 生产包装模板 Paktypdict map[string]db.Prod_packtype // 生产包装类型 Sgdict map[string]db.Me_supplygroup // 供应组 Pfdict map[string]db.Me_partfamily // 零件族 } // 加载项目的主数据 func (pproj *ProdProject) LoadMasterData() (err error) { // 读取项目的零件族主数据 if err = pproj.LoadPartFamily(); err != nil { return } // 读取项目的包装类型主数据 if err = pproj.LoadPackType(); err != nil { return } // 读取项目的供应组主数据 if err = pproj.LoadSupplyGroup(); err != nil { return } // 读取项目的发运包装模板主数据 if err = pproj.LoadPackageTemplate(); err != nil { return } return } // 加载项目的发运包装模板 func (pproj *ProdProject) LoadPackageTemplate() (err error) { var ( paktmpltab db.Prod_packtemplate paktmpltablst []db.Prod_packtemplate bl_sp BL_ProdPackTmp i,j int ) // 初始化 pproj.Packtmpldict = make(map[string]BL_ProdPackTmp) paktmpltab = db.Prod_packtemplate{} // 读取项目发运包装模板数据 if paktmpltablst, err = paktmpltab.GetProjectAll(pproj.Projectid); err != nil { return } for i = 0; i < len(paktmpltablst); i++ { bl_sp = BL_ProdPackTmp{} bl_sp.SgDict = make(map[string]string) bl_sp.PackTmplId = paktmpltablst[i].Packtemplateid bl_sp.Paktmpltab = paktmpltablst[i] for j = 0; j < len(paktmpltablst[i].Itemlst); j++ { bl_sp.SgDict[paktmpltablst[i].Itemlst[j].Supplygroupid] = paktmpltablst[i].Itemlst[j].Supplygroupid } pproj.Packtmpldict[bl_sp.PackTmplId] = bl_sp } return } // 加载包装类型 func (pproj *ProdProject) LoadPackType() (err error) { var ( paktyptab db.Prod_packtype paktyptablst []db.Prod_packtype i int ) // 初始化 pproj.Paktypdict = make(map[string]db.Prod_packtype) paktyptab = db.Prod_packtype{} paktyptablst = []db.Prod_packtype{} if paktyptablst, err = paktyptab.GetProjectAll(pproj.Projectid); err != nil { return } for i = 0; i < len(paktyptablst); i++ { pproj.Paktypdict[paktyptablst[i].Packtypeid] = paktyptablst[i] } return } // 加载供应组信息 func (pproj *ProdProject) LoadSupplyGroup() (err error) { var ( sgtab db.Me_supplygroup sgtablst []db.Me_supplygroup i int ) // 初始化 pproj.Sgdict = make(map[string]db.Me_supplygroup) sgtab = db.Me_supplygroup{} sgtablst = []db.Me_supplygroup{} if sgtablst, err = sgtab.GetProjectAll(pproj.Projectid); err != nil { return } for i = 0; i < len(sgtablst); i++ { pproj.Sgdict[sgtablst[i].Supplygroupid] = sgtablst[i] } return } // 获取项目的零件族字典 func (pproj *ProdProject) LoadPartFamily() (err error) { var ( pftab db.Me_partfamily pftablst []db.Me_partfamily i int ) // 初始化项目的零件族字典 pproj.Pfdict = make(map[string]db.Me_partfamily) pftab = db.Me_partfamily{} if pftablst, err = pftab.GetProjectPfList(pproj.Projectid); err != nil { return } // 遍历零件族列表并写入字典 for i = 0; i < len(pftablst); i++ { pproj.Pfdict[pftablst[i].Partfamilyid] = pftablst[i] } return } // 获取项目供应组的包装排序 func (pproj *ProdProject) GetSupplyGroupPackSortWay(sgid string) (sortway string) { var ( bl_paktmp BL_ProdPackTmp paktmpitemtab db.Prod_packtemplate_itemlst paktyptab db.Prod_packtype ok bool ) // 判断供应组 if _, ok = pproj.Sgdict[sgid]; !ok { glog.Infoln("包装匹配", "工单的供应组在当前项目中不存在!",sgid,pproj.Projectid) sortway = common.MESPACK_SORT_RELSEQ return } // 获取供应组对应的包装单模板 ok = false for _, bl_paktmp = range pproj.Packtmpldict { for _, paktmpitemtab = range bl_paktmp.Paktmpltab.Itemlst { if paktmpitemtab.Supplygroupid == sgid { ok = true break } } if ok { break } } if !ok { sortway = common.MESPACK_SORT_RELSEQ glog.Infoln("包装匹配", "工单的供应组没有对应的包装模板!",sgid,pproj.Projectid) return } // 获取包装模板的包装类型 if paktyptab, ok = pproj.Paktypdict[bl_paktmp.Paktmpltab.Packtypeid]; !ok { sortway = common.MESPACK_SORT_RELSEQ glog.Infoln("包装匹配", "工单的供应组对应的包装模板的包装类型在当前项目中不存在!",sgid,bl_paktmp.Paktmpltab.Packtemplateid,bl_paktmp.Paktmpltab.Packtypeid) return } sortway = paktyptab.Sortorder return } // 判断两者的pfid是否一致 func (pproj *ProdProject) IsSamePartFamily(sgid, chksgid string)(same bool){ var( sgtab, chksgtab db.Me_supplygroup ) sgtab, _ = pproj.Sgdict[sgid] chksgtab, _ = pproj.Sgdict[chksgid] if chksgtab.Partfamilyid != sgtab.Partfamilyid { return false }else{ return true } } // 基于项目的供应组获取需要生产包装的生产订单 func (pproj *ProdProject) CreatePackOrderRelMsg(packordid string, session *xorm.Session)(err error){ var( bl_msg BL_Mesmsg ) bl_msg = BL_Mesmsg{} bl_msg.MsgType = common.MESMSG_TYPE_PACK bl_msg.MsgEvent = common.MESMSG_EVENT_RELPACK bl_msg.MsgObjid = packordid bl_msg.MsgiPara1 = 0 bl_msg.MsgiPara2 = 0 bl_msg.MsgcPara1 = pproj.Projectid bl_msg.MsgcPara2 = "" if err = bl_msg.CreateProdPackMsg(session); err != nil { err = errors.New(fmt.Sprintf("插入包装单:%s下达消息失败:%v", packordid, err)) return } return } // 基于指定起始的OEMSEQ号按oemseq和worklineid排序依次获取未进行生产包装的生产订单 func (pproj *ProdProject) GetUnpackedWorkorderListByOemseq()(wotablst []db.Pln_workorder, err error){ var ( i int wotab db.Pln_workorder wopacktab db.Prod_wo_packstatus vwotablst []db.VWorkOrderPackStatus ) // 获取项目的起始OEMSEQ, 查询未包装订单 if vwotablst, err = wopacktab.GetUnpackedWOByStartOemseq(pproj.Projecttab.Startoemseq, pproj.Projecttab.Endoemseq); err != nil { err = errors.New(fmt.Sprintf("基于起始OEMSEQ:%d获取未包装生产订单失败:%v",pproj.Projecttab.Startoemseq, err)) return } // 返回数据 wotablst = []db.Pln_workorder{} for i = 0; i < len(vwotablst); i++ { wotab = vwotablst[i].Pln_workorder wotab.Clipped() wotablst = append(wotablst, wotab) } return } // 下达包装单 // 1. 必须满包,检查包装项数量是否满足 // 2. 可以不满包,检查已下达的OEMSEQ数是否达标,如果不达标,则检查剩余填充项是否存在维保的WO(基于OEMSEQ+SGID检索) func (pproj *ProdProject) ReleasePackOrder(session *xorm.Session, bl_pakord BL_ProdPackOrder) (relstat bool, err error) { var ( i int pakordtab db.Prod_packorder wotab db.Pln_workorder bl_paktpl BL_ProdPackTmp ok,exist bool ) relstat= false // 查询包装单数据 pakordtab = db.Prod_packorder{Finr: db.G_FINR, Packorderid: bl_pakord.PackorderId} if bl_pakord.Pkotab, err = pakordtab.SelectOneBySession(session); err != nil { return } // 获取包装单完整数据,检查包装单状态是否满足 if bl_pakord.Pkotab.Status >= common.PKO_STATUS_RELEASED { return } // 获取包装单的模板 if bl_paktpl, ok = pproj.Packtmpldict[bl_pakord.Pkotab.Packtemplateid]; !ok { err = errors.New(fmt.Sprintf("Packorder %s template %s is not existing in global template dict!", bl_pakord.Pkotab.Packorderid, bl_pakord.Pkotab.Packtemplateid)) return } // 更新包装单模板和包装单的填充状态 bl_paktpl.RefreshFillStatus() bl_pakord.RefreshFillStatus() // 基于不同类型的包装下达模式进行处理 if bl_paktpl.Paktmpltab.Unfullfillable > 0 { if bl_pakord.OemseqCount >= bl_paktpl.OemseqCount { // 检查剩余未填充的工单是否存在 ok = true for i = 0; i < len(bl_pakord.Pkotab.Itemlst); i++{ if bl_pakord.Pkotab.Itemlst[i].Status >= common.PKO_STATUS_RELEASED{ continue } if exist, wotab, err = wotab.GetByProjectOemSeqSg(session, bl_pakord.Pkotab.Projnr,bl_pakord.Pkotab.Itemlst[i].Oemseq,bl_pakord.Pkotab.Itemlst[i].Supplygroupid); err != nil{ err = errors.New(fmt.Sprintf("查找项目 %s OEMSEQ %s 供应组 %s 的工单失败!", bl_pakord.Pkotab.Projnr,bl_pakord.Pkotab.Itemlst[i].Oemseq,bl_pakord.Pkotab.Itemlst[i].Supplygroupid)) return } if exist && (wotab.Packstatus <= 0){ ok = false break } } if ok { // 达到下达条件 if err = bl_pakord.Release(session, bl_pakord.FillQty); err != nil { return } relstat= true } } } else { // 检查包装项是否都已填满,如果是,则释放包装订单 if bl_pakord.FillQty >= bl_pakord.Pkotab.Planqty { // 达到下达条件 if err = bl_pakord.Release(session, bl_pakord.FillQty); err != nil { return } relstat= true } } return } // 基于指定供应组寻找匹配的包装单模板 func (pproj *ProdProject) GetPackTemplateListBySupplyGroup(sgid string) (rettpldict map[string]string) { var ( tpldict map[string]BL_ProdPackTmp bl_paktpl, bl_paktpl2 BL_ProdPackTmp i int matched bool ) // 初始化 tpldict = make(map[string]BL_ProdPackTmp) // 基于sgid查询获取包装模板ID for _, bl_paktpl = range pproj.Packtmpldict { matched = false for i = 0; i < len(bl_paktpl.Paktmpltab.Itemlst); i++ { if strings.TrimSpace(sgid) == strings.TrimSpace(bl_paktpl.Paktmpltab.Itemlst[i].Supplygroupid) { matched = true break } } if matched { tpldict[bl_paktpl.Paktmpltab.Packtemplateid] = bl_paktpl } } // 遍历获取的模板ID,获取具有相同同步号的模板 rettpldict = make(map[string]string) for _, bl_paktpl = range tpldict { rettpldict[bl_paktpl.Paktmpltab.Packtemplateid] = bl_paktpl.Paktmpltab.Packtemplateid for _, bl_paktpl2 = range pproj.Packtmpldict { if bl_paktpl.Paktmpltab.Syncnr == bl_paktpl2.Paktmpltab.Syncnr { rettpldict[bl_paktpl2.Paktmpltab.Packtemplateid] = bl_paktpl2.Paktmpltab.Packtemplateid } } } return } // 获取指定项目,OEMSEQ和supplygroup的开口包装 func (pproj *ProdProject) GetOpenPackOrderByOemseqSupplyGroup(wotab db.Pln_workorder) (exist bool, bl_pakord BL_ProdPackOrder, err error) { var( pakord db.Prod_packorder pakordlst []db.Prod_packorder ) if pakordlst, err = pakord.GetByOemSeqSupplyGroup(pproj.Projectid, common.ValueToInt(wotab.Oemseq, 0), wotab.Supplygroupid); err != nil { err = errors.New(fmt.Sprintf("基于项目 %s Oemseq %d 供应组 %s 查询开口包装单失败!", pproj.Projectid, wotab.Oemseq, wotab.Supplygroupid)) return } exist = false if len(pakordlst) > 0 { bl_pakord = BL_ProdPackOrder{PackorderId: pakordlst[0].Packorderid, Pkotab: pakordlst[0]} exist = true return } return } // 获取指定项目,schedseq和supplygroup的开口包装 func (pproj *ProdProject) GetOpenPackOrderBySupplyGroup(sgid string) (exist bool, bl_pakord BL_ProdPackOrder, err error) { var( pakord db.Prod_packorder pakordlst []db.Prod_packorder ) if pakordlst, err = pakord.GetOpenOnesBySupplyGroup(pproj.Projectid, sgid); err != nil { err = errors.New(fmt.Sprintf("基于项目 %s 供应组 %s 查询开口包装单失败!", pproj.Projectid, sgid)) return } exist = false if len(pakordlst) > 0 { bl_pakord = BL_ProdPackOrder{PackorderId: pakordlst[0].Packorderid, Pkotab: pakordlst[0]} exist = true return } return } // 获取指定项目,checksequence的开口包装 func (pproj *ProdProject) GetOpenPackOrderBySchedSeq(session *xorm.Session, cs int) (bl_pakordlst []BL_ProdPackOrder, err error) { var( i int pakord db.Prod_packorder pakordlst []db.Prod_packorder bl_pakord BL_ProdPackOrder ) bl_pakordlst = []BL_ProdPackOrder{} if pakordlst, err = pakord.GetByCheckSeq(session, pproj.Projectid, cs); err != nil { err = errors.New(fmt.Sprintf("基于项目 %s CheckSequence %d 查询开口包装单失败!", pproj.Projectid, cs)) return } for i = 0; i < len(pakordlst); i++ { bl_pakord = BL_ProdPackOrder{PackorderId: pakordlst[i].Packorderid, Pkotab: pakordlst[i]} bl_pakordlst = append(bl_pakordlst, bl_pakord) } return } func (pproj *ProdProject) CreatePackOrderByOemseq(session *xorm.Session, wotab db.Pln_workorder, sortway string) (bl_polst []BL_ProdPackOrder, err error) { var ( bl_pak BL_ProdPackTmp bl_pakord BL_ProdPackOrder paktmpitemtab db.Prod_packtemplate_itemlst syncid, boxid, paktpl string sgdict map[string]string tpldict map[string]string ok bool ) // 初始化 bl_polst = []BL_ProdPackOrder{} tpldict = make(map[string]string) // 1. 基于供应组ID获取包含它的模板ID列表 tpldict = pproj.GetPackTemplateListBySupplyGroup(wotab.Supplygroupid) if len(tpldict) <= 0 { err = errors.New(fmt.Sprintf("供应组%s 没有任何适配的包装模板!", wotab.Supplygroupid)) return } // 2. 如果有多个匹配模板,则获取自动同步号 if len(tpldict) > 1 { if strings.TrimSpace(pproj.Projecttab.Prodpacksync_snr) != "" { if syncid, err = SN_GetNextSnrBySession(strings.TrimSpace(pproj.Projecttab.Prodpacksync_snr), session); err != nil { return } } else { if syncid, err = SN_GetNextSnrBySession("PRODPACKSYNC", session); err != nil { return } } } else { syncid = "" } // 3. 获取包装模板 sgdict = make(map[string]string) for _, paktpl = range tpldict { if bl_pak, ok = pproj.Packtmpldict[paktpl]; !ok { err = errors.New(fmt.Sprintf("包装模板 %s 不存在!", paktpl)) return } for _, paktmpitemtab = range bl_pak.Paktmpltab.Itemlst { sgdict[paktmpitemtab.Supplygroupid] = paktmpitemtab.Supplygroupid } } // 4. 获取包装箱流水号( 默认取多个模板最后一个模板为参照) if bl_pak.Paktmpltab.Boxsn != "" { if boxid, err = SN_GetNextSnrBySession(bl_pak.Paktmpltab.Boxsn, session); err != nil { return } } else { boxid = "" } // 5. 根据获取的模板列表依次创建包装单,并设置同步号 for _, paktpl = range tpldict { if bl_pakord, err = pproj.CreatePackOrder(paktpl, syncid, boxid, sortway, wotab, session); err != nil { return } bl_polst = append(bl_polst, bl_pakord) fmt.Println("--------------------新建包装:",bl_pakord.PackorderId,"---------------") } return } func (pproj *ProdProject) CreatePackOrder(paktplid, syncid, boxid, sortway string, wotab db.Pln_workorder, session *xorm.Session) (bl_pako BL_ProdPackOrder, err error) { var ( pkoitemtab db.Prod_packorder_itemlst bl_pak BL_ProdPackTmp i int ok bool pkoid string ) // 获取包装模板 if bl_pak, ok = pproj.Packtmpldict[paktplid]; !ok { err = errors.New(fmt.Sprintf("包装模板 %s 不存在!", paktplid)) return } // 获取项目的包装单号 if strings.TrimSpace(bl_pak.Paktmpltab.Packordersn) != "" { if pkoid, err = SN_GetNextSnrBySession(strings.TrimSpace(bl_pak.Paktmpltab.Packordersn), session); err != nil { return } } else { if pkoid, err = SN_GetNextSnrBySession(strings.TrimSpace(pproj.Projecttab.Prodpack_snr), session); err != nil { return } } // 创建包装单头 bl_pako = BL_ProdPackOrder{} bl_pako.Pkotab.Finr = db.G_FINR bl_pako.Pkotab.Packorderid = pkoid bl_pako.Pkotab.Packtemplateid = bl_pak.PackTmplId bl_pako.Pkotab.Projnr = bl_pak.Paktmpltab.Projnr bl_pako.Pkotab.Packtypeid = bl_pak.Paktmpltab.Packtypeid bl_pako.Pkotab.Boxsn = boxid bl_pako.Pkotab.Syncsn = syncid bl_pako.Pkotab.Orderinfo = bl_pak.Paktmpltab.Syncflag bl_pako.Pkotab.Planqty = bl_pak.Paktmpltab.Planqty bl_pako.Pkotab.Actqty = 0 bl_pako.Pkotab.Printerid = bl_pak.Paktmpltab.Printerid bl_pako.Pkotab.Templatefile = bl_pak.Paktmpltab.Templatefile bl_pako.Pkotab.Status = common.PKO_STATUS_PLANNED bl_pako.Pkotab.Loadstatus = common.PKO_STATUS_UNLOADED bl_pako.Pkotab.Credatuz = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss") bl_pako.Pkotab.Lastuser = "service" bl_pako.Pkotab.Itemlst = []db.Prod_packorder_itemlst{} for i = 0; i < len(bl_pak.Paktmpltab.Itemlst); i++ { pkoitemtab = db.Prod_packorder_itemlst{} pkoitemtab.Finr = db.G_FINR pkoitemtab.Packorderid = pkoid pkoitemtab.Supplygroupid = bl_pak.Paktmpltab.Itemlst[i].Supplygroupid pkoitemtab.Pos = bl_pak.Paktmpltab.Itemlst[i].Pos pkoitemtab.Poscode = bl_pak.Paktmpltab.Itemlst[i].Poscode pkoitemtab.Seq = bl_pak.Paktmpltab.Itemlst[i].Seq if sortway == common.MESPACK_SORT_OEMSEQ { pkoitemtab.Oemseq = common.ValueToInt(wotab.Oemseq, 0) + bl_pak.Paktmpltab.Itemlst[i].Seq - 1 } pkoitemtab.Planqty = bl_pak.Paktmpltab.Itemlst[i].Planqty pkoitemtab.Actqty = 0 pkoitemtab.Status = common.PKO_STATUS_PLANNED pkoitemtab.Credatuz = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss") pkoitemtab.Lastuser = "service" bl_pako.Pkotab.Itemlst = append(bl_pako.Pkotab.Itemlst, pkoitemtab) } if err = bl_pako.Pkotab.Insert(session); err != nil { return } bl_pako.PlanQty = bl_pak.Paktmpltab.Planqty bl_pako.PackorderId = pkoid return } // 将生产订单加入包装单 func (pproj *ProdProject) AddWOToPackOrder(wotab db.Pln_workorder, bl_pakord *BL_ProdPackOrder, sortway string, session *xorm.Session) (success bool, err error) { var ( pakordtab db.Prod_packorder pakstatab db.Prod_wo_packstatus i,pos,seq int ) // 获取包装单完整数据 pakordtab = db.Prod_packorder{Finr: db.G_FINR, Packorderid: bl_pakord.PackorderId} if bl_pakord.Pkotab, err = pakordtab.SelectOneBySession(session); err != nil { return } // 检查包装单状态是否满足 success = false if bl_pakord.Pkotab.Status >= common.PKO_STATUS_RELEASED { return } // 遍历包装单项,匹配WO并更新 pos = -1 for i = 0; i < len(bl_pakord.Pkotab.Itemlst); i++ { switch sortway { case common.MESPACK_SORT_OEMSEQ: if (bl_pakord.Pkotab.Itemlst[i].Supplygroupid == wotab.Supplygroupid) && bl_pakord.Pkotab.Itemlst[i].Oemseq == common.ValueToInt(wotab.Oemseq,0) { success = true pos = i } case common.MESPACK_SORT_RELSEQ: if bl_pakord.Pkotab.Itemlst[i].Status < common.PKO_STATUS_RELEASED && bl_pakord.Pkotab.Itemlst[i].Supplygroupid == wotab.Supplygroupid { success = true pos = i } } // 找到WO对应的包装项更新对应的状态和OEMSEQ信息 if success { // 更新包装子项的计划包装信息 bl_pakord.Pkotab.Itemlst[i].Status = common.PKO_STATUS_RELEASED bl_pakord.Pkotab.Itemlst[i].Workordernr = wotab.Workordernr bl_pakord.Pkotab.Itemlst[i].Oemseq = common.ValueToInt(wotab.Oemseq,0) bl_pakord.Pkotab.Itemlst[i].Lastmodif = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss") if !bl_pakord.Pkotab.Itemlst[i].UpdateBySession(session) { err = errors.New("Failed to update jit_packorder_itemlst!") return } // 新建包装单和生产订单的关系 pakstatab = db.Prod_wo_packstatus{} pakstatab.Finr = db.G_FINR pakstatab.Workordernr = wotab.Workordernr pakstatab.Packorderid = bl_pakord.Pkotab.Packorderid pakstatab.Projnr = bl_pakord.Pkotab.Projnr pakstatab.Packstatus = 1 pakstatab.Lastuser = "pack_service" pakstatab.Credatuz = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss") if !pakstatab.UpdateBySession(session) { err = errors.New(fmt.Sprintf("将生产订单%s更新到包装单%s的状态表失败!", wotab.Workordernr,bl_pakord.Pkotab.Packorderid)) return } seq = bl_pakord.Pkotab.Itemlst[i].Seq break } } // 遍历包装单,根据pos插入的WO更新其它包装项 if success && sortway == common.MESPACK_SORT_OEMSEQ { for i = 0; i < len(bl_pakord.Pkotab.Itemlst); i++ { if i == pos || bl_pakord.Pkotab.Itemlst[i].Status >= common.PKO_STATUS_RELEASED { continue } // 如果模板中的SEQ一致,尝试更新OEMSEQ if bl_pakord.Pkotab.Itemlst[i].Oemseq <= 0{ bl_pakord.Pkotab.Itemlst[i].Oemseq = common.ValueToInt(wotab.Oemseq,0) + bl_pakord.Pkotab.Itemlst[i].Seq - seq bl_pakord.Pkotab.Itemlst[i].Lastmodif = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss") if !bl_pakord.Pkotab.Itemlst[i].UpdateBySession(session) { err = errors.New("Failed to update jit_packorder_itemlst!") return } } } } return }