SJA APS后端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

387 lines
13 KiB

package seq
import (
"fmt"
"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"
"time"
)
// 测试SEQ文件解析和保存
func ParseSeqNew() {
for {
var (
err error
projtab db.Me_project
projtablst []db.Me_project
seqland SeqLandData
seqProj service.SeqProject
rd []os.FileInfo
fi os.FileInfo
edi_file string
matched bool
)
projtab = db.Me_project{}
if projtablst, err = projtab.GetAllActive(); err != nil {
glog.InfoExtln("seq解析", "Failed to get project list!", err)
return
}
for i, _ := range projtablst {
seqProj = service.SeqProject{}
seqProj.Projecttab = projtablst[i]
seqProj.Projectid = projtablst[i].Projectid
fmt.Println("Ready to load data for project:", projtablst[i].Projectid)
// 读取文件夹内的文件并解析
if rd, err = ioutil.ReadDir(seqProj.Projecttab.Seq_folder + "/inbox"); err != nil {
return
}
rds := common.SortByTime(rd)
for _, fi = range rds {
if fi.IsDir() {
continue
}
edi_file = seqProj.Projecttab.Seq_folder + "/inbox" + "/" + fi.Name()
// 判断文件的合规性
if matched, err = regexp.MatchString(seqProj.Projecttab.Seq_filename_regexp, fi.Name()); err != nil {
glog.InfoExtln("seq解析", "Failed to match EDI file name:", fi.Name(), err)
return
}
if !matched {
glog.InfoExtln("seq解析", "The specified EDI file: doesn't match the required name specification!", fi.Name())
os.Rename(edi_file, seqProj.Projecttab.Seq_folder+"/errbox"+"/"+fi.Name())
return
}
// 解析SEQ文件到字典
fmt.Println("Ready to read tod data......")
seqland = SeqLandData{}
seqland.Projnr = projtablst[i].Projectid
seqland.Edifile = edi_file
if err = seqland.ReadSeqData(edi_file); err != nil {
glog.InfoExtln("seq解析", "Failed to parse SEQ file due to: ", err)
os.Rename(edi_file, seqProj.Projecttab.Seq_folder+"/errbox"+"/"+fi.Name())
return
}
// 保存SEQ字典到SEQ的临时缓存表
if err = seqland.SaveSeqData(); err != nil {
glog.InfoExtln("seq解析", "Failed to save SEQ parse result due to:", err)
return
}
// 将文件移到outbox
os.Rename(edi_file, seqProj.Projecttab.Seq_folder+"/outbox"+"/"+fi.Name())
}
}
time.Sleep(10 * time.Second)
}
}
// 解析并读取SEQ
func ParseSeqOrder() {
for {
var (
err error
i, j, prevseq int
projtab db.Me_project
projtablst []db.Me_project
seqProj service.SeqProject
seqlandtab db.Pln_seqdata_landing
seqlandtablst []db.Pln_seqdata_landing
cotab db.Pln_custorder
bl_co service.BL_CustOrder
bl_ordmsg service.BL_Ordmsg
ok, exist bool
)
projtab = db.Me_project{}
if projtablst, err = projtab.GetAllActive(); err != nil {
glog.InfoExtln("解析并读取SEQ", "Failed to get project list!")
return
}
for i, _ = range projtablst {
seqProj = service.SeqProject{}
seqProj.Projecttab = projtablst[i]
seqProj.Projectid = projtablst[i].Projectid
fmt.Println("Ready to load data for project:", projtablst[i].Projectid)
// 加载项目的二级物料主数据
if err = seqProj.LoadMaterialData(); err != nil {
glog.InfoExtln("解析并读取SEQ", "Failed to Load material data due to:", err)
return
}
// 加载BOM主数据
if err = seqProj.LoadBomData(); err != nil {
glog.InfoExtln("解析并读取SEQ", "Failed to load bom data due to: ", err)
return
}
// 读取SEQ解析用主数据
seqlandtab = db.Pln_seqdata_landing{Projnr: seqProj.Projectid}
if seqlandtablst, err = seqlandtab.GetUnparsedLandingData(); err != nil {
glog.InfoExtln("解析并读取SEQ", "Failed to GetUnparsedLandingData due to:", err)
return
}
// 读取SEQ的LandingData
for j, _ = range seqlandtablst {
/* 获取锁 */
LOOP:
err = etcd.G_jobLock.TryLock("lock")
if err != nil {
fmt.Println("seq groutine lock fail!")
time.Sleep(5 * time.Millisecond)
goto LOOP
}
fmt.Println("seq groutine lock success!")
// 初始化客户订单对象并获取客户订单头,如果不存在则返回
cotab = db.Pln_custorder{Projnr: seqlandtablst[j].Projnr, Oemordernr: seqlandtablst[j].Oemordernr, Partfamilyid: seqlandtablst[j].Partfamilyid}
if exist, cotab, err = cotab.GetByOemOrderNr(); err != nil {
glog.InfoExtln("解析并读取SEQ", "Failed to get custorder for oemorder due to: ", seqlandtablst[j].Oemordernr, err)
etcd.G_jobLock.UnLock()
return
}
if exist {
bl_co = service.BL_CustOrder{}
bl_co.Custordertab = cotab
bl_co.Custordernr = cotab.Custordernr
bl_co.Partfamilyid = cotab.Partfamilyid
bl_co.Projnr = cotab.Projnr
bl_co.SeqType = seqlandtablst[j].Seqmode
bl_co.Oemordernr = seqlandtablst[j].Oemordernr
} else {
glog.InfoExtln("custorder信息", "custorder due to: ", bl_co.Custordernr)
etcd.G_jobLock.UnLock()
time.Sleep(10 * time.Millisecond)
continue
}
// 获取客户订单完整数据(客户订单头、解析的零件和属性、生产订单列表)
if err = bl_co.GetFullData(); err != nil {
glog.InfoExtln("解析并读取SEQ", "Failed to get full data for custorder due to: ", bl_co.Custordernr, err)
etcd.G_jobLock.UnLock()
return
}
// 验证客户订单状态是否满足更新条件
if bl_co.Custordertab.Handlestatus != common.CO_PARSE_STATUS_OK {
fmt.Println("验证客户订单状态是否满足更新条件!", bl_co.Custordertab.Handlestatus, common.CO_PARSE_STATUS_OK)
etcd.G_jobLock.UnLock()
time.Sleep(10 * time.Millisecond)
continue
}
// 判断订单状态,如果是>=26,则跳出循环
if bl_co.Custordertab.Status >= common.CO_STATUS_RELEASED {
glog.InfoExtln("custorder信息", "custorder due to: ", bl_co.Custordernr)
// 客户订单状态不允许更新,设置解析状态为9
seqlandtablst[j].Parsed = common.EDI_PARSE_ERROR
seqlandtablst[j].Lastmodif = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss")
fields := []string{"parsed", "lastmodif"}
if err = seqlandtablst[j].UpdateFieldsWithoutSession(fields); err != nil {
etcd.G_jobLock.UnLock()
return
}
etcd.G_jobLock.UnLock()
time.Sleep(10 * time.Millisecond)
continue
}
// 校验客户订单的OEMSEQ是否连续(基于零件族获取最大的已计划的客户订单的SEQ),版本1校验,其它版本不校验
if seqlandtablst[j].Oemseq > 0 && seqlandtablst[j].Oemseq < 9999999999 && seqlandtablst[j].Version == 1 && seqProj.Projecttab.Seq_verify_sequence > 0 && seqProj.IsPartFamilyNeedToContinue(bl_co.Custordertab.Partfamilyid) {
// 读取项目各零件族最大的OEMSEQ号
if err = seqProj.GetPartFamilyMaxOemseq(); err != nil {
glog.InfoExtln("解析并读取SEQ", "加载项目零件族最大OEMSEQ号失败: ", err)
etcd.G_jobLock.UnLock()
return
}
if prevseq, ok = seqProj.Pfseqdict[bl_co.Custordertab.Partfamilyid]; !ok {
glog.InfoExtln("解析并读取SEQ", "获取零件族最大OEMSEQ失败!", bl_co.Custordertab.Partfamilyid, err)
etcd.G_jobLock.UnLock()
return
}
if prevseq > 0 && (prevseq+1 != common.ValueToInt(seqlandtablst[j].Oemseq, 0)) {
glog.InfoExtln("解析并读取SEQ", fmt.Sprintf("当前零件族%s的最大OEMSEQ%d,与SEQ订单%s的排序%d不连续!", bl_co.Custordertab.Partfamilyid,
prevseq, seqlandtablst[j].Oemordernr, common.ValueToInt(seqlandtablst[j].Oemseq, 0)))
etcd.G_jobLock.UnLock()
time.Sleep(10 * time.Millisecond)
continue
}
}
// 对于版本号大于1的则需要校验它的版本1是否已解析,如果没有解析,则也不解析
if seqlandtablst[j].Oemseq > 0 && seqlandtablst[j].Oemseq < 9999999999 && seqlandtablst[j].Version > 1 {
if ok, err = seqlandtablst[j].IsFirstVersionParsed(); err != nil {
glog.InfoExtln("解析并读取SEQ", "获取客户订单SEQ的解析版本1数据失败!", seqlandtablst[j].Oemordernr, err)
etcd.G_jobLock.UnLock()
return
}
if !ok {
glog.InfoExtln("解析并读取SEQ", fmt.Sprintf("当前客户订单%s的SEQ解析版本1尚未解析!", seqlandtablst[j].Oemordernr))
etcd.G_jobLock.UnLock()
time.Sleep(10 * time.Millisecond)
continue
}
}
//开启事务
session := db.G_DbEngine.NewSession()
if err = session.Begin(); err != nil {
session.Close()
etcd.G_jobLock.UnLock()
glog.InfoExtln("custorder信息", "custorder due to err: ", err)
return
}
// 基于SEQ保存客户订单版本信息(用于追溯)
if err = bl_co.SaveSeqCOVSession(session, seqlandtablst[j]); err != nil {
glog.InfoExtln("解析并读取SEQ", "Failed to insert SEQ cov data for custorder due to: ", bl_co.Custordernr, err)
session.Rollback()
session.Close()
etcd.G_jobLock.UnLock()
return
}
// 将SEQ信息更新到对应的客户订单和生产订单
if err = bl_co.UpdateSEQDataSession(session, seqlandtablst[j]); err != nil {
glog.InfoExtln("解析并读取SEQ", "Failed to update SEQ data for custorder due to:", bl_co.Custordernr, err)
session.Rollback()
session.Close()
etcd.G_jobLock.UnLock()
return
}
// 创建OEM订单消息用于Carmodel的解析
bl_ordmsg = service.BL_Ordmsg{MsgType: common.MSG_TYPE_CARMODEL, MsgEvent: common.MSG_EVENT_NEW, MsgObjid: bl_co.Oemordernr, MsgcPara1: bl_co.Projnr}
if err = bl_ordmsg.CreateForOemorderToParseCarmodel(session); err != nil {
glog.InfoExtln("解析并读取SEQ", "为客户订单创建车型解析消息失败: ", bl_co.Custordernr, err)
session.Rollback()
session.Close()
etcd.G_jobLock.UnLock()
return
}
// 创建客户订单计算二级需求的消息
//bl_ordmsg = service.BL_Ordmsg{MsgType: common.MSG_TYPE_DEMAND, MsgEvent: common.MSG_EVENT_NEW, MsgObjid: bl_co.Custordernr, MsgcPara1: bl_co.Projnr}
//if err = bl_ordmsg.Create(session); err != nil {
// glog.InfoExtln("解析并读取SEQ", "为客户订单 创建二级需求消息失败:", bl_co.Custordernr, err)
// session.Rollback()
// session.Close()
// etcd.G_jobLock.UnLock()
// return
//}
// 更新解析记录的状态为已解析
seqlandtablst[j].Parsed = common.EDI_PARSE_YES
seqlandtablst[j].Lastmodif = common.Date(time.Now().Unix(), "YYYYMMDDHHmmss")
fields := []string{"parsed", "lastmodif"}
if err = seqlandtablst[j].UpdateFields(session, fields); err != nil {
glog.InfoExtln("解析并读取SEQ", "Failed to close seqlandtab for custorder due to: ", bl_co.Custordernr, err)
session.Rollback()
session.Close()
etcd.G_jobLock.UnLock()
return
}
glog.InfoExtln("custorder信息", "custorder due to: ", bl_co.Custordernr)
session.Commit()
session.Close()
etcd.G_jobLock.UnLock()
time.Sleep(5 * time.Millisecond)
}
}
time.Sleep(10 * time.Second)
}
}
// 排序调度
func Scheduler() {
var (
err error
se service.SchedEngine
bl_wl service.BL_Workline
i int
)
se = service.SchedEngine{}
se.PlanMode = common.LINE_PLAN_IN_SEQ
se.LineTypes = append(se.LineTypes, "A", "M", "V")
// 加载排序产线
if err = se.LoadMasterData(); err != nil {
glog.InfoExtln("排序调度", "Failed to load master data due to: ", err)
return
}
// 按产线启动排序派工服务
for i = 0; i < len(se.Wltablst); i++ {
bl_wl = service.BL_Workline{}
bl_wl.PickTmpDict = make(map[string]service.BL_PickingTemplate)
bl_wl.WorklineId = se.Wltablst[i].Worklineid
bl_wl.SortMode = se.Wltablst[i].Taskqueuesortway
if se.Wltablst[i].Multiqueuemixsort == 1 {
bl_wl.MixSort = true
bl_wl.MixSortMode = se.Wltablst[i].Taskqueuemixsortway
bl_wl.MixSortRule = se.Wltablst[i].Mixsortlogic
} else {
bl_wl.MixSort = false
}
bl_wl.ReleaseMode = se.Wltablst[i].Taskreleaseway
bl_wl.ReleaseValue = se.Wltablst[i].Releaseparameter
bl_wl.Worklinetab = se.Wltablst[i]
// 启动产线派工下达协程
go ScheduleTaskToRelease(bl_wl, &se)
}
}
// 拣料单服务
func Picker() {
var (
err error
)
// 运行拣料服务
if err = RunPicker(); err != nil {
glog.InfoExtln("排序调度", "Failed to RunPicker due to: ", err)
return
}
}
// 车型生成服务
func RunCarmodelParserTask() {
var (
projtab db.Me_project
projtablst []db.Me_project
i int
err error
)
projtab = db.Me_project{}
if projtablst, err = projtab.GetAllActive(); err != nil {
glog.InfoExtln("解析并读取SEQ", "Failed to get project list!")
return
}
for {
for i, _ = range projtablst {
fmt.Println(i, "--Load project to parse:", projtablst[i].Projectid)
// 运行拣料服务
if err = RunCarmodelParser(projtablst[i].Projectid); err != nil {
glog.InfoExtln("车型生成服务", "Failed to RunCarmodelParser: ", err)
return
}
}
time.Sleep(time.Duration(5) * time.Second)
}
}