|
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
|
|
}
|