From abfd3b7a58721bb2f09de41f7128bc0ee443bbd0 Mon Sep 17 00:00:00 2001 From: zhangxin Date: Mon, 25 Apr 2022 16:45:20 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0excel=E5=B9=B6=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E6=8E=92=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../base/implments/WorkLine.service.impl.go | 18 +- .../pln/implments/CustOrder.service.impl.go | 452 +++++++++++++----- services/schedule/Scheduler.Ctrl.go | 125 ++++- 3 files changed, 462 insertions(+), 133 deletions(-) diff --git a/services/base/implments/WorkLine.service.impl.go b/services/base/implments/WorkLine.service.impl.go index 10a2573..d694b37 100644 --- a/services/base/implments/WorkLine.service.impl.go +++ b/services/base/implments/WorkLine.service.impl.go @@ -967,15 +967,7 @@ func (impl *WorkLineServiceImplement) WorkLineRepairSchedule(user *global.User, func (impl *WorkLineServiceImplement) SaveWorkLineScheduler(user *global.User, data schedule.SchedulerData) error { grmi.Log(user, "/services/base/implments/WorkLine.service.impl.go", "SaveWorkLineScheduler", "保存调度结果") - - StartDate, err := utils.TimeParse(data.StartDate) - if err != nil { - return err - } - EndDate, err := utils.TimeParse(data.EndDate) - if err != nil { - return err - } + var err error //开启事务 engine := db.Eloquent.Master() session := engine.NewSession() @@ -997,8 +989,8 @@ func (impl *WorkLineServiceImplement) SaveWorkLineScheduler(user *global.User, d updateCustOrder := new(plnModel.CustOrder) updateCustOrder.PlantNr = plannedTask.PlantNr updateCustOrder.CustOrderId = plannedTask.TaskId - updateCustOrder.PlanStartDate = grmi.Date(StartDate) - updateCustOrder.PlanEndDate = grmi.Date(EndDate) + updateCustOrder.PlanStartDate = grmi.Date(plannedTask.SchedStartTime) + updateCustOrder.PlanEndDate = grmi.Date(plannedTask.SchedEndTime) updateCustOrder.PlanStartTime = grmi.DateTime(plannedTask.SchedStartTime) updateCustOrder.PlanEndTime = grmi.DateTime(plannedTask.SchedEndTime) updateCustOrder.LastModify = grmi.DateTime(time.Now()) @@ -1050,8 +1042,8 @@ func (impl *WorkLineServiceImplement) SaveWorkLineScheduler(user *global.User, d updateCustOrder := new(plnModel.CustOrder) updateCustOrder.PlantNr = task.PlantNr updateCustOrder.CustOrderId = task.TaskId - updateCustOrder.PlanStartDate = grmi.Date(StartDate) - updateCustOrder.PlanEndDate = grmi.Date(EndDate) + updateCustOrder.PlanStartDate = grmi.Date(task.SchedStartTime) + updateCustOrder.PlanEndDate = grmi.Date(task.SchedEndTime) updateCustOrder.PlanStartTime = grmi.DateTime(task.SchedStartTime) updateCustOrder.PlanEndTime = grmi.DateTime(task.SchedEndTime) updateCustOrder.LastModify = grmi.DateTime(time.Now()) diff --git a/services/pln/implments/CustOrder.service.impl.go b/services/pln/implments/CustOrder.service.impl.go index 7d70552..095b25d 100644 --- a/services/pln/implments/CustOrder.service.impl.go +++ b/services/pln/implments/CustOrder.service.impl.go @@ -23,16 +23,16 @@ import ( omModel "LAPP_ACURA_MOM_BACKEND/models/om" model "LAPP_ACURA_MOM_BACKEND/models/pln" omSvr "LAPP_ACURA_MOM_BACKEND/services/om" + "LAPP_ACURA_MOM_BACKEND/services/schedule" "LAPP_ACURA_MOM_BACKEND/utils" "container/list" "errors" "github.com/360EntSecGroup-Skylar/excelize/v2" + "github.com/go-xorm/xorm" uuid "github.com/iris-contrib/go.uuid" "strconv" "strings" "sync" - - //"sync" "time" ) @@ -2524,7 +2524,7 @@ func (impl *CustOrderServiceImplement) Dashboard(user *global.User, workLineId s go func(wg *sync.WaitGroup) { DashboardData.DashboardDataPic1, err1 = impl.SelectPic1(user, dayModel, workLineId) wg.Done() // 操作完成,减少一个计数 - }(&wg ) + }(&wg) //图例002 go func(wg *sync.WaitGroup) { @@ -3326,7 +3326,6 @@ func (impl *CustOrderServiceImplement) SelectPic1(user *global.User, dayModel *b return result, nil } - func (impl *CustOrderServiceImplement) GetUsefulTime(start, end time.Time, timeLine *list.List) int { var duration int for element := timeLine.Front(); element != nil; element = element.Next() { @@ -3928,12 +3927,17 @@ func (impl *CustOrderServiceImplement) AnalysisPlanFromExcel(user *global.User, engine := db.Eloquent.Master() session := engine.NewSession() defer session.Close() - custOrderDao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId) - custOrderStatusDao := dal.NewCustOrderStatusDAO(session, user.PlantNr, user.UserId) + var startDate, endDate time.Time custOrderQtyDao := dal.NewCustOrderQtyDAO(session, user.PlantNr, user.UserId) productFamilyDao := meDal.NewProductFamilyDAO(session, user.PlantNr, user.UserId) + productFamilyWorkLineDao := meDal.NewProductFamilyWorkLineLstDAO(session, user.PlantNr, user.UserId) + productFamilyRelateDao := meDal.NewProductFamilyRelateDAO(session, user.PlantNr, user.UserId) + productWorkLineDao := meDal.NewProductWorkLineLstDAO(session, user.PlantNr, user.UserId) projectDao := meDal.NewProjectDAO(session, user.PlantNr, user.UserId) + serialOrderDao := omDal.NewSerialOrderDAO(session, user.PlantNr, user.UserId) + serialOrderStatusDao := omDal.NewSerialOrderStatusDAO(session, user.PlantNr, user.UserId) snrDao := baseDal.NewSnrDAO(session, user.PlantNr, user.UserId) + workLineDao := baseDal.NewWorkLineDAO(session, user.PlantNr, user.UserId) file, err := excelize.OpenFile(filepath) if err != nil { return grmi.NewBusinessError("读取文件失败, error:" + err.Error()) @@ -3946,7 +3950,7 @@ func (impl *CustOrderServiceImplement) AnalysisPlanFromExcel(user *global.User, rowIndex := 0 projectMap := make(map[string]*meModel.Project) productFamilyMap := make(map[string]*meModel.ProductFamily) - planDateCustOrderMap := make(map[string][]model.CustOrder, 0) + custOrderWorkLineMap := make(map[string][]model.CustOrder, 0) for rowsIterator.Next() { rowIndex++ // 第一行标题行 @@ -3962,7 +3966,7 @@ func (impl *CustOrderServiceImplement) AnalysisPlanFromExcel(user *global.User, if err != nil { return grmi.NewBusinessError("去读excel行数据失败, error:" + err.Error()) } - if len(row) != 4 { + if len(row) != 5 { return grmi.NewBusinessError("excel数据列数不合规, 行数:" + strconv.Itoa(rowIndex)) } productFamilyId := row[0] @@ -3982,6 +3986,17 @@ func (impl *CustOrderServiceImplement) AnalysisPlanFromExcel(user *global.User, if planDate.Before(today) { return grmi.NewBusinessError("计划日期不能早于今天") } + if rowIndex == 2 { + startDate = planDate + endDate = planDate + } + if planDate.Before(startDate) { + startDate = planDate + } + if endDate.Before(planDate) { + endDate = planDate + } + workLineId := row[4] productFamily, exist := productFamilyMap[productFamilyId] if !exist { productFamily, err = productFamilyDao.SelectOne(productFamilyId) @@ -3993,6 +4008,29 @@ func (impl *CustOrderServiceImplement) AnalysisPlanFromExcel(user *global.User, } productFamilyMap[productFamilyId] = productFamily } + if !productFamily.MultiWorkLineToggle { + if productFamily.WorkLineId != workLineId { + return grmi.NewBusinessError("派生指定的产线不可生产, 派生ID:" + productFamilyId + ", 产线ID:" + workLineId) + } + + } else { + workLineLi, err := productFamilyWorkLineDao.Select([]grmi.Predicate{ + meMeta.ProductFamilyWorkLineLst_ProductFamilyId.NewPredicate(grmi.Equal, productFamilyId), + }, nil) + if err != nil { + return grmi.NewBusinessError("查询派生可生产产线失败, 错误:" + err.Error()) + } + var match bool + for _, workLine := range workLineLi { + if workLine.WorkLineId == workLineId { + match = true + break + } + } + if !match { + return grmi.NewBusinessError("派生指定的产线不可生产, 派生ID:" + productFamilyId + ", 产线ID:" + workLineId) + } + } project, exist := projectMap[projectId] if !exist { project, err = projectDao.SelectOne(projectId) @@ -4015,89 +4053,45 @@ func (impl *CustOrderServiceImplement) AnalysisPlanFromExcel(user *global.User, ModelValue: productFamily.ModelValue, ColorValue: productFamily.ColorValue, PlanQty: qty, - WorkLineId: productFamily.WorkLineId, + WorkLineId: workLineId, QuantityPerHour: int(productFamily.Jph), PlanStartDate: grmi.Date(planDate), - PlanEndDate: grmi.Date(planDate), - } - planDateCustOrderMap[planDate.Format(grmi.DateOutFormat)] = append(planDateCustOrderMap[planDate.Format(grmi.DateOutFormat)], custOrder) - } - // 计算计划时间 - // 如果根据所有的jph当天时间够用 根据jph进行分配时间 如果不够根据数量占用所有时间 - // 查询当天是否有计划客户订单 - for planDate, custOrderLi := range planDateCustOrderMap { - dayStartTime := planDate + " 00:00:00" - dayEndTime := planDate + " 23:59:59" - existCustOrderLi, err := custOrderDao.SelectCrossDayCustOrder(dayEndTime) - if err != nil { - return grmi.NewBusinessError("查询已存在的客户订单数据失败, 错误:" + err.Error()) + SourceId: "EXCEL", } - if len(existCustOrderLi) != 0 { - return grmi.NewBusinessError("计划日期中存在跨天的客户订单,无法计划客户订单, 日期:" + planDate) + custOrder.OrderStatus = model.CustOrderStatus{ + Status: baseModel.ORDER_STATUS_UNPLANED, } - existCustOrderLi, err = custOrderDao.SelectCurrentDayCustOrder(dayStartTime, dayEndTime) - if err != nil { - return grmi.NewBusinessError("查询已存在的客户订单数据失败, 错误:" + err.Error()) - } - var startPlanTime time.Time - // 如果当天没有客户订单 使用的开始时间从0点开始 - if len(existCustOrderLi) == 0 { - startPlanTime, _ = time.ParseInLocation(grmi.DateTimeOutFormat, dayStartTime, utils.TimezoneLocation) - } else { - startPlanTime = existCustOrderLi[0].PlanEndTime.Restore() + custOrder.OrderQty = model.CustOrderQty{ + PlanQty: custOrder.PlanQty, } - if startPlanTime.Before(time.Now()) { - startPlanTime = time.Now() + custOrderWorkLineMap[workLineId] = append(custOrderWorkLineMap[workLineId], custOrder) + } + // 产线组与所属产线的MAP数据结构 + workLineGroupMap := make(map[string]map[string]interface{}) + workLineMap := make(map[string]baseModel.WorkLine) + allWorkLineLi, err := workLineDao.Select(nil, nil) + if err != nil { + return grmi.NewBusinessError("查询工厂产线数据失败, 错误:" + err.Error()) + } + for _, workLine := range allWorkLineLi { + workLineMap[workLine.WorkLineid] = workLine + if workLine.GroupType == baseModel.WORK_LINE_TYPE_GROUP { + workLineGroupMap[workLine.WorkLineid] = make(map[string]interface{}) } - // 按照jph计算当时的时间 - useTimeMap := make(map[int]int) - var allUsedSeconds int - var allQty int - for index, custOrder := range custOrderLi { - jph := productFamilyMap[custOrder.ProductFamilyId].Jph - planQty := custOrder.PlanQty - useSeconds := 3600 / int(jph) * planQty - useTimeMap[index] = useSeconds - allUsedSeconds += useSeconds - allQty += custOrder.PlanQty - } - endPlanTme := startPlanTime.Add(time.Second * time.Duration(allUsedSeconds)) - // 如果计算结束时间大于当天则时间剩余时间分配 如果没有大于当天则时间计划时间 - endDayTime, _ := time.ParseInLocation(grmi.DateTimeOutFormat, dayEndTime, utils.TimezoneLocation) - prePlanEndTime := startPlanTime - if endPlanTme.After(endDayTime) { - // 当天还可以使用的时间 - CanUsedTime := endDayTime.Sub(startPlanTime).Seconds() - // 没台套使用的时间 单位s - perCarUsedTime := int(CanUsedTime) / allQty - if perCarUsedTime < 60 { - return grmi.NewBusinessError("分配给每个台套的时间已不足一分钟, 日期:" + planDate) - } - for index, custOrder := range custOrderLi { - custOrder.PlanStartTime = grmi.DateTime(prePlanEndTime) - custOrder.PlanEndTime = grmi.DateTime(prePlanEndTime.Add(time.Duration(custOrder.PlanQty*perCarUsedTime) * time.Second)) - prePlanEndTime = custOrder.PlanEndTime.Restore() - custOrderLi[index] = custOrder - } - } else { - for index, custOrder := range custOrderLi { - custOrder.PlanStartTime = grmi.DateTime(prePlanEndTime) - usedTime := useTimeMap[index] - custOrder.PlanEndTime = grmi.DateTime(prePlanEndTime.Add(time.Duration(usedTime) * time.Second)) - prePlanEndTime = custOrder.PlanEndTime.Restore() - custOrderLi[index] = custOrder + } + for _, workLine := range allWorkLineLi { + if workLine.GroupType == baseModel.WORK_LINE_TYPE_REAL { + _, exist := workLineGroupMap[workLine.GroupLineId] + if exist { + workLineGroupMap[workLine.GroupLineId][workLine.WorkLineid] = nil } } - planDateCustOrderMap[planDate] = custOrderLi } + if err = session.Begin(); err != nil { return grmi.NewBusinessError("开启事务失败, 错误:" + err.Error()) } - - for _, custOrderLi := range planDateCustOrderMap { - custOrderStatusLi := make([]model.CustOrderStatus, 0, 20) - custOrderQtyLi := make([]model.CustOrderQty, 0, 20) - tempCustOrderLi := make([]model.CustOrder, 0, 20) + for workLineId, custOrderLi := range custOrderWorkLineMap { for index, custOrder := range custOrderLi { project := projectMap[custOrder.ProjectId] custOrderId, err := snrDao.GetNextSnr(project.CustOrderSnr) @@ -4106,54 +4100,191 @@ func (impl *CustOrderServiceImplement) AnalysisPlanFromExcel(user *global.User, return grmi.NewBusinessError("获取客户订单流水号失败, 错误:" + err.Error()) } custOrder.CustOrderId = custOrderId - custOrderStatus := model.CustOrderStatus{ - CustOrderId: custOrderId, - Status: baseModel.WO_STATUS_PLANNED, - } - custOrderStatusLi = append(custOrderStatusLi, custOrderStatus) - custOrderQty := model.CustOrderQty{ - CustOrderId: custOrderId, - PlanQty: custOrder.PlanQty, + custOrder.OrderQty.CustOrderId = custOrderId + custOrder.OrderStatus.CustOrderId = custOrderId + custOrderLi[index] = custOrder + } + custOrderWorkLineMap[workLineId] = custOrderLi + } + endDate = endDate.AddDate(0, 0, 2) + for workLineId, custOrderLi := range custOrderWorkLineMap { + plannedLi, err := impl.AutoScheduler(user, session, workLineId, startDate, endDate, custOrderLi) + if err != nil { + _ = session.Rollback() + return grmi.NewBusinessError("自动排程失败,错误:" + err.Error()) + } + // 用于生成工艺的serialOrder map + productSerialOrderMap := make(map[string][]*omModel.SerialOrder) + for _, orderData := range plannedLi { + // 获取客户订单的车型配置下的所有座椅 + productLi, err := productFamilyRelateDao.SelectProductByFamilyIdForCreateSerialOrder(orderData.ProjectId, orderData.ProductFamilyId) + if err != nil { + _ = session.Rollback() + return grmi.NewBusinessError("通过车型配置查询关联座椅产品失败, error:" + err.Error()) } - custOrderQtyLi = append(custOrderQtyLi, custOrderQty) - tempCustOrderLi = append(tempCustOrderLi, custOrder) - if index != 0 && index%20 == 0 { - err = custOrderDao.Insert(&tempCustOrderLi) + if len(productLi) == 0 { + _ = session.Rollback() + return grmi.NewBusinessError("该客户订单的车型配置未关联座椅产品") + } + // 通过客户订单的时间间隔进行切割 分配给每一个序列工单 + duration := orderData.PlanEndTime.Restore().Sub(orderData.PlanStartTime.Restore()) + totalQty := orderData.PlanQty * len(productLi) + orderData.OrderQty.SerialOrderQty = totalQty + orderData.OrderQty.ReleasedQty = orderData.OrderQty.PlanQty + err = custOrderQtyDao.UpdateOne(&orderData.OrderQty) + if err != nil { + _ = session.Rollback() + return grmi.NewBusinessError("更新客户订单数量失败, error:" + err.Error()) + } + var current int + perDuration := duration.Seconds() / float64(totalQty) + var isFirstPieceToggle bool + var syncKey string + project := projectMap[orderData.ProjectId] + + // 临时工单列表 + serialOrderLi := make([]omModel.SerialOrder, 0) + // 临时工单状态列表 + serialOrderStatusLi := make([]omModel.SerialOrderStatus, 0) + + // 创建序列工单和工单状态 + for i := 0; i < orderData.PlanQty; i++ { + syncKey = orderData.CustOrderId + "-" + strconv.Itoa(i) + serialNumber, err := snrDao.GetNextSnrWithTime(project.SerialOrderSnr, orderData.PlanStartTime.Restore()) if err != nil { _ = session.Rollback() - return grmi.NewBusinessError("保存客户订单数据失败, 错误:" + err.Error()) + return grmi.NewBusinessError("生成工单流水号失败, error:" + err.Error()) + } + for _, product := range productLi { + // 获取生产使用的产线 + var resourceId string + if product.MultiWorkLineToggle { + relateWorkLineLi, err := productWorkLineDao.Select([]grmi.Predicate{ + meMeta.ProductWorkLineLst_ProductId.NewPredicate(grmi.Equal, product.ProductId), + meMeta.ProductWorkLineLst_ProjectId.NewPredicate(grmi.Equal, product.ProjectId), + }, nil) + if err != nil { + _ = session.Rollback() + return grmi.NewBusinessError("查询总成关联产线失败, 错误:" + err.Error()) + } + canUsedWorkLineMap, exist := workLineGroupMap[orderData.WorkLineId] + if !exist { + _ = session.Rollback() + return grmi.NewBusinessError("未获取到该派生产线组下的实体产线") + } + for _, workLine := range relateWorkLineLi { + _, exist = canUsedWorkLineMap[workLine.WorkLineId] + if exist { + if resourceId == "" { + resourceId = workLine.WorkLineId + } else { + _ = session.Rollback() + return grmi.NewBusinessError("总成在关联了可生产产线,总成ID:" + product.ProductId) + } + } + } + if resourceId == "" { + _ = session.Rollback() + return grmi.NewBusinessError("未获取到可生产的产线") + } + } else { + resourceId = product.DefaultWorkLineId + } + planStartTime := orderData.PlanStartTime.Restore().Add(time.Duration(int(perDuration)*current) * time.Second) + planEndTime := orderData.PlanStartTime.Restore().Add(time.Duration(int(perDuration)*(current+1)) * time.Second) + current++ + planStartDate := grmi.Date(planStartTime) + planEndDate := grmi.Date(planEndTime) + serialOrderId := product.MachineCode + serialNumber + product.ProductType + product.ColorValue + + timeInt, err := strconv.Atoi(planStartTime.Format("060102150405")) + if err != nil { + _ = session.Rollback() + return grmi.NewBusinessError("通过时间获取工单调度Key失败, error:" + err.Error()) + } + var dealedSchedKey = int64(timeInt * 100) + if i == 0 { + isFirstPieceToggle = true + } + serialOrder := omModel.SerialOrder{ + SerialOrderId: serialOrderId, + ArtId: product.ProductId, + ProjectId: orderData.ProjectId, + Descr: product.Descr, + CustOrderId: orderData.CustOrderId, + OrderType: baseModel.ODER_TYPE_SEQ, + PlanResourceId: resourceId, + UsedResourceId: resourceId, + SchedKey: dealedSchedKey, + PlanQty: 1, + PlanStartDate: planStartDate, + PlanEndDate: planEndDate, + PlanStartTime: grmi.DateTime(planStartTime), + PlanEndTime: grmi.DateTime(planEndTime), + PickingFlag: product.PickingFlag, + IsFirstPieceToggle: isFirstPieceToggle, + SyncKey: syncKey, + } + isFirstPieceToggle = false + serialOrderLi = append(serialOrderLi, serialOrder) + serialOrderStatus := omModel.SerialOrderStatus{ + SerialOrderId: serialOrderId, + Status: baseModel.WO_STATUS_RELEASED, + } + serialOrderStatusLi = append(serialOrderStatusLi, serialOrderStatus) + _, exist := productSerialOrderMap[product.ProductId] + if !exist { + productSerialOrderMap[product.ProductId] = make([]*omModel.SerialOrder, 0) + } + productSerialOrderMap[product.ProductId] = append(productSerialOrderMap[product.ProductId], &serialOrder) } - err = custOrderStatusDao.Insert(&custOrderStatusLi) + } + // 将工单数据落库 + tempSerialOrderLi := make([]omModel.SerialOrder, 0, 20) + for index, serialOrder := range serialOrderLi { + if index%20 == 0 && index != 0 { + err = serialOrderDao.Insert(&tempSerialOrderLi) + if err != nil { + _ = session.Rollback() + return grmi.NewBusinessError("插入序列工单数据失败, error:" + err.Error()) + } + tempSerialOrderLi = make([]omModel.SerialOrder, 0, 20) + } + tempSerialOrderLi = append(tempSerialOrderLi, serialOrder) + } + if len(tempSerialOrderLi) != 0 { + err = serialOrderDao.Insert(&tempSerialOrderLi) if err != nil { _ = session.Rollback() - return grmi.NewBusinessError("保存客户订单状态数据失败, 错误:" + err.Error()) + return grmi.NewBusinessError("插入序列工单数据失败, error:" + err.Error()) + } + } + tempSerialOrderStatusLi := make([]omModel.SerialOrderStatus, 0, 20) + for index, serialOrderStatus := range serialOrderStatusLi { + if index%20 == 0 && index != 0 { + err = serialOrderStatusDao.Insert(&tempSerialOrderStatusLi) + if err != nil { + _ = session.Rollback() + return grmi.NewBusinessError("插入序列工单状态数据失败, error:" + err.Error()) + } + tempSerialOrderStatusLi = make([]omModel.SerialOrderStatus, 0, 20) } - err = custOrderQtyDao.Insert(&custOrderQtyLi) + tempSerialOrderStatusLi = append(tempSerialOrderStatusLi, serialOrderStatus) + } + if len(tempSerialOrderStatusLi) != 0 { + err = serialOrderStatusDao.Insert(&tempSerialOrderStatusLi) if err != nil { _ = session.Rollback() - return grmi.NewBusinessError("保存客户订单数据量数据失败, 错误:" + err.Error()) + return grmi.NewBusinessError("插入序列工单状态数据失败, error:" + err.Error()) } - custOrderStatusLi = make([]model.CustOrderStatus, 0, 20) - custOrderQtyLi = make([]model.CustOrderQty, 0, 20) - tempCustOrderLi = make([]model.CustOrder, 0, 20) } } - if len(tempCustOrderLi) != 0 { - err = custOrderDao.Insert(&tempCustOrderLi) - if err != nil { - _ = session.Rollback() - return grmi.NewBusinessError("保存客户订单数据失败, 错误:" + err.Error()) - } - err = custOrderStatusDao.Insert(&custOrderStatusLi) - if err != nil { - _ = session.Rollback() - return grmi.NewBusinessError("保存客户订单状态数据失败, 错误:" + err.Error()) - } - err = custOrderQtyDao.Insert(&custOrderQtyLi) - if err != nil { - _ = session.Rollback() - return grmi.NewBusinessError("保存客户订单数据量数据失败, 错误:" + err.Error()) - } + // 创建serialOrder service接口 + serialOrderSvr := omSvr.NewSerialOrderService() + err = serialOrderSvr.GenerateCraftDataByCustOrder(user, session, productSerialOrderMap) + if err != nil { + _ = session.Rollback() + return grmi.NewBusinessError("生成工艺数据失败, error:" + err.Error()) } } _ = session.Commit() @@ -4207,3 +4338,94 @@ func (impl *CustOrderServiceImplement) QuickSortProductData(values []model.HourP impl.QuickSortProductData(values[:head]) impl.QuickSortProductData(values[head+1:]) } + +// AutoScheduler 自动排程 同时对客户订单进行落库 +func (impl *CustOrderServiceImplement) AutoScheduler(user *global.User, session *xorm.Session, workLineId string, startDate time.Time, endDate time.Time, unplannedCustOrderLi []model.CustOrder) ([]model.CustOrder, error) { + var ( + schedEngine schedule.SchedulerSrv + + err error + ) + returnCustOrderLi := make([]model.CustOrder, 0, len(unplannedCustOrderLi)) + custOrderMap := make(map[string]*model.CustOrder) + for index, custOrder := range unplannedCustOrderLi { + custOrderMap[custOrder.CustOrderId] = &unplannedCustOrderLi[index] + } + endDate = endDate.Add(1 * time.Second) + schedEngine = schedule.SchedulerSrv{PlantNr: user.PlantNr, StartDate: startDate, EndDate: endDate} + schedEngine.Tmsrv.StartDate = startDate + schedEngine.Tmsrv.EndDate = endDate + custOrderDao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId) + custOrderQtyDao := dal.NewCustOrderQtyDAO(session, user.PlantNr, user.UserId) + custOrderStatusDao := dal.NewCustOrderStatusDAO(session, user.PlantNr, user.UserId) + // 加载激活的项目主数据 + err = schedEngine.LoadProjectData() + if err != nil { + return nil, err + } + // 加载时间模型,基于调度引擎指定的时间区间 + err = schedEngine.LoadTimeModel(session, workLineId) + + // 加载产品换型主数据 + err = schedEngine.LoadSetupData() + if err != nil { + return nil, err + } + // 加载产线主数据 + err = schedEngine.LoadWorkLineData(workLineId) + if err != nil { + return nil, err + } + // 加载产线班组计划出勤数据 + err = schedEngine.LoadWorkLineWorkShiftData() + if err != nil { + return nil, err + } + // 生成产线的时间曲线 + err = schedEngine.GenerateWorkLineTimeCurve() + if err != nil { + return nil, err + } + // 加载工单数据(调度任务) + err = schedEngine.LoadSchedCustTask(session, workLineId, unplannedCustOrderLi) + if err != nil { + return nil, err + } + // 对调度任务进行排序 + schedEngine.SortUnplannedCustOrder() + // 依次调度未计划工单 + err = schedEngine.AutoSchedule() + if err != nil { + return nil, err + } + // 将已计划的客户订单进行落库 状态设置为26 + for _, plannedTask := range schedEngine.UnPlannedTaskArray { + //过滤订单状态大于20的订单 + if plannedTask.CustOrderStatus.Status > baseModel.WO_STATUS_PLANNED { + continue + } + // 保存客户订单数据 + custOrder := custOrderMap[plannedTask.TaskId] + custOrder.PlanEndDate = grmi.Date(plannedTask.SchedEndTime) + custOrder.PlanStartTime = grmi.DateTime(plannedTask.SchedStartTime) + custOrder.PlanEndTime = grmi.DateTime(plannedTask.SchedEndTime) + err = custOrderDao.InsertOne(custOrder) + if err != nil { + return nil, grmi.NewBusinessError("保存客户订单数据失败, 错误:" + err.Error()) + } + custOrderStatus := custOrder.OrderStatus + custOrderStatus.Status = baseModel.WO_STATUS_RELEASED + err = custOrderStatusDao.InsertOne(&custOrderStatus) + if err != nil { + return nil, grmi.NewBusinessError("保存客户订单状态失败, 错误:" + err.Error()) + } + err = custOrderQtyDao.InsertOne(&custOrder.OrderQty) + if err != nil { + return nil, grmi.NewBusinessError("保存客户订单数量失败, 错误:" + err.Error()) + } + returnCustOrderLi = append(returnCustOrderLi, *custOrder) + + } + return returnCustOrderLi, nil +} + diff --git a/services/schedule/Scheduler.Ctrl.go b/services/schedule/Scheduler.Ctrl.go index 08e7b08..2e803cb 100644 --- a/services/schedule/Scheduler.Ctrl.go +++ b/services/schedule/Scheduler.Ctrl.go @@ -16,6 +16,7 @@ import ( "LAPP_ACURA_MOM_BACKEND/utils" "errors" "fmt" + "github.com/go-xorm/xorm" uuid "github.com/iris-contrib/go.uuid" "reflect" "strconv" @@ -132,6 +133,37 @@ func (schedsrv *SchedulerSrv) LoadTimeModelData(workLineId string) (err error) { return nil } +// LoadTimeModel 加载时间模型 +func (schedsrv *SchedulerSrv) LoadTimeModel(session *xorm.Session, workLineId string) (err error) { + + //查询边界开始日期 + // 查询已经分配到产线上的客户订单 + var custOrderLi []plnModel.CustOrder + dao := plnDal.NewCustOrderDAO(session, schedsrv.PlantNr, "scheduler") + if custOrderLi, err = dao.SelectWorkLineTaskBeyondStatus(schedsrv.StartDate, schedsrv.EndDate, workLineId, common.WO_STATUS_PLANNED); err != nil { + return grmi.NewBusinessError("加载已经分配到产线上的客户订单失败, error:" + err.Error()) + } + if len(custOrderLi) > 1 { + PlanStartDate := custOrderLi[0].PlanStartDate.Restore() + if PlanStartDate.Unix() < schedsrv.StartDate.Unix() { + schedsrv.StartDate = PlanStartDate + } + } + // 初始化 + schedsrv.Tmsrv = TimeModelSrv{PlantNr: schedsrv.PlantNr, StartDate: schedsrv.StartDate, EndDate: schedsrv.EndDate} + // 加载指定日期范畴内的时间模型相关主数据 + err = schedsrv.Tmsrv.LoadBasicData(schedsrv.StartDate, schedsrv.EndDate) + if err != nil { + return grmi.NewBusinessError("加载时间模型主数据失败, error:" + err.Error()) + } + // 生成日模型的时间线列表 + err = schedsrv.Tmsrv.GenDayModelLineArray() + if err != nil { + return grmi.NewBusinessError("日模型时间线失败, error:" + err.Error()) + } + return nil +} + // LoadWorkLineWorkShiftData 加载产线班次的实际出勤数据,指定时段,没有按班次指定的默认值填充 func (schedsrv *SchedulerSrv) LoadWorkLineWorkShiftData() (err error) { // 遍历产线 @@ -235,6 +267,49 @@ func (schedsrv *SchedulerSrv) LoadSchedTaskData(workLineId string) (err error) { return } +// LoadSchedCustTask 加载调度任务 +func (schedsrv *SchedulerSrv) LoadSchedCustTask(session *xorm.Session, workLineId string, unPlannedCustOrderLi []plnModel.CustOrder) (err error) { + var ( + i int + tasksrv TaskSrv + custOrderLi []plnModel.CustOrder + ) + // 初始化 + schedsrv.LockedTaskArray = []TaskSrv{} + schedsrv.PlannedTaskArray = []TaskSrv{} + schedsrv.UnPlannedTaskArray = []TaskSrv{} + // 加载调度任务数据 + // 1. 按实际开始时间先后加载状态 >= 24已开始的任务 + dao := plnDal.NewCustOrderDAO(session, schedsrv.PlantNr, "scheduler") + if custOrderLi, err = dao.SelectWorkLineTaskBeyondStatus(schedsrv.StartDate, schedsrv.EndDate, workLineId, common.WO_STATUS_LOCKED); err != nil { + return grmi.NewBusinessError("加载已锁定及以上的客户订单失败, error:" + err.Error()) + } + for i = 0; i < len(custOrderLi); i++ { + tasksrv = TaskSrv{} + tasksrv.Init(custOrderLi[i]) + schedsrv.LockedTaskArray = append(schedsrv.LockedTaskArray, tasksrv) + } + // 2. 按计划开始时间先后加载状态 = 20 的已计划任务 + if custOrderLi, err = dao.SelectWorkLineTaskEqualStatus(schedsrv.StartDate, schedsrv.EndDate, workLineId, common.WO_STATUS_PLANNED); err != nil { + return grmi.NewBusinessError("加载已计划的客户订单失败, error:" + err.Error()) + } + for i = 0; i < len(custOrderLi); i++ { + tasksrv = TaskSrv{} + tasksrv.Init(custOrderLi[i]) + schedsrv.PlannedTaskArray = append(schedsrv.PlannedTaskArray, tasksrv) + } + // 3. 按指定规则加载未计划的任务 + //if custOrderLi, err = dao.SelectUnPlannedCustOrder(workLineId); err != nil { + // return grmi.NewBusinessError("加载未计划的客户订单失败, error:" + err.Error()) + //} + for i = 0; i < len(unPlannedCustOrderLi); i++ { + tasksrv = TaskSrv{} + tasksrv.Init(unPlannedCustOrderLi[i]) + schedsrv.UnPlannedTaskArray = append(schedsrv.UnPlannedTaskArray, tasksrv) + } + return +} + // RetrieveSchedule 撤回计划,将未下达的任务全部更新为未计划 func (schedsrv *SchedulerSrv) RetrieveSchedule() { var schedTask TaskSrv @@ -1104,6 +1179,39 @@ func (schedsrv *SchedulerSrv) SortUnplannedTask() { }) } +// 对调度任务进行排序 +func (schedsrv *SchedulerSrv) SortUnplannedCustOrder() { + var ( + i int + sortTasks []interface{} + ) + + // 计算排序任务的排序属性 + //for i = 0; i < len(schedsrv.UnPlannedTaskArray); i++ { + // + //} + + // 准备排序 + sortTasks = []interface{}{} + for i = 0; i < len(schedsrv.UnPlannedTaskArray); i++ { + sortTasks = append(sortTasks, schedsrv.UnPlannedTaskArray[i]) + } + + SortBody(sortTasks, func(p, q *interface{}) bool { + v1 := reflect.ValueOf(*p) + i := v1.FieldByName("PlanStartDate") + v2 := reflect.ValueOf(*q) + j := v2.FieldByName("PlanStartDate") + if i.String() != j.String() { + return i.String() < j.String() + } else { + m := v1.FieldByName("CustOrderId") + n := v2.FieldByName("CustOrderId") + return m.String() < n.String() + } + }) +} + // 调度引擎自动排程 func (schedsrv *SchedulerSrv) AutoSchedule() (err error) { var ( @@ -1111,21 +1219,28 @@ func (schedsrv *SchedulerSrv) AutoSchedule() (err error) { ) // 遍历已锁定任务,先占位 for i = 0; i < len(schedsrv.LockedTaskArray); i++ { - schedsrv.ScheduleTask(schedsrv.LockedTaskArray[i].SchedResId, &schedsrv.LockedTaskArray[i]) + err = schedsrv.ScheduleTask(schedsrv.LockedTaskArray[i].SchedResId, &schedsrv.LockedTaskArray[i]) + if err != nil { + return err + } } // 遍历已计划任务,占位 for i = 0; i < len(schedsrv.PlannedTaskArray); i++ { - schedsrv.ScheduleTask(schedsrv.PlannedTaskArray[i].SchedResId, &schedsrv.PlannedTaskArray[i]) + err = schedsrv.ScheduleTask(schedsrv.PlannedTaskArray[i].SchedResId, &schedsrv.PlannedTaskArray[i]) + if err != nil { + return err + } } // 将未计划任务排序 // 遍历未计划任务 for i = 0; i < len(schedsrv.UnPlannedTaskArray); i++ { // 此处可以增加选择调度资源逻辑 - // 将未计划任务调度到指定的计划资源上 - schedsrv.ScheduleTask(schedsrv.UnPlannedTaskArray[i].SchedResId, &schedsrv.UnPlannedTaskArray[i]) - + err = schedsrv.ScheduleTask(schedsrv.UnPlannedTaskArray[i].SchedResId, &schedsrv.UnPlannedTaskArray[i]) + if err != nil { + return err + } } return }