package calloff import ( "encoding/json" "encoding/xml" "fmt" "github.com/go-xorm/xorm" "io" "io/ioutil" "leit.com/leit_seat_aps/common" "leit.com/leit_seat_aps/db" "leit.com/leit_seat_aps/etcd" "leit.com/leit_seat_aps/glog" "leit.com/leit_seat_aps/service" "os" "regexp" "strconv" "strings" "time" ) // Calloff文件解析和保存 func ParseCalloffNew() { for { var ( err error projtab db.Me_project projtablst []db.Me_project cfland CalloffLandData cfProj service.CalloffProject rd []os.FileInfo fi os.FileInfo edi_file string mail db.Sendmailtab matched bool ) projtab = db.Me_project{} if projtablst, err = projtab.GetAllActive(); err != nil { glog.InfoExtln("Calloff解析", "Failed to get project list!") return } for i, _ := range projtablst { cfProj = service.CalloffProject{} cfProj.Projecttab = projtablst[i] cfProj.Projectid = projtablst[i].Projectid fmt.Println("Ready to load data for project:", projtablst[i].Projectid) // 读取文件夹内的文件并解析 if rd, err = ioutil.ReadDir(cfProj.Projecttab.Calloff_folder + "/inbox"); err != nil { return } rds := common.SortByTime(rd) for _, fi = range rds { if fi.IsDir() { continue } edi_file = cfProj.Projecttab.Calloff_folder + "/inbox" + "/" + fi.Name() // 判断文件的合规性 if matched, err = regexp.MatchString(cfProj.Projecttab.Calloff_filename_regexp, fi.Name()); err != nil { glog.InfoExtln("Calloff解析", "Failed to match EDI file name: due to: ", fi.Name(), err) os.Rename(edi_file, cfProj.Projecttab.Calloff_folder+"/errbox"+"/"+fi.Name()) continue } if !matched { glog.InfoExtln("Calloff解析", "The specified EDI file: doesn't match the required name specification!", fi.Name()) os.Rename(edi_file, cfProj.Projecttab.Calloff_folder+"/errbox"+"/"+fi.Name()) continue } // 解析CALLOFF文件到字典 fmt.Println("Ready to read tod data......") cfland = CalloffLandData{} cfland.Projnr = projtablst[i].Projectid cfland.Edifile = edi_file if err = cfland.ReadCalloffData(edi_file); err != nil { glog.InfoExtln("Calloff解析", "Failed to parse Calloff file due to: ", err) os.Rename(edi_file, cfProj.Projecttab.Calloff_folder+"/errbox"+"/"+fi.Name()) return } // 保存CALLOFF字典到临时缓存表 if err = cfland.SaveCalloffData(); err != nil { glog.InfoExtln("Calloff解析", "Failed to save Calloff parse result due to: ", err) //发邮件 host := projtablst[i].Emailserver_host + ":" + common.ValueToString(projtablst[i].Emailserver_port, "") body := "项目号: " + projtablst[i].Projectid + "\r\nEdifile :" + fi.Name() + "\r\nErrorinfo :" + err.Error() mail.Status = "waiting" mail.Body = body mail.Subject = "calloff解析错误" mail.Name = projtablst[i].From_email mail.Tomail = projtablst[i].Calloff_error_to_recievers mail.Host = host mail.Password = projtablst[i].From_pwd mail.Username = projtablst[i].From_email err = mail.Add() os.Rename(edi_file, cfProj.Projecttab.Calloff_folder+"/errbox"+"/"+fi.Name()) continue } // 将文件移到outbox os.Rename(edi_file, cfProj.Projecttab.Calloff_folder+"/outbox"+"/"+fi.Name()) } } time.Sleep(10 * time.Second) } } // 读取Calloff信息并生成发运包装 func ParseCalloffOrder() { for { var ( err error i, j, k, prevCS, m, n int projtab db.Me_project projtablst []db.Me_project cfProj service.CalloffProject cflandtab db.Pln_calloffdata_landing cflandtablst []db.Pln_calloffdata_landing cflandtablst2 []db.Pln_calloffdata_landing cftab db.Pln_calloffdata_landing cftablst []db.Pln_calloffdata_landing edictrltab db.Edi_control bl_co service.BL_CustOrder bl_prevco service.BL_CustOrder wotab db.Pln_workorder exist, ok, audit, relstat, stop bool prevOemord string sgdict map[string]string bl_pakordlst []service.BL_PackOrder bl_pakord service.BL_PackOrder cferror db.Pln_calloff_errorlst errorlst []db.Pln_calloff_errorlst mail db.Sendmailtab session *xorm.Session ) projtab = db.Me_project{} if projtablst, err = projtab.GetAllActive(); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "Failed to get project list!") return } for i, _ = range projtablst { cfProj = service.CalloffProject{} cfProj.Projecttab = projtablst[i] cfProj.Projectid = projtablst[i].Projectid glog.InfoExtln("CALLOFF-Debug", "----------------循环读取Calloff项目", projtablst[i].Projectid, "----------------") // 判断calloff是否已暂停 edictrltab = db.Edi_control{Projectid: projtablst[i].Projectid, Ediid: "CALLOFF"} if edictrltab, err = edictrltab.SelectOne(); edictrltab.Enabled <= 0 { continue } // 加载项目主数据 fmt.Println("Ready to load data for project:", projtablst[i].Projectid) if err = cfProj.LoadMasterData(); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "Failed to load project master data due to: !", err) return } // 循环读取未处理的Calloff消息,按零件族和CheckSequence排序 cflandtab = db.Pln_calloffdata_landing{Projnr: cfProj.Projectid} if cflandtablst, err = cflandtab.GetUnparsedLandingData(); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "Failed to get unparsed calloff landding data due to:", err) return } // 遍历未处理的Calloff消息 for j = 0; j < len(cflandtablst); j++ { // 判断calloff是否已暂停 edictrltab = db.Edi_control{Projectid: projtablst[i].Projectid, Ediid: "CALLOFF"} if edictrltab, err = edictrltab.SelectOne(); edictrltab.Enabled <= 0 { break } errorlst = []db.Pln_calloff_errorlst{} glog.InfoExtln("CALLOFF-Debug", j, "-- calloff 解析请求", cflandtablst[j]) // 读取项目各零件族解析的最大CheckSequence号 if err = cfProj.LoadPartFamilyMaxParsedCheckSequence(); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "Failed to load project parsed max check sequence data for each partfamily due to: ", err) return } // 验证Calloff有效性 // 1. 基于零件族判断CheckSequence是否连续 if projtablst[i].Calloff_verify_checksequence > 0 { if prevCS, ok = cfProj.Pfcsdict[cflandtablst[j].Partfamilyid]; !ok { glog.InfoExtln("读取Calloff信息并生成发运包装", "CheckSequence不连续:", prevCS, "==>", cflandtablst[j].Checksequence) return } // 检查checksequence是否连续,如果不连续查询两者之间是否有报错的解析记录,如果没有报错,如果有继续不处理 if prevCS > 0 && prevCS+1 != cflandtablst[j].Checksequence { if exist, err = cflandtablst[j].AnyErrorRecordBetweenCheckSequence(cfProj.Projectid, cflandtablst[j].Partfamilyid, prevCS, cflandtablst[j].Checksequence); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "查询零件族:", cflandtablst[j].Partfamilyid, "checksequence区间失败:", prevCS, cflandtablst[j].Checksequence) return } if exist { continue } else { cferror = db.Pln_calloff_errorlst{} cferror.Finr = db.G_FINR cferror.Calloffnr = cflandtablst[j].Calloffnr cferror.Errortype = common.CALLOFF_CHECK_SEQUENCE cferror.Consumeplant = cflandtablst[j].Consumeplant cferror.Partfamilyid = cflandtablst[j].Partfamilyid cferror.Oemordernr = cflandtablst[j].Oemordernr cferror.Errorstatus = "O" cferror.Errorinfo = "CheckSequence不连续:" + common.ValueToString(prevCS, "") + ";" + common.ValueToString(cflandtablst[j].Checksequence, "") cferror.Lastmodif = common.TimeFormat(time.Now(), "yyyyMMddHHmmss") cferror.Credatuz = common.TimeFormat(time.Now(), "yyyyMMddHHmmss") errorlst = append(errorlst, cferror) // CheckSequence 不连续,报错 fmt.Println("CheckSequence不连续:", prevCS, "==>", cflandtablst[j].Checksequence) } } } // 2. 判断客户订单是否存在 /* 获取锁 */ LOOP: err = etcd.G_jobLock.TryLock("lock") if err != nil { fmt.Println("calloff groutine lock fail!") time.Sleep(5 * time.Millisecond) goto LOOP } fmt.Println("calloff groutine lock success!") bl_co = service.BL_CustOrder{Projnr: cflandtablst[j].Projnr, Oemordernr: cflandtablst[j].Oemordernr, Partfamilyid: cflandtablst[j].Partfamilyid} if exist, err = bl_co.GetCalloffOemorder(); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "Failed to get custorder for oemorder due to: ", cflandtablst[j].Oemordernr, err) etcd.G_jobLock.UnLock() return } if !exist { cferror = db.Pln_calloff_errorlst{} cferror.Finr = db.G_FINR cferror.Calloffnr = cflandtablst[j].Calloffnr cferror.Errortype = common.CALLOFF_ORDER_NOTEXIST cferror.Consumeplant = cflandtablst[j].Consumeplant cferror.Partfamilyid = cflandtablst[j].Partfamilyid cferror.Oemordernr = cflandtablst[j].Oemordernr cferror.Errorstatus = "O" cferror.Errorinfo = "Calloff的客户订单不存在:Partfamilyid:" + cflandtablst[j].Partfamilyid + ";Oemordernr:" + cflandtablst[j].Oemordernr cferror.Lastmodif = common.TimeFormat(time.Now(), "yyyyMMddHHmmss") cferror.Credatuz = common.TimeFormat(time.Now(), "yyyyMMddHHmmss") errorlst = append(errorlst, cferror) glog.InfoExtln("读取Calloff信息并生成发运包装", "Calloff的客户订单不存在 :", cflandtablst[j].Oemordernr, cflandtablst[j].Partfamilyid) } glog.InfoExtln("CALLOFF-Debug", "获取客户订单:", bl_co.Custordertab.Custordernr, "生产工单数:", len(bl_co.Custordertab.Wotablst)) // 如果没有生产工单,则不再处理 if len(bl_co.Custordertab.Wotablst) <= 0 { fmt.Println("获取客户订单:", bl_co.Custordertab.Custordernr, "生产工单数:", len(bl_co.Custordertab.Wotablst)) etcd.G_jobLock.UnLock() continue } prevCS, _ = cfProj.Pfcsdict[cflandtablst[j].Partfamilyid] prevOemord = "" if prevCS > 0 { cflandtab = db.Pln_calloffdata_landing{Projnr: cfProj.Projectid, Checksequence: prevCS, Partfamilyid: cflandtablst[j].Partfamilyid} if cflandtablst2, err = cflandtab.GetByProjectCheckSequencePartfamily(); len(cflandtablst2) > 0 { prevOemord = cflandtablst2[0].Oemordernr // 获取前序客户订单对应的calloff记录 cftab = db.Pln_calloffdata_landing{Projnr: cfProj.Projectid, Oemordernr: prevOemord} // 获取前序calloff的所有记录 if cftablst, err = cftab.GetByProjectOemorder(); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "查询项目客户订单的calloff记录失败:", cftab.Projnr, cftab.Oemordernr, err) etcd.G_jobLock.UnLock() return } // 获取前序客户订单 bl_prevco = service.BL_CustOrder{Projnr: cfProj.Projectid, Oemordernr: cflandtablst2[0].Oemordernr, Partfamilyid: cflandtablst2[0].Partfamilyid} if exist, err = bl_prevco.GetCalloffOemorder(); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "获取前序客户订单失败:", cflandtablst2[0].Oemordernr, err) etcd.G_jobLock.UnLock() return } // 校验客户订单的零件族是否齐全 sgdict = make(map[string]string) if sgdict, err = bl_prevco.GetOemorderModelSpecPfdict(); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "查询项目客户订单的车型规格字典记录失败:", bl_co.Custordertab.Projnr, bl_co.Custordertab.Custordernr, err) etcd.G_jobLock.UnLock() return } if len(sgdict) != len(cftablst) { // 整车副缺零件族 glog.InfoExtln("CALLOFF-Debug", "整车副缺零件族len(cftablst):", len(cftablst), "整车副缺零件族len(sgdict):", len(sgdict)) etcd.G_jobLock.UnLock() continue } // 校验是否解析有错误 if len(cftablst) > 0 { // 校验前车付的calloff是否有错 stop = false for k = 0; k < len(cftablst); k++ { //fmt.Println(k,"-->",cftablst[k]) if cftablst[k].Parsed == 0 || cftablst[k].Handlestatus != common.CO_PARSE_STATUS_OK { stop = true break } } if stop { fmt.Println("前序未完成处理,跳过!") etcd.G_jobLock.UnLock() continue } } } } // 3. 判断客户订单状态是否满足 if projtablst[i].Calloff_verify_orderstatus > 0 && bl_co.Custordertab.Status < common.CO_STATUS_PLANNED { cferror = db.Pln_calloff_errorlst{} cferror.Finr = db.G_FINR cferror.Calloffnr = cflandtablst[j].Calloffnr cferror.Errortype = common.CALLOFF_ORDER_NOTSTATUS cferror.Consumeplant = cflandtablst[j].Consumeplant cferror.Partfamilyid = cflandtablst[j].Partfamilyid cferror.Oemordernr = cflandtablst[j].Oemordernr cferror.Errorstatus = "O" cferror.Errorinfo = "calloff的客户订单状态不满足:Partfamilyid:" + cflandtablst[j].Partfamilyid + ";Oemordernr:" + cflandtablst[j].Oemordernr cferror.Lastmodif = common.TimeFormat(time.Now(), "yyyyMMddHHmmss") cferror.Credatuz = common.TimeFormat(time.Now(), "yyyyMMddHHmmss") errorlst = append(errorlst, cferror) } // 4. 判断客户订单规格是否已审核 if projtablst[i].Calloff_verify_orderspec > 0 { if audit, err = bl_co.IsCarmodelSpecAudited(); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "获取客户订单规格失败 :", bl_co.Custordernr) etcd.G_jobLock.UnLock() return } else { if !audit { cferror = db.Pln_calloff_errorlst{} cferror.Finr = db.G_FINR cferror.Calloffnr = cflandtablst[j].Calloffnr cferror.Errortype = common.CALLOFF_ORDER_NOTSPEC cferror.Consumeplant = cflandtablst[j].Consumeplant cferror.Partfamilyid = cflandtablst[j].Partfamilyid cferror.Oemordernr = cflandtablst[j].Oemordernr cferror.Errorstatus = "O" cferror.Errorinfo = "calloff的客户订单的规格型号未审核:" + cflandtablst[j].Partfamilyid + ";Oemordernr:" + cflandtablst[j].Oemordernr cferror.Lastmodif = common.TimeFormat(time.Now(), "yyyyMMddHHmmss") cferror.Credatuz = common.TimeFormat(time.Now(), "yyyyMMddHHmmss") errorlst = append(errorlst, cferror) } } } // 如果有错,则停下不解析 if len(errorlst) > 0 { session = db.G_DbEngine.NewSession() if err = session.Begin(); err != nil { session.Close() etcd.G_jobLock.UnLock() return } //保存错误 if err = cferror.InsertList(session, errorlst); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "插入Calloff解析错误记录失败 :", err) session.Rollback() session.Close() etcd.G_jobLock.UnLock() return } //发邮件 host := projtablst[i].Emailserver_host + ":" + common.ValueToString(projtablst[i].Emailserver_port, "") body := "项目号: " + projtablst[i].Projectid + "\r\nOemordernr 订单号: " + cferror.Oemordernr + "\r\nErrorinfo :" + cferror.Errorinfo mail.Status = "waiting" mail.Body = body mail.Subject = "calloff解析错误" mail.Name = projtablst[i].From_email mail.Tomail = projtablst[i].Calloff_error_to_recievers mail.Host = host mail.Password = projtablst[i].From_pwd mail.Username = projtablst[i].From_email err = mail.Add() if err != nil { glog.InfoExtln("发送邮件", "err is :", err) } cflandtablst[j].Parsed = common.EDI_PARSE_YES cflandtablst[j].Handlestatus = common.CO_PARSE_STATUS_ERROR cflandtablst[j].Lastmodif = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss") if err = cflandtablst[j].UpdateFields(session, "parsed,handlestatus,lastmodif"); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "更新Calloff解析记录失败 :", err) session.Rollback() session.Close() etcd.G_jobLock.UnLock() return } session.Commit() session.Close() etcd.G_jobLock.UnLock() continue } // Hardcode: 对于G38项目的PF2的CALLOFF需要等同一客户订单的PF1的CALL进来后才解析 if cflandtablst[j].Projnr == "G38" && cflandtablst[j].Partfamilyid == "SITKD2" { // 获取同项目OEMORDER的Calloff判断解析状态 if exist, err = cflandtab.ExistUnParsedCfByProjectOemorderPf(cfProj.Projectid, cflandtablst[j].Oemordernr, "SITKD1"); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "获取项目客户订单零件族的calloff记录失败 :", cfProj.Projectid, cflandtablst[j].Oemordernr, cflandtablst[j].Partfamilyid, err) etcd.G_jobLock.UnLock() return } if exist { glog.InfoExtln("读取Calloff信息并生成发运包装", "408行 exist is false :", err) etcd.G_jobLock.UnLock() continue } } session = db.G_DbEngine.NewSession() if err = session.Begin(); err != nil { session.Close() etcd.G_jobLock.UnLock() return } // 遍历客户订单的生产订单列表,将生产订单加入包装 for k = 0; k < len(bl_co.Custordertab.Wotablst); k++ { glog.InfoExtln("CALLOFF-Debug", "遍历客户订单的生产订单", k, "--", bl_co.Custordertab.Wotablst[k]) wotab = bl_co.Custordertab.Wotablst[k] if wotab.Shippable == 0 || wotab.Packstatus == common.WO_STATUS_PACKED { continue } glog.InfoExtln("CALLOFF-Debug", "需要包装的工单:", wotab.Workordernr, "供应组:", wotab.Supplygroupid, "OEMSEQ:", wotab.Oemseq, "CheckSeq:", cflandtablst[j].Checksequence) // 初始化 bl_pakord = service.BL_PackOrder{} // 基于checksequence和工单的供应组ID查找包装单 if exist, bl_pakord, err = cfProj.GetPackOrderByCheckSequenceSupplyGroup(session, cflandtablst[j].Checksequence, wotab.Supplygroupid); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "无法获取checksequence的包装订单,原因是:", cflandtablst[j].Checksequence, err) session.Rollback() session.Close() etcd.G_jobLock.UnLock() return } // 基于OEMSEQ和工单的供应组ID查找包装单 if !exist { glog.InfoExtln("CALLOFF-Debug", "基于checkseq:", cflandtablst[j].Checksequence, "工单供应组:", wotab.Supplygroupid, "未找到开口包装!") if exist, bl_pakord, err = cfProj.GetPackOrderByOemseqSupplyGroup(session, wotab); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "无法获取OEMSEQ的包装订单,原因是:", wotab.Oemseq, err) session.Rollback() session.Close() etcd.G_jobLock.UnLock() return } } else { glog.InfoExtln("CALLOFF-Debug", "基于checkseq:", cflandtablst[j].Checksequence, "工单供应组:", wotab.Supplygroupid, "找到适配包装!") glog.InfoExtln("CALLOFF-Debug", "适配包装:", bl_pakord.Pkotab) } // 不存在则新建包装单 if !exist { glog.InfoExtln("CALLOFF-Debug", "基于OEMSEQ", wotab.Oemseq, "工单供应组:", wotab.Supplygroupid, "未找到开口包装!") if bl_pakordlst, err = cfProj.CreatePackOrderByCheckSeqWO(session, cflandtablst[j], wotab); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "创建开口包装单失败,原因是:", err) session.Rollback() session.Close() etcd.G_jobLock.UnLock() return } // 获取当前checksequence的包装单 ok = false glog.InfoExtln("CALLOFF-Debug", "新建开口包装成功,数量:", len(bl_pakordlst)) for m = 0; m < len(bl_pakordlst); m++ { glog.InfoExtln("CALLOFF-Debug", m, "----遍历开口包装适配:", bl_pakordlst[m].PackorderId) for n = 0; n < len(bl_pakordlst[m].Pkotab.Itemlst); n++ { glog.InfoExtln("CALLOFF-Debug", n, " ----匹配包装项:", bl_pakordlst[m].Pkotab.Itemlst[n]) if bl_pakordlst[m].Pkotab.Itemlst[n].Seq == cflandtablst[j].Checksequence && bl_pakordlst[m].Pkotab.Itemlst[n].Supplygroupid == wotab.Supplygroupid { ok = true bl_pakord = bl_pakordlst[m] break } } if ok { break } } if !ok { glog.InfoExtln("CALLOFF-Debug", "生产工单", wotab.Workordernr, "匹配包装失败!!!") glog.InfoExtln("读取Calloff信息并生成发运包装", "无法为当前工单找到包装单!", wotab.Workordernr) continue } } else { glog.InfoExtln("CALLOFF-Debug", "基于OEMSEQ:", wotab.Oemseq, "工单供应组:", wotab.Supplygroupid, "找到适配包装!") glog.InfoExtln("CALLOFF-Debug", "适配包装:", bl_pakord.Pkotab) } // 将工单加入到当前包装单 glog.InfoExtln("CALLOFF-Debug", "尝试将工单:", wotab.Workordernr, "添加到包装单:", bl_pakord.PackorderId) if ok, err = cfProj.AddWOToPackOrder(wotab, cflandtablst[j].Checksequence, &bl_pakord, session); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "添加工单到包装单出错,原因是:", wotab.Workordernr, bl_pakord.PackorderId, err) session.Rollback() session.Close() etcd.G_jobLock.UnLock() return } if ok { fmt.Println("成功添加工单", wotab.Workordernr, "到包装单", bl_pakord.PackorderId) glog.InfoExtln("CALLOFF-Debug", "成功添加工单", wotab.Workordernr, "到包装单", bl_pakord.PackorderId) // 关闭当前包装 if relstat, err = cfProj.ReleasePackOrder(session, bl_pakord); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "下达包装单出错!", bl_pakord.PackorderId, err) session.Rollback() session.Close() etcd.G_jobLock.UnLock() return } if relstat { glog.InfoExtln("CALLOFF-Debug", "成功下达包装单!", bl_pakord.PackorderId) glog.InfoExtln("读取Calloff信息并生成发运包装", "成功下达包装单!", bl_pakord.PackorderId) } } else { glog.InfoExtln("CALLOFF-Debug", "无法添加工单", wotab.Workordernr, "到包装单", bl_pakord.PackorderId) } } // 更新客户订单Call off相关信息 bl_co.Custordertab.Calloffnr = cflandtablst[j].Calloffnr bl_co.Custordertab.Calloffswet = cflandtablst[j].Swet bl_co.Custordertab.Checksequence = cflandtablst[j].Checksequence bl_co.Custordertab.Consumecompany = cflandtablst[j].Consumecompany bl_co.Custordertab.Consumeplant = cflandtablst[j].Consumeplant bl_co.Custordertab.Consigneecompany = cflandtablst[j].Consigneecompany bl_co.Custordertab.Consigneeplant = cflandtablst[j].Consigneeplant bl_co.Custordertab.Vehicleidset = cflandtablst[j].Vehicleidset bl_co.Custordertab.Vehicleid = cflandtablst[j].Vehicleid bl_co.Custordertab.Unloadingplace = cflandtablst[j].Unloadingplace bl_co.Custordertab.Lastmodif = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss") if err = bl_co.Custordertab.UpdateFields(session, "calloffnr, calloffswet, checksequence, consumecompany, consumeplant, consigneecompany, consigneeplant, vehicleidset, vehicleid, unloadingplace, lastmodif"); err != nil { glog.InfoExtln("读取Calloff更新客户订单数据", "Rollback", err) session.Rollback() session.Close() etcd.G_jobLock.UnLock() return } // calloff 客户订单成功,将landdata置位 cflandtablst[j].Handlestatus = common.CO_PARSE_STATUS_OK cflandtablst[j].Parsed = common.EDI_PARSE_YES cflandtablst[j].Lastmodif = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss") if err = cflandtablst[j].UpdateFields(session, "parsed,handlestatus, lastmodif"); err != nil { glog.InfoExtln("读取Calloff信息并生成发运包装", "Rollback", err) session.Rollback() session.Close() etcd.G_jobLock.UnLock() return } session.Commit() session.Close() etcd.G_jobLock.UnLock() time.Sleep(10 * time.Millisecond) } } time.Sleep(1 * time.Second) } } // 将26下达的包装单加载到发运车中,系统根据实际加载情况 func GenerateDeliveryCar() { for { var ( err error i, j, idx int projtab db.Me_project projtablst []db.Me_project pkotab db.Jit_packorder pkotablst []db.Jit_packorder cfProj service.CalloffProject bl_sco service.BL_ShipcarOrder bl_scolst []service.BL_ShipcarOrder fillable, canfix, canrelease bool shiptplid string session *xorm.Session ) projtab = db.Me_project{} if projtablst, err = projtab.GetAllActive(); err != nil { glog.InfoExtln("Calloff包装单", "Failed to get project list!") return } for i, _ = range projtablst { cfProj = service.CalloffProject{} cfProj.Projecttab = projtablst[i] cfProj.Projectid = projtablst[i].Projectid fmt.Println("Ready to load data for project:", projtablst[i].Projectid) // 读取项目的包装类型主数据 if err = cfProj.LoadPackageType(); err != nil { glog.InfoExtln("Calloff包装单", "Failed to load project package type data due to: ", err) return } // 读取项目的发运车模板主数据 if err = cfProj.LoadShipCarTemplate(); err != nil { glog.InfoExtln("Calloff包装单", "Failed to load project ship car data due to: ", err) return } // 循环读取状态>=26已下达且未装车的包装单 pkotab = db.Jit_packorder{} if pkotablst, err = pkotab.GetUnloadedPackOrders(cfProj.Projectid); err != nil { glog.InfoExtln("Calloff包装单", "Failed to load project unloaded pack orders due to: ", err) return } // 遍历包装单 for j = 0; j < len(pkotablst); j++ { // 判断状态 if pkotablst[j].Status < common.PKO_STATUS_PLANNED || pkotablst[j].Loadstatus == common.PKO_STATUS_LOADED { continue } // 获取开口发运车订单并添加到发运车中 if bl_scolst, err = cfProj.GetOpenShipCarOrder(); err != nil { glog.InfoExtln("Calloff包装单", "Failed to get open car orders due to: ", err) return } session = db.G_DbEngine.NewSession() defer session.Close() if err = session.Begin(); err != nil { return } // 匹配所有可用模板计算各包装项最大装载量并与已填充量比较,确认是否可以继续填充 => 有可用发运车 if len(bl_scolst) > 0 { fillable, idx = cfProj.CheckOpenCarOrdersForPackOrder(bl_scolst, pkotablst[j]) } bl_sco = service.BL_ShipcarOrder{} if len(bl_scolst) > 0 && fillable { bl_sco.Shiporderid = bl_scolst[idx].Shiporderid if err = bl_sco.AddPackOrder(session, pkotablst[j]); err != nil { glog.InfoExtln("Calloff包装单", "Failed to add packorder :, into shipcar order :, due to: ", pkotablst[j].Packorderid, bl_sco.Shiporderid, err) session.Rollback() return } } else { // 如果没有开口发运车,则创建发运车并添加 if bl_sco, err = cfProj.CreateShipCarOrder(session); err != nil { glog.InfoExtln("Calloff包装单", "Failed to create shipcar order due to: ", err) session.Rollback() return } if err = bl_sco.AddPackOrder(session, pkotablst[j]); err != nil { glog.InfoExtln("Calloff包装单", "Failed to add packorder : , into shipcar order :, due to: ", pkotablst[j].Packorderid, bl_sco.Shiporderid, err) session.Rollback() return } } // 获取发运车最新的数据 if err = bl_sco.GetOrderDataBySession(session); err != nil { glog.InfoExtln("Calloff包装单", "Failed to get ship order data!", bl_sco.Shiporderid) session.Rollback() return } // 检查发运车是否可以指定模板,状态从10 -> 20 if bl_sco.Spordtab.Status < common.SPO_STATUS_PLANNED { cfProj.InitShipOrderWorkoload(&bl_sco) cfProj.RecalShipItemWorkloadMaxQty(&bl_sco) if canfix, shiptplid, err = cfProj.IsShipcarOrderFixTemplate(&bl_sco); err != nil { glog.InfoExtln("Calloff包装单", "Failed to check shiporder fixable due to :", err) session.Rollback() return } if canfix { // 释放发运车并更新匹配的模板 if err = cfProj.FixShipCarOrderTemplate(session, &bl_sco, shiptplid); err != nil { glog.InfoExtln("Calloff包装单", "Failed to release ship car order!") session.Rollback() return } } } // 检查发运车是否达到上限可关闭,状态从20 -> 26 if canrelease, err = cfProj.IsShipcarOrderReleasable(&bl_sco); err != nil { glog.InfoExtln("Calloff包装单", "Failed to check shiporder releasable due to :", err) session.Rollback() return } if canrelease { // 释放发运车并更新匹配的模板 if err = cfProj.ReleaseShipCarOrder(session, &bl_sco); err != nil { glog.InfoExtln("Calloff包装单", "Failed to release ship car order!") session.Rollback() return } } fmt.Println("---------------------生成xmL_msg1") //APS向WMS传递发运包装信息 var o = PlnCalloffdataLandingXml{} o.Packorderid = pkotablst[j].Packorderid o.Packtemplateid = pkotablst[j].Packtemplateid o.Projnr = pkotablst[j].Projnr o.Status = strconv.Itoa(pkotablst[j].Status) o.Shortpack = strconv.Itoa(pkotablst[j].Shortpack) o.Orderinfo = pkotablst[j].Orderinfo o.Boxsn = pkotablst[j].Boxsn o.Packtypeid = pkotablst[j].Packtypeid o.Printerid = pkotablst[j].Printerid o.Templatefile = pkotablst[j].Templatefile o.Planqty = strconv.Itoa(pkotablst[j].Planqty) o.Actqty = strconv.Itoa(pkotablst[j].Actqty) for _, info := range pkotablst[j].Itemlst{ o.Details = append(o.Details, Pln_calloffdata_landing_Xml{ Packorderid :info.Packorderid, Pos :common.ValueToString(info.Pos,""), Poscode :info.Poscode, Oemseq : common.ValueToString(info.Oemseq, ""), Checkseq :common.ValueToString(info.Seq,""), Supplygroupid : info.Supplygroupid, Workordernr : info.Workordernr, Status : common.ValueToString(info.Status,""), Planqty :common.ValueToString(info.Planqty,""), Actqty :common.ValueToString(info.Actqty,""), }) } jsonBytes, err := json.Marshal(o) if err != nil { fmt.Println(err) } bl_xmlmsg := service.BL_Xmlmsg{MsgType: common.MSG_TYPE_SHIP, Msg: string(jsonBytes)} fmt.Println("---------------------生成xmL_msg2") if err = bl_xmlmsg.Create(session); err != nil { fmt.Println(err) } err = session.Commit() if err != nil { fmt.Println(err) return } } } time.Sleep(10 * time.Second) } } func CallOffXmlTick(){ timer := time.NewTicker(60 * time.Second) for { select { case <-timer.C: Xml_msg := db.Xml_msg{} if xmllst, err := Xml_msg.GetUnXmlMessages(); err != nil { glog.InfoExtln("Calloff包装单", "解析发运单消息失败: ", err) }else{ for _, xmlInfo := range xmllst{ var xmlStruct PlnCalloffdataLandingXml json.Unmarshal([]byte(xmlInfo.Msg), &xmlStruct) resXML, err := xml.MarshalIndent(xmlStruct, " ", " ") if err != nil { glog.InfoExtln("Calloff包装单", "Failed to create xml due to :",err) } timeS := time.Now().Format("20060102150405.999") fileName := strings.Trim(timeS,".") f, err := os.Create("./OutData/"+fileName +".xml") if err != nil { glog.InfoExtln("Calloff包装单", "Failed to create xml due to :",err) } io.WriteString(f, xml.Header) io.WriteString(f, string(resXML)) Xml_msg.Msgid = xmlInfo.Msgid Xml_msg.Status = common.MSG_STATUS_FINISHED Xml_msg.Lastmodif = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss") Xml_msg.Lastuser = "service" if err = Xml_msg.UpdateFieldsWithoutSession("status,lastmodif,lastuser"); err != nil { glog.InfoExtln("Calloff包装单", "Failed to create xml due to :",err) } } } } } } type PlnCalloffdataLandingXml struct { XMLName xml.Name `xml:"Content"` Packorderid string `xml:"packorderid,attr"` Packtemplateid string `xml:"packtemplateid,attr"` Projnr string `xml:"projnr,attr"` Status string `xml:"status,attr"` Shortpack string `xml:"shortpack,attr"` Orderinfo string `xml:"orderinfo,attr"` Boxsn string `xml:"boxsn,attr"` Packtypeid string `xml:"packtypeid,attr"` Printerid string `xml:"printerid,attr"` Templatefile string `xml:"templatefile,attr"` Planqty string `xml:"planqty,attr"` Actqty string `xml:"actqty,attr"` Details []Pln_calloffdata_landing_Xml `xml:"Details"` Description string `xml:",innerxml"` } type Pln_calloffdata_landing_Xml struct { XMLName xml.Name `xml:"Details"` Packorderid string `xml:"packorderid,attr"` Pos string `xml:"pos,attr"` Poscode string `xml:"poscode,attr"` Oemseq string `xml:"oemseq,attr"` Checkseq string `xml:"checkseq,attr"` Supplygroupid string `xml:"supplygroupid,attr"` Workordernr string `xml:"workordernr,attr"` Status string `xml:"status,attr"` Planqty string `xml:"planqty,attr"` Actqty string `xml:"actqty,attr"` }