package schedule import ( dal "LAPP_ACURA_MOM_BACKEND/dao/om" plnDal "LAPP_ACURA_MOM_BACKEND/dao/pln" "LAPP_ACURA_MOM_BACKEND/db" "LAPP_ACURA_MOM_BACKEND/grmi" common "LAPP_ACURA_MOM_BACKEND/models/base" model "LAPP_ACURA_MOM_BACKEND/models/om" plnModel "LAPP_ACURA_MOM_BACKEND/models/pln" "errors" "fmt" "github.com/go-xorm/xorm" "time" ) // TaskSrv 调度批次任务对象 type TaskSrv struct { TaskId string TaskType string PlantNr int ProjectId string SortKey int64 // 用于给MES用的排序号 ArtId string // 任务产品ID Priority int Status int SchedResGrpId string // 调度资源组ID SchedResId string // 调度资源 FixResource bool // 锁定资源 PlanQty float64 // 计划数量 CancelQty float64 // 取消数量 ReleasedQty float64 // 已下达数量 - 每个独立生成序列订单 FinishedQty float64 // 已完成数量 Duration time.Duration // 任务所需工时 EarliestStartTime time.Time // 最早开始时间 LatestEndTime time.Time // 最迟结束时间 SetupStartTime time.Time // 换型开始时间 SetupEndTime time.Time // 换型结束时间 FixStartTime bool // 锁定派车给开始时间 SchedStartTime time.Time // 排程开始时间 SchedEndTime time.Time // 排程结束时间 ActStartTime time.Time // 实际开始时间 ActEndTime time.Time // 实际结束时间 CustOrder plnModel.CustOrder CustOrderStatus plnModel.CustOrderStatus CustOrderQty plnModel.CustOrderQty SerialTaskArray []SerialTaskSrv // 批次订单的序列订单 } // SerialTaskSrv 序列任务对象 type SerialTaskSrv struct { TaskId string TaskType string ParentTaskId string PlantNr int ProjectId string Barcode string // 序列订单条码 ArtId string // 任务产品ID Status int SchedResId string // 调度资源 PlanQty float64 // 计划数量 Duration time.Duration // 任务所需工时 EarliestStartTime time.Time // 最早开始时间 LatestEndTime time.Time // 最迟结束时间 SetupStartTime time.Time // 换型开始时间 SetupEndTime time.Time // 换型结束时间 SchedStartTime time.Time // 排程开始时间 SchedEndTime time.Time // 排程结束时间 ActStartTime time.Time // 实际开始时间 ActEndTime time.Time // 实际结束时间 SerialOrderTab model.SerialOrder SerialOrderStatusTab model.SerialOrderStatus } // Get 基于指定的批次订单号获取批次订单对象 func (tasksrv *TaskSrv) Get() (err error) { engine := db.Eloquent.Master() session := engine.NewSession() defer session.Close() dao := plnDal.NewCustOrderDAO(session, tasksrv.PlantNr, "scheduler") var custOrder *plnModel.CustOrder if custOrder, err = dao.SelectOne(tasksrv.TaskId); err != nil { return grmi.NewBusinessError("获取工厂客户订单失败, 客户订单ID:" + tasksrv.TaskId + ", error:" + err.Error()) } tasksrv.Init(*custOrder) return } // Init 基于给定的订单表和订单状态表进行结构初始化 func (tasksrv *TaskSrv) Init(custOrder plnModel.CustOrder) { // 初始化批次任务的批次订单信息 tasksrv.TaskId = custOrder.CustOrderId tasksrv.TaskType = custOrder.OrderType tasksrv.SortKey = custOrder.PlanStartTime.Restore().Unix() // 用于给MES用的排序号 tasksrv.ArtId = custOrder.ProductFamilyId // 任务产品ID //tasksrv.Priority = custOrder.Priority // 优先级 tasksrv.Status = custOrder.OrderStatus.Status // 订单状态 //tasksrv.SchedResGrpId = wotab.PlanResourceGroupId // 调度资源组ID tasksrv.SchedResId = custOrder.WorkLineId // 调度资源 tasksrv.FixResource = false // 锁定资源 tasksrv.PlanQty = float64(custOrder.OrderQty.PlanQty) // 计划数量 tasksrv.ReleasedQty = float64(custOrder.OrderQty.ReleasedQty) // 已下达数量 - 每个独立生成序列订单 tasksrv.FinishedQty = float64(custOrder.OrderQty.ActQty) // 已完成数量 tasksrv.CancelQty = float64(custOrder.OrderQty.CancelQty) tasksrv.EarliestStartTime = custOrder.PlanStartDate.Restore() // 最早开始时间 tasksrv.LatestEndTime = custOrder.PlanEndTime.Restore() // 最迟结束时间 tasksrv.SetupStartTime = custOrder.SetupStartTime.Restore() // 换型开始时间 tasksrv.SetupEndTime = custOrder.SetupEndTime.Restore() // 换型结束时间 if custOrder.FixStartTimeToggle { // 锁定开始时间 tasksrv.FixStartTime = true } else { tasksrv.FixStartTime = false } tasksrv.SchedStartTime = custOrder.PlanStartTime.Restore() // 排程开始时间 tasksrv.SchedEndTime = custOrder.PlanEndTime.Restore() // 排程结束时间 tasksrv.ActStartTime = custOrder.ActStartTime.Restore() // 实际开始时间 tasksrv.ActEndTime = custOrder.ActEndTime.Restore() // 实际结束时间 // 获取调度任务所需要的工时 calQty := custOrder.PlanQty - custOrder.OrderQty.CancelQty //if custOrder.RatePerHourToggle { if custOrder.QuantityPerHour <= 0 || calQty <= 0 { tasksrv.Duration = 0 } else { tasksrv.Duration = time.Duration(float64(calQty)/float64(custOrder.QuantityPerHour)*3600) * time.Second } //} //if wotab.TimePerItemToggle { // perItemSeconds := float64(wotab.OpTimePerItem) * GetTimeUomSeconds(wotab.TimeUomId) // tasksrv.Duration = time.Duration(float64(calQty)*perItemSeconds) * time.Second //} //if wotab.TimePerBatchToggle { // if wotab.BatchTime <= 0 || wotab.BatchQuantity <= 0 || calQty <= 0 { // tasksrv.Duration = 0 // } else { // perBatchSeconds := float64(wotab.BatchTime) * GetTimeUomSeconds(wotab.TimeUomId) // tasksrv.Duration = time.Duration(perBatchSeconds*float64(calQty)/float64(wotab.BatchQuantity)) * time.Hour // } //} tasksrv.CustOrder = custOrder tasksrv.CustOrderStatus = custOrder.OrderStatus tasksrv.CustOrderQty = custOrder.OrderQty } // LoadSerialOrders 加载批次订单的序列订单 func (tasksrv *TaskSrv) LoadSerialOrders(session *xorm.Session) (err error) { var ( i int sordertablst []model.SerialOrder serialtasksrv SerialTaskSrv ) // 初始化批次订单的序列订单信息 tasksrv.SerialTaskArray = []SerialTaskSrv{} dao := dal.NewSerialOrderDAO(session, tasksrv.PlantNr, "scheduler") if sordertablst, err = dao.SelectByCustOrder(tasksrv.CustOrder.CustOrderId, common.WO_STATUS_LOCKED); err != nil { return grmi.NewBusinessError(fmt.Sprintf("查询客户订单的序列订单失败!, error:" + err.Error() + " ,客户订单ID: " + tasksrv.CustOrder.CustOrderId)) } for i = 0; i < len(sordertablst); i++ { serialtasksrv = SerialTaskSrv{} serialtasksrv.Init(sordertablst[i]) tasksrv.SerialTaskArray = append(tasksrv.SerialTaskArray, serialtasksrv) } return } // CreateStatusRecord 生成状态记录 func (tasksrv *TaskSrv) CreateStatusRecord(prevstatus int, eventsrv EventSrv) (err error) { var wostatusrectab model.WorkOrderStatusRecLst // 初始化 wostatusrectab = model.WorkOrderStatusRecLst{} wostatusrectab.PlantNr = tasksrv.PlantNr wostatusrectab.WorkOrderId = tasksrv.TaskId wostatusrectab.PrevStatus = prevstatus wostatusrectab.Status = tasksrv.Status wostatusrectab.TriggerEvent = eventsrv.TriggerEvent wostatusrectab.TriggerObjectId = eventsrv.TriggerObjectId wostatusrectab.TriggerSubObjectId = eventsrv.TriggerSubObjectId wostatusrectab.OutputStatus = common.OUTPUT_TRIGGER_UNHANDLED // 未处理 wostatusrectab.OutputEvent = eventsrv.OutputEvent wostatusrectab.OutputEventMessageId = eventsrv.OutputEventMsgId wostatusrectab.OutputObjectId = eventsrv.OutputObjectId wostatusrectab.OutputSubObjectId = eventsrv.OutputSubObjectId SetTableLastModify(&wostatusrectab, wostatusrectab, common.MODIFY_MODE_CREATE, eventsrv.TriggerService) engine := db.Eloquent.Master() session := engine.NewSession() defer session.Close() dao := dal.NewWorkOrderStatusRecLstDAO(session, tasksrv.PlantNr, "scheduler") if err := dao.InsertOne(&wostatusrectab); err != nil { err = errors.New(fmt.Sprintf("无法为工单%s插入状态变更记录%v!", tasksrv.TaskId, err)) return err } return } // ReleaseSerialOrder 下达批次订单,同步生成对应的序列订单 func (tasksrv *TaskSrv) ReleaseSerialOrder(relQty int, releaseId string) (err error) { //engine := db.Eloquent.Master() //session := engine.NewSession() //defer session.Close() //if err = session.Begin(); err != nil { // return grmi.NewBusinessError("开启事务失败, error:" + err.Error()) //} //var user = "scheduler" //workLineDao := baseDal.NewWorkLineDAO(session, tasksrv.PlantNr, user) //innerLog, _ := logger.NewLogger("scheduler", "scheduler") //innerLog.Debug("开始派工, 派工任务ID:"+releaseId, ", 客户订单ID:"+tasksrv.CustOrder.CustOrderId+", 通过数量进行派工,派工数量:"+strconv.Itoa(relQty)) //// 判断批次订单状态是否满足下达条件 >= 24 && < 80 //if tasksrv.CustOrderStatus.Status < common.WO_STATUS_LOCKED || tasksrv.CustOrderStatus.Status >= common.WO_STATUS_FINISHED { // _ = session.Rollback() // return grmi.NewBusinessError("客户订单状态不满足派工条件, 无法下达, 客户订单ID:" + tasksrv.CustOrder.CustOrderId + ", 订单状态:" + strconv.Itoa(tasksrv.CustOrderStatus.Status)) //} //innerLog.Debug("开始派工, 派工任务ID:"+releaseId, ", 客户订单ID:"+tasksrv.CustOrder.CustOrderId+", 加载客户订单下的序列订单完成") //// 计算实际可下达的序列订单数量 //actRelQty := len(tasksrv.SerialTaskArray) //if actRelQty <= 0 { // _ = session.Rollback() // innerLog.Error("开始派工, 派工任务ID:" + releaseId + ", 客户订单ID:" + tasksrv.CustOrder.CustOrderId + ", 该客户订单下可派工的订单数量为0") // return grmi.NewBusinessError("客户订单可下达数量为0, 客户订单ID:" + tasksrv.CustOrder.CustOrderId) //} //if relQty > actRelQty { // _ = session.Rollback() // innerLog.Error("开始派工, 派工任务ID:" + releaseId + ", 客户订单ID:" + tasksrv.CustOrder.CustOrderId + ", 需要派工数量大于客户订单可派工数量, 需要派工数量:" + strconv.Itoa(relQty) + ", 可派工数量:" + strconv.Itoa(actRelQty)) // return grmi.NewBusinessError("客户订单需要派工数量大于可派工数量, 客户订单ID:" + tasksrv.CustOrder.CustOrderId) //} //workLine, err := workLineDao.SelectOne(tasksrv.CustOrder.WorkLineId) //if err != nil { // _ = session.Rollback() // innerLog.Error("开始派工, 派工任务ID:" + releaseId + ", 客户订单ID:" + tasksrv.CustOrder.CustOrderId + ", 获取产线数据失败, error:" + err.Error()) // return grmi.NewBusinessError("获取产线数据失败, 客户订单ID:" + tasksrv.CustOrder.CustOrderId + ", error:" + err.Error()) //} //if workLine == nil { // _ = session.Rollback() // innerLog.Error("开始派工, 派工任务ID:" + releaseId + ", 客户订单ID:" + tasksrv.CustOrder.CustOrderId + ", 产线不存在, 产线ID:" + tasksrv.CustOrder.WorkLineId) // return grmi.NewBusinessError("获取产线不存在, 产线ID:" + tasksrv.CustOrder.WorkLineId + ", 客户订单ID:" + tasksrv.CustOrder.CustOrderId) //} //custOrderSvr := plnSvr.NewCustOrderService() //resCustOrder, err := custOrderSvr.ReleaseCustOrder(session, relQty, &tasksrv.CustOrder) //if err != nil { // _ = session.Rollback() // innerLog.Error("开始派工, 派工任务ID:" + releaseId + ", 客户订单ID:" + tasksrv.CustOrder.CustOrderId + ", 客户订单派工阶段失败, error:" + err.Error()) //} //_ = session.Commit() //innerLog.Debug("派工完成, 派工任务ID:"+releaseId, ", 客户订单ID:"+tasksrv.CustOrder.CustOrderId+", 派工数量:"+strconv.Itoa(relQty)) //tasksrv.Init(*resCustOrder) return } // Get 基于指定的序列订单号获取序列订单对象 func (stasksrv *SerialTaskSrv) Get() (err error) { var serordtab model.SerialOrder engine := db.Eloquent.Master() session := engine.NewSession() defer session.Close() dao := dal.NewSerialOrderDAO(session, stasksrv.PlantNr, "scheduler") if serordtab, err = dao.SelectInfo(stasksrv.TaskId); err != nil { err = errors.New(fmt.Sprintf("获取工厂%d序列订单%s失败!", stasksrv.PlantNr, stasksrv.TaskId)) return } stasksrv.Init(serordtab) return } // Init 初始化序列订单 func (stasksrv *SerialTaskSrv) Init(serialordertab model.SerialOrder) { stasksrv.SerialOrderTab = serialordertab stasksrv.SerialOrderStatusTab = serialordertab.SerialOrderStatus } // Create 创建序列订单 func (stasksrv *SerialTaskSrv) Create() (err error) { // 插入序列订单 stasksrv.SerialOrderTab = model.SerialOrder{} stasksrv.SerialOrderTab.PlantNr = stasksrv.PlantNr stasksrv.SerialOrderTab.ProjectId = stasksrv.ProjectId stasksrv.SerialOrderTab.ArtId = stasksrv.ArtId stasksrv.SerialOrderTab.WorkOrderId = stasksrv.ParentTaskId stasksrv.SerialOrderTab.PlanResourceId = stasksrv.SchedResId stasksrv.SerialOrderTab.OrderType = stasksrv.TaskType stasksrv.SerialOrderTab.SerialOrderId = stasksrv.TaskId stasksrv.SerialOrderTab.PlanQty = float64(stasksrv.PlanQty) stasksrv.SerialOrderTab.PlanStartTime = grmi.DateTime(stasksrv.SchedStartTime) stasksrv.SerialOrderTab.PlanEndTime = grmi.DateTime(stasksrv.SchedEndTime) SetTableLastModify(&stasksrv.SerialOrderTab, stasksrv.SerialOrderTab, common.MODIFY_MODE_CREATE, "rel_service") engine := db.Eloquent.Master() session := engine.NewSession() defer session.Close() dao := dal.NewSerialOrderDAO(session, stasksrv.PlantNr, "rel_service") if err = dao.InsertOne(&stasksrv.SerialOrderTab); err != nil { err = errors.New(fmt.Sprintf("工单%s的序列订单%s头创建失败%v!", stasksrv.ParentTaskId, stasksrv.TaskId, err)) return } // 插入序列订单状态行 stasksrv.SerialOrderStatusTab = model.SerialOrderStatus{} stasksrv.SerialOrderStatusTab.PlantNr = stasksrv.PlantNr stasksrv.SerialOrderStatusTab.SerialOrderId = stasksrv.TaskId stasksrv.SerialOrderStatusTab.Status = common.WO_STATUS_PLANNED stasksrv.SerialOrderStatusTab.TriggerObjectId = stasksrv.ParentTaskId stasksrv.SerialOrderStatusTab.TriggerEvent = common.BATORD_EVENT_LOCK SetTableLastModify(&stasksrv.SerialOrderStatusTab, stasksrv.SerialOrderStatusTab, common.MODIFY_MODE_CREATE, "rel_service") serial := dal.NewSerialOrderStatusDAO(session, stasksrv.PlantNr, "rel_service") if err = serial.InsertOne(&stasksrv.SerialOrderStatusTab); err != nil { err = errors.New(fmt.Sprintf("工单%s的序列订单%s状态头创建失败%v!", stasksrv.ParentTaskId, stasksrv.TaskId, err)) return } // 插入序列订单状态记录行 // 如果需要触发动作可在此处添加 serordstatrectab := model.SerialOrderStatusRecLst{} serordstatrectab.PlantNr = stasksrv.PlantNr serordstatrectab.SerialOrderId = stasksrv.TaskId serordstatrectab.PrevStatus = 0 serordstatrectab.Status = common.WO_STATUS_PLANNED serordstatrectab.OutputEvent = common.OUTPUT_EVENT_SER_NEW serordstatrectab.OutputObjectId = serordstatrectab.SerialOrderId serordstatrectab.OutputStatus = common.OUTPUT_TRIGGER_UNHANDLED SetTableLastModify(&serordstatrectab, serordstatrectab, common.MODIFY_MODE_CREATE, "rel_service") serord := dal.NewSerialOrderStatusRecLstDAO(session, stasksrv.PlantNr, "rel_service") if err = serord.InsertOne(&serordstatrectab); err != nil { err = errors.New(fmt.Sprintf("工单%s的序列订单%s状态记录行创建失败%v!", stasksrv.ParentTaskId, stasksrv.TaskId, err)) return } return } // Release 下达序列订单 func (stasksrv *SerialTaskSrv) Release() (err error) { var prevstatus int // 判断序列订单是否可以被下达 if stasksrv.SerialOrderStatusTab.Status >= common.WO_STATUS_RELEASED { return } // 获取序列订单当前状态 prevstatus = stasksrv.SerialOrderStatusTab.Status // 更新序列订单状态行 stasksrv.SerialOrderStatusTab.Status = common.WO_STATUS_RELEASED stasksrv.SerialOrderStatusTab.TriggerObjectId = stasksrv.ParentTaskId stasksrv.SerialOrderStatusTab.TriggerEvent = common.BATORD_EVENT_RELEASE SetTableLastModify(&stasksrv.SerialOrderStatusTab, stasksrv.SerialOrderStatusTab, common.MODIFY_MODE_UPDATE, "rel_service") engine := db.Eloquent.Master() session := engine.NewSession() defer session.Close() serial := dal.NewSerialOrderStatusDAO(session, stasksrv.PlantNr, "rel_service") if err = serial.UpdateOne(&stasksrv.SerialOrderStatusTab); err != nil { err = errors.New(fmt.Sprintf("工单%s的序列订单%s状态头更新失败%v!", stasksrv.ParentTaskId, stasksrv.TaskId, err)) return } // 插入序列订单状态记录行 // 如果需要触发动作可在此处添加 serordstatrectab := model.SerialOrderStatusRecLst{} serordstatrectab.PlantNr = stasksrv.PlantNr serordstatrectab.SerialOrderId = stasksrv.TaskId serordstatrectab.PrevStatus = prevstatus serordstatrectab.Status = common.WO_STATUS_RELEASED serordstatrectab.OutputEvent = common.OUTPUT_EVENT_SER_REL serordstatrectab.OutputObjectId = serordstatrectab.SerialOrderId serordstatrectab.OutputStatus = common.OUTPUT_TRIGGER_UNHANDLED SetTableLastModify(&serordstatrectab, serordstatrectab, common.MODIFY_MODE_UPDATE, "rel_service") serord := dal.NewSerialOrderStatusRecLstDAO(session, stasksrv.PlantNr, "rel_service") if err = serord.UpdateOne(&serordstatrectab); err != nil { err = errors.New(fmt.Sprintf("工单%s的序列订单%s状态记录行创建失败%v!", stasksrv.ParentTaskId, stasksrv.TaskId, err)) return } return }