// Copyright (c) Shenyang Leading Edge Intelligent Technology Co., Ltd. All rights reserved.

package implments

import (
	baseDal "LAPP_ACURA_MOM_BACKEND/dao/base"
	jitDal "LAPP_ACURA_MOM_BACKEND/dao/jit"
	meDal "LAPP_ACURA_MOM_BACKEND/dao/me"
	omDal "LAPP_ACURA_MOM_BACKEND/dao/om"
	dal "LAPP_ACURA_MOM_BACKEND/dao/pln"
	qmDal "LAPP_ACURA_MOM_BACKEND/dao/qm"
	"LAPP_ACURA_MOM_BACKEND/db"
	"LAPP_ACURA_MOM_BACKEND/global"
	"LAPP_ACURA_MOM_BACKEND/grmi"
	"LAPP_ACURA_MOM_BACKEND/infra/logger"
	baseMeta "LAPP_ACURA_MOM_BACKEND/meta/base"
	meMeta "LAPP_ACURA_MOM_BACKEND/meta/me"
	omMeta "LAPP_ACURA_MOM_BACKEND/meta/om"
	meta "LAPP_ACURA_MOM_BACKEND/meta/pln"
	qmMeta "LAPP_ACURA_MOM_BACKEND/meta/qm"
	baseModel "LAPP_ACURA_MOM_BACKEND/models/base"
	meModel "LAPP_ACURA_MOM_BACKEND/models/me"
	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/utils"
	"container/list"
	"errors"
	"github.com/360EntSecGroup-Skylar/excelize/v2"
	uuid "github.com/iris-contrib/go.uuid"
	"strconv"
	"strings"
	"sync"

	//"sync"
	"time"
)

/******************************************************************************
 *
 * @Description              : CustOrder的默认查询条件
 *
 * @Author                   : 代码生成器创建
 *
 * @Date                     : 2021-10-22 13:50:40
 *
 ******************************************************************************/
var DefaultConditionOfCustOrder = grmi.NewCondition(
	map[string]grmi.ConditionItem{
		meta.CustOrder_CustOrderId.UrlParameterName:        grmi.NewConditionItem(meta.CustOrder_CustOrderId, grmi.Equal, true),
		meta.CustOrder_ProductFamilyId.UrlParameterName:    grmi.NewConditionItem(meta.CustOrder_ProductFamilyId, grmi.Equal, false),
		meta.CustOrder_PartId.UrlParameterName:             grmi.NewConditionItem(meta.CustOrder_PartId, grmi.Equal, false),
		meta.CustOrder_OemOrderId.UrlParameterName:         grmi.NewConditionItem(meta.CustOrder_OemOrderId, grmi.Equal, false),
		meta.CustOrder_OrderType.UrlParameterName:          grmi.NewConditionItem(meta.CustOrder_OrderType, grmi.Equal, false),
		meta.CustOrder_OrderInfo.UrlParameterName:          grmi.NewConditionItem(meta.CustOrder_OrderInfo, grmi.Equal, false),
		meta.CustOrder_OrderTime.UrlParameterName:          grmi.NewConditionItem(meta.CustOrder_OrderTime, grmi.Approximate, false),
		meta.CustOrder_DeliveryTime.UrlParameterName:       grmi.NewConditionItem(meta.CustOrder_DeliveryTime, grmi.Approximate, false),
		meta.CustOrder_ProjectId.UrlParameterName:          grmi.NewConditionItem(meta.CustOrder_ProjectId, grmi.Equal, false),
		meta.CustOrder_ConfigValue.UrlParameterName:        grmi.NewConditionItem(meta.CustOrder_ConfigValue, grmi.Equal, false),
		meta.CustOrder_ModelValue.UrlParameterName:         grmi.NewConditionItem(meta.CustOrder_ModelValue, grmi.Equal, false),
		meta.CustOrder_ColorValue.UrlParameterName:         grmi.NewConditionItem(meta.CustOrder_ColorValue, grmi.Equal, false),
		meta.CustOrder_HandleStatus.UrlParameterName:       grmi.NewConditionItem(meta.CustOrder_HandleStatus, grmi.Equal, false),
		meta.CustOrder_VinPrefix.UrlParameterName:          grmi.NewConditionItem(meta.CustOrder_VinPrefix, grmi.Equal, false),
		meta.CustOrder_VinNrFrom.UrlParameterName:          grmi.NewConditionItem(meta.CustOrder_VinNrFrom, grmi.Equal, false),
		meta.CustOrder_VinNrTo.UrlParameterName:            grmi.NewConditionItem(meta.CustOrder_VinNrTo, grmi.Equal, false),
		meta.CustOrder_Vin.UrlParameterName:                grmi.NewConditionItem(meta.CustOrder_Vin, grmi.Equal, false),
		meta.CustOrder_PlanQty.UrlParameterName:            grmi.NewConditionItem(meta.CustOrder_PlanQty, grmi.Equal, false),
		meta.CustOrder_DeliveryDate.UrlParameterName:       grmi.NewConditionItem(meta.CustOrder_DeliveryDate, grmi.Approximate, false),
		meta.CustOrder_DeliveryDateTime.UrlParameterName:   grmi.NewConditionItem(meta.CustOrder_DeliveryDateTime, grmi.Approximate, false),
		meta.CustOrder_OemSeq.UrlParameterName:             grmi.NewConditionItem(meta.CustOrder_OemSeq, grmi.Equal, false),
		meta.CustOrder_AssemblyLine.UrlParameterName:       grmi.NewConditionItem(meta.CustOrder_AssemblyLine, grmi.Equal, false),
		meta.CustOrder_UnloadingPoint.UrlParameterName:     grmi.NewConditionItem(meta.CustOrder_UnloadingPoint, grmi.Equal, false),
		meta.CustOrder_CalloffId.UrlParameterName:          grmi.NewConditionItem(meta.CustOrder_CalloffId, grmi.Equal, false),
		meta.CustOrder_CalloffDateTime.UrlParameterName:    grmi.NewConditionItem(meta.CustOrder_CalloffDateTime, grmi.Approximate, false),
		meta.CustOrder_ConsigneePlant.UrlParameterName:     grmi.NewConditionItem(meta.CustOrder_ConsigneePlant, grmi.Equal, false),
		meta.CustOrder_ConsigneeCompany.UrlParameterName:   grmi.NewConditionItem(meta.CustOrder_ConsigneeCompany, grmi.Equal, false),
		meta.CustOrder_ConsumeCompany.UrlParameterName:     grmi.NewConditionItem(meta.CustOrder_ConsumeCompany, grmi.Equal, false),
		meta.CustOrder_ConsumePlant.UrlParameterName:       grmi.NewConditionItem(meta.CustOrder_ConsumePlant, grmi.Equal, false),
		meta.CustOrder_UnloadingPlace.UrlParameterName:     grmi.NewConditionItem(meta.CustOrder_UnloadingPlace, grmi.Equal, false),
		meta.CustOrder_VehicleIdSet.UrlParameterName:       grmi.NewConditionItem(meta.CustOrder_VehicleIdSet, grmi.Equal, false),
		meta.CustOrder_VehicleId.UrlParameterName:          grmi.NewConditionItem(meta.CustOrder_VehicleId, grmi.Equal, false),
		meta.CustOrder_WorkLineId.UrlParameterName:         grmi.NewConditionItem(meta.CustOrder_WorkLineId, grmi.Equal, false),
		meta.CustOrder_PlanStartTime.UrlParameterName:      grmi.NewConditionItem(meta.CustOrder_PlanStartTime, grmi.Equal, false),
		meta.CustOrder_PlanEndTime.UrlParameterName:        grmi.NewConditionItem(meta.CustOrder_PlanEndTime, grmi.Equal, false),
		meta.CustOrder_PlanStartDate.UrlParameterName:      grmi.NewConditionItem(meta.CustOrder_PlanStartDate, grmi.Equal, false),
		meta.CustOrder_PlanEndDate.UrlParameterName:        grmi.NewConditionItem(meta.CustOrder_PlanEndDate, grmi.Equal, false),
		meta.CustOrder_ActStartTime.UrlParameterName:       grmi.NewConditionItem(meta.CustOrder_ActStartTime, grmi.Equal, false),
		meta.CustOrder_ActEndTime.UrlParameterName:         grmi.NewConditionItem(meta.CustOrder_ActEndTime, grmi.Equal, false),
		meta.CustOrder_SetupStartTime.UrlParameterName:     grmi.NewConditionItem(meta.CustOrder_SetupStartTime, grmi.Equal, false),
		meta.CustOrder_SetupEndTime.UrlParameterName:       grmi.NewConditionItem(meta.CustOrder_SetupEndTime, grmi.Equal, false),
		meta.CustOrder_FixStartTimeToggle.UrlParameterName: grmi.NewConditionItem(meta.CustOrder_FixStartTimeToggle, grmi.Equal, false),
		meta.CustOrder_QuantityPerHour.UrlParameterName:    grmi.NewConditionItem(meta.CustOrder_QuantityPerHour, grmi.Equal, false),
		meta.CustOrder_CtrlPara1.UrlParameterName:          grmi.NewConditionItem(meta.CustOrder_CtrlPara1, grmi.Equal, false),
		meta.CustOrder_CtrlPara2.UrlParameterName:          grmi.NewConditionItem(meta.CustOrder_CtrlPara2, grmi.Equal, false),
		meta.CustOrder_CtrlStr1.UrlParameterName:           grmi.NewConditionItem(meta.CustOrder_CtrlStr1, grmi.Equal, false),
		meta.CustOrder_CtrlStr2.UrlParameterName:           grmi.NewConditionItem(meta.CustOrder_CtrlStr2, grmi.Equal, false),
		meta.CustOrder_LastModify.UrlParameterName:         grmi.NewConditionItem(meta.CustOrder_LastModify, grmi.Approximate, false),
		meta.CustOrder_LastUser.UrlParameterName:           grmi.NewConditionItem(meta.CustOrder_LastUser, grmi.Equal, false),
		meta.CustOrder_CreateTime.UrlParameterName:         grmi.NewConditionItem(meta.CustOrder_CreateTime, grmi.Approximate, false),
		meta.CustOrder_SourceId.UrlParameterName:           grmi.NewConditionItem(meta.CustOrder_SourceId, grmi.Equal, false),
	},
	nil,
)

/******************************************************************************
 *
 * @Description              : CustOrder的默认分页查询条件
 *
 * @Author                   : 代码生成器创建
 *
 * @Date                     : 2021-10-22 13:50:40
 *
 ******************************************************************************/
var DefaultConditionOfCustOrderAndPaging = grmi.NewCondition(
	DefaultConditionOfCustOrder.Items,
	grmi.NewPaging(),
)

/******************************************************************************
 *
 * @Struct Name              : CustOrderServiceImplement
 *-----------------------------------------------------------------------------
 *
 * @Description              : CustOrder的服务实现
 *
 * @Author                   : 代码生成器创建
 *
 * @Date                     : 2021-10-22 13:50:40
 *
 ******************************************************************************/
type CustOrderServiceImplement struct {
}

/******************************************************************************
 *
 * @Function Name            : NewCustOrderDAOImplement
 *-----------------------------------------------------------------------------
 *
 * @Description              : 创建一个CustOrderDAOImplement实例
 *
 * @Return Value             : CustOrderDAOImplement实例
 *
 * @Author                   : 代码生成器创建
 *
 * @Date                     : 2021-10-22 13:50:40
 *
 ******************************************************************************/
func NewCustOrderServiceImplement() *CustOrderServiceImplement {
	return &CustOrderServiceImplement{}
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/CustOrderService.InsertOne
 *
 ******************************************************************************/
func (impl *CustOrderServiceImplement) InsertOne(user *global.User, entity *model.CustOrder) error {

	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "InsertOneCustOrder", "插入一个CustOrder")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	snrDao := baseDal.NewSnrDAO(session, user.PlantNr, user.UserId)
	projectDao := meDal.NewProjectDAO(session, user.PlantNr, user.UserId)
	qtyDao := dal.NewCustOrderQtyDAO(session, user.PlantNr, user.UserId)
	statusDao := dal.NewCustOrderStatusDAO(session, user.PlantNr, user.UserId)
	if entity.PlanQty == 0 {
		return grmi.NewBusinessError("创建客户订单计划生产数量为0")
	}
	if entity.ProductFamilyId == "" {
		return grmi.NewBusinessError("工单数据缺失")
	}
	productFamilyDao := meDal.NewProductFamilyDAO(session, user.PlantNr, user.UserId)
	productFamily, err := productFamilyDao.SelectOne(entity.ProductFamilyId)
	if err != nil {
		return grmi.NewBusinessError("查询车型配置失败, error:" + err.Error())
	}
	if productFamily == nil {
		return grmi.NewBusinessError("不存在订单指定的车型配置,车型配置ID:" + entity.ProductFamilyId)
	}
	if !productFamily.Enable {
		return grmi.NewBusinessError("当前派生未启用， 不允许创建客户订单")
	}
	project, err := projectDao.SelectOne(productFamily.ProjectId)
	if err != nil {
		return grmi.NewBusinessError("查询车型项目失败, error:" + err.Error())
	}
	if project == nil {
		return grmi.NewBusinessError("不存在对应的车型项目, 车型项目ID:" + productFamily.ProjectId)
	}
	// 校验指定的生产产线 派生是否已经关联
	if entity.WorkLineId == "" {
		return grmi.NewBusinessError("未指定生产产线")
	}
	usedWorkLineId := entity.WorkLineId
	if !productFamily.MultiWorkLineToggle {
		if usedWorkLineId != productFamily.WorkLineId {
			return grmi.NewBusinessError("该派生不能在指定的产线上生产")
		}
	} else {
		productFamilyWorkLineDao := meDal.NewProductFamilyWorkLineLstDAO(session, user.PlantNr, user.UserId)
		workLineLi, err := productFamilyWorkLineDao.Select([]grmi.Predicate{
			meMeta.ProductFamilyWorkLineLst_ProductFamilyId.NewPredicate(grmi.Equal, entity.ProductFamilyId),
		}, nil)
		if err != nil {
			return grmi.NewBusinessError("查询派生产线关联数据失败, 错误:" + err.Error())
		}
		var canProduct bool
		for _, workLine := range workLineLi {
			if workLine.WorkLineId == entity.WorkLineId {
				canProduct = true
				break
			}
		}
		if !canProduct {
			return grmi.NewBusinessError("该派生不能在指定的产线上生产")
		}
	}
	entity.SourceId = baseModel.ODER_TYPE_INTERVAL
	entity.OrderType = baseModel.ODER_TYPE_INTERVAL
	entity.QuantityPerHour = int(productFamily.Jph)
	entity.OrderInfo = productFamily.Descr
	entity.ConfigValue = productFamily.ConfigValue
	entity.ColorValue = productFamily.ColorValue
	entity.ModelValue = productFamily.ModelValue
	entity.ProjectId = productFamily.ProjectId
	if err = session.Begin(); err != nil {
		return err
	}
	custOrderId, err := snrDao.GetNextSnr(project.CustOrderSnr)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("生成客户订单流水号失败, error:" + custOrderId)
	}
	entity.CustOrderId = custOrderId
	custOrderQty := model.CustOrderQty{
		CustOrderId: custOrderId,
		PlanQty:     entity.PlanQty,
	}
	err = qtyDao.InsertOne(&custOrderQty)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("写入客户订单数量失败, error:" + err.Error())
	}
	custOrderStatus := model.CustOrderStatus{
		CustOrderId: custOrderId,
		Status:      baseModel.WO_STATUS_UNPLANNED,
	}
	err = statusDao.InsertOne(&custOrderStatus)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("写入客户订单状态数据失败, error:" + err.Error())
	}
	err = dao.InsertOne(entity)
	if err != nil {
		_ = session.Rollback()
		return err
	}
	_ = session.Commit()
	return nil
}

func (impl *CustOrderServiceImplement) Cancel(user *global.User, custOrderId string) error {
	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "Cancel", "取消一个CustOrder")
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	record, err := dao.SelectOne(custOrderId)
	if err != nil {
		return err
	}
	if record == nil {
		return grmi.NewBusinessError("不存在指定记录!")
	}
	//查询订单状态
	statusDao := dal.NewCustOrderStatusDAO(session, user.PlantNr, user.UserId)
	historyDao := dal.NewCustOrderStatusHistoryDAO(session, user.PlantNr, user.UserId)
	status, err := statusDao.SelectOne(record.CustOrderId)
	if err != nil {
		return err
	}
	if status.Status != baseModel.ORDER_STATUS_UNPLANED {
		return grmi.NewBusinessError("订单状态不在未计划中无法取消")
	}
	//修改订单状态
	session.Begin()
	status.Status = baseModel.ORDER_STATUS_CANCELED
	err = statusDao.UpdateOne(status)
	if err != nil {
		session.Rollback()
		return grmi.NewBusinessError(err.Error())
	}
	statusLog := model.CustOrderStatusHistory{
		CustOrderId: record.CustOrderId,
		FromStatus:  baseModel.ORDER_STATUS_UNPLANED,
		ToStatus:    baseModel.ORDER_STATUS_CANCELED,
		ChangeTime:  grmi.DateTime{},
	}
	err = historyDao.InsertOne(&statusLog)
	if err != nil {
		session.Rollback()
		return grmi.NewBusinessError(err.Error())
	}
	_ = session.Commit()
	return nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/CustOrderService.DeleteOne
 *
 ******************************************************************************/
func (impl *CustOrderServiceImplement) DeleteOne(user *global.User, custOrderId string) error {

	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "DeleteOneCustOrder", "删除一个CustOrder")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	record, err := dao.SelectOne(custOrderId)
	if err != nil {
		return err
	}
	if record == nil {
		return grmi.NewBusinessError("不存在指定记录!")
	}
	err = dao.DeleteOne(custOrderId)
	if err != nil {
		return err
	}
	return nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/CustOrderService.SelectOne
 *
 ******************************************************************************/
func (impl *CustOrderServiceImplement) SelectOne(user *global.User, custOrderId string) (*model.CustOrder, error) {

	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "SelectOneCustOrder", "查询一个CustOrder")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	result, err := dao.SelectOne(custOrderId)

	if err != nil {
		return nil, err
	}
	return result, nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/CustOrderService.UpdateOne
 *
 ******************************************************************************/
func (impl *CustOrderServiceImplement) UpdateOne(user *global.User, entity *model.CustOrder) error {

	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "UpdateOneCustOrder", "修改一个CustOrder")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	custOrderQtyDao := dal.NewCustOrderQtyDAO(session, user.PlantNr, user.UserId)
	record, err := dao.SelectOne(entity.CustOrderId)
	if err != nil {
		return err
	}
	if record == nil {
		return grmi.NewBusinessError("不存在指定记录!")
	}
	if record.OrderStatus.Status != baseModel.WO_STATUS_UNPLANNED {
		return grmi.NewBusinessError("该客户订单状态不是未计划，不允许修改")
	}
	if err := session.Begin(); err != nil {
		return grmi.NewBusinessError("开启事务失败, error:" + err.Error())
	}
	if record.PlanQty != entity.PlanQty {
		record.OrderQty.PlanQty = entity.PlanQty
		err = custOrderQtyDao.UpdateOne(&record.OrderQty)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("更新客户订单数量失败, error:" + err.Error())
		}
	}
	err = dao.UpdateOne(entity)
	if err != nil {
		_ = session.Rollback()
		return err
	}
	_ = session.Commit()
	return nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/CustOrderService.Insert
 *
 ******************************************************************************/
func (impl *CustOrderServiceImplement) Insert(user *global.User, entities *[]model.CustOrder) error {

	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "InsertCustOrder", "插入多个CustOrder")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)

	for _, entity := range *entities {
		record, err := dao.SelectOne(entity.CustOrderId)
		if err != nil {
			return err
		}
		if record != nil {
			return grmi.NewBusinessError("已经存在相同主键的记录!")
		}
	}

	err := dao.Insert(entities)
	if err != nil {
		return err
	}
	return nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/CustOrderService.Delete
 *
 ******************************************************************************/
func (impl *CustOrderServiceImplement) Delete(user *global.User, entities *[]model.CustOrder) error {

	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "DeleteCustOrder", "删除多个CustOrder")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)

	for _, entity := range *entities {
		record, err := dao.SelectOne(entity.CustOrderId)
		if err != nil {
			return err
		}
		if record == nil {
			return grmi.NewBusinessError("不存在指定记录!")
		}
	}

	err := dao.Delete(entities)
	if err != nil {
		return err
	}
	return nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/CustOrderService.Select
 *
 ******************************************************************************/
func (impl *CustOrderServiceImplement) Select(user *global.User, urlParameters map[string]string) ([]model.CustOrder, error) {

	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "SelectCustOrder", "查询CustOrder")

	condition := DefaultConditionOfCustOrderAndPaging
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	predicates, err := condition.BuildPredicates(urlParameters)
	if err != nil {
		return nil, err
	}
	dao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	result, err := dao.Select(predicates, condition.OrderByFields)
	if err != nil {
		return nil, err
	}
	return result, nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/CustOrderService.SelectAndPaging
 *
 ******************************************************************************/
func (impl *CustOrderServiceImplement) SelectAndPaging(user *global.User, urlParameters map[string]string) (grmi.PagingResult, error) {

	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "SelectCustOrder", "查询CustOrder")

	condition := DefaultConditionOfCustOrderAndPaging
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	predicates, err := condition.BuildPredicates(urlParameters)
	if err != nil {
		return grmi.EmptyPagingResult, err
	}
	dao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	condition.Fill(urlParameters)
	result, err := dao.SelectAndPaging(condition.Paging, predicates, condition.OrderByFields)
	if err != nil {
		return grmi.EmptyPagingResult, err
	}
	return result, nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/CustOrderService.Update
 *
 ******************************************************************************/
func (impl *CustOrderServiceImplement) Update(user *global.User, entities *[]model.CustOrder) error {

	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "UpdateCustOrder", "修改多个CustOrder")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)

	for _, entity := range *entities {
		record, err := dao.SelectOne(entity.CustOrderId)
		if err != nil {
			return err
		}
		if record == nil {
			return grmi.NewBusinessError("不存在指定记录!")
		}
	}

	err := dao.Update(entities)
	if err != nil {
		return err
	}
	return nil
}

// PlanCustOrder 将客户订单状态置为已计划 并设置计划开始时间
func (impl *CustOrderServiceImplement) PlanCustOrder(user *global.User, entity *model.CustOrder) error {
	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "PlanCustOrder", "计划客户订单")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	if err := session.Begin(); err != nil {
		return err
	}
	entity.PlanStartDate = grmi.Date(time.Now())
	entity.PlanEndDate = grmi.Date(time.Now())
	entity.PlanStartTime = grmi.DateTime(time.Now())
	entity.PlanEndTime = grmi.DateTime(time.Now())
	dao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	record, err := dao.SelectOne(entity.CustOrderId)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("查询客户订单数据失败, error:" + err.Error())
	}
	if record == nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("客户订单不存在, 订单ID:" + entity.CustOrderId)
	}
	statusDao := dal.NewCustOrderStatusDAO(session, user.PlantNr, user.UserId)
	status, err := statusDao.SelectOne(entity.CustOrderId)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("查询客户订单状态失败, error:" + err.Error())
	}
	if status == nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("客户订单状态不存在, 订单ID:" + entity.CustOrderId)
	}
	if status.Status != baseModel.WO_STATUS_UNPLANNED {
		_ = session.Rollback()
		return grmi.NewBusinessError("客户订单状态不是未计划, 订单ID:" + entity.CustOrderId)
	}
	err = dao.UpdateOne(entity)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("更新客户订单数据失败, error:" + err.Error())
	}
	status.Status = baseModel.WO_STATUS_PLANNED
	err = statusDao.UpdateOne(status)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("更新客户订单状态失败， error:" + err.Error())
	}
	statusRecDao := dal.NewCustOrderStatusHistoryDAO(session, user.PlantNr, user.UserId)
	statusRec := model.CustOrderStatusHistory{
		CustOrderId: entity.CustOrderId,
		FromStatus:  baseModel.WO_STATUS_UNPLANNED,
		ToStatus:    baseModel.WO_STATUS_PLANNED,
		ChangeTime:  grmi.DateTime(time.Now()),
	}
	err = statusRecDao.InsertOne(&statusRec)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("插入客户订单状态变更记录失败, error:" + err.Error())
	}
	_ = session.Commit()
	return nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/CustOrderService.LockCustOrder
 *
 ******************************************************************************/
func (impl *CustOrderServiceImplement) LockCustOrder(user *global.User, custOrderIdLi []string) error {
	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "LockCustOrder", "锁定客户订单")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	custOrderDao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	projectDao := meDal.NewProjectDAO(session, user.PlantNr, user.UserId)
	snrDao := baseDal.NewSnrDAO(session, user.PlantNr, user.UserId)
	workLineDao := baseDal.NewWorkLineDAO(session, user.PlantNr, user.UserId)
	custOrderStatusDao := dal.NewCustOrderStatusDAO(session, user.PlantNr, user.UserId)
	custOrderStatusRecDao := dal.NewCustOrderStatusHistoryDAO(session, user.PlantNr, user.UserId)
	serialOrderDao := omDal.NewSerialOrderDAO(session, user.PlantNr, user.UserId)
	serialOrderStatusDao := omDal.NewSerialOrderStatusDAO(session, user.PlantNr, user.UserId)
	serialOrderStatusRecDao := omDal.NewSerialOrderStatusRecLstDAO(session, user.PlantNr, user.UserId)
	serialOrderPoDao := omDal.NewSerialOrderPOLstDAO(session, user.PlantNr, user.UserId)
	serialOrderStepDao := omDal.NewSerialOrderStepLstDAO(session, user.PlantNr, user.UserId)
	serialOrderOPDetailDao := omDal.NewSerialOrderOPDetailDAO(session, user.PlantNr, user.UserId)
	productFamilyRelateDao := meDal.NewProductFamilyRelateDAO(session, user.PlantNr, user.UserId)
	productWorkLineDao := meDal.NewProductWorkLineLstDAO(session, user.PlantNr, user.UserId)
	custOrderQtyDao := dal.NewCustOrderQtyDAO(session, user.PlantNr, user.UserId)
	// 产线组与所属产线的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{})
		}
	}
	for _, workLine := range allWorkLineLi {
		if workLine.GroupType == baseModel.WORK_LINE_TYPE_REAL {
			_, exist := workLineGroupMap[workLine.GroupLineId]
			if exist {
				workLineGroupMap[workLine.GroupLineId][workLine.WorkLineid] = nil
			}
		}
	}
	if err = session.Begin(); err != nil {
		return err
	}

	// 用于生成工艺的serialOrder map
	productSerialOrderMap := make(map[string][]*omModel.SerialOrder)
	for _, custOrderId := range custOrderIdLi {
		// 校验客户订单是否存在及状态
		orderData, err := custOrderDao.SelectOne(custOrderId)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("查询客户订单失败, error:" + err.Error())
		}
		if orderData == nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("客户订单不存在, 订单ID:" + custOrderId)
		}
		if orderData.OrderStatus.Status != baseModel.WO_STATUS_PLANNED {
			_ = session.Rollback()
			return grmi.NewBusinessError("客户订单当前状态不是已计划, 订单ID:" + custOrderId)
		}
		// 获取客户订单的车型配置下的所有座椅
		productLi, err := productFamilyRelateDao.SelectProductByFamilyIdForCreateSerialOrder(orderData.ProjectId, orderData.ProductFamilyId)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("通过车型配置查询关联座椅产品失败, error:" + err.Error())
		}
		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
		// 如果客户订单是拆分出来的客户订单 则只是重置所归属的工单及工艺状态
		if orderData.CtrlPara1 == 1 {
			serialOrderDataLi, err := serialOrderDao.Select([]grmi.Predicate{
				omMeta.SerialOrder_CustOrderId.NewPredicate(grmi.Equal, custOrderId),
				omMeta.SerialOrder_OrderType.NewPredicate(grmi.Equal, baseModel.ODER_TYPE_SEQ),
			}, []grmi.Field{omMeta.SerialOrder_PlanStartTime})
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("查询客户订单下的工单失败， error:" + err.Error())
			}
			for _, serialOrder := range serialOrderDataLi {
				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)
				timeInt, err := strconv.Atoi(planStartTime.Format("060102150405"))
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("通过时间获取工单调度Key失败, error:" + err.Error())
				}
				//dealedSchedKey := int64(todayInt*1000000 + schedKey*100)
				var dealedSchedKey = int64(timeInt * 100)
				serialOrder.PlanStartTime = grmi.DateTime(planStartTime)
				serialOrder.PlanEndTime = grmi.DateTime(planEndTime)
				serialOrder.PlanStartDate = planStartDate
				serialOrder.PlanEndDate = planEndDate
				serialOrder.SchedKey = dealedSchedKey
				err = serialOrderDao.UpdateOne(&serialOrder)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("更新工单数据失败， error:" + err.Error())
				}
				serialOrderStatusRec := omModel.SerialOrderStatusRecLst{
					SerialOrderId: serialOrder.SerialOrderId,
					PrevStatus:    serialOrder.SerialOrderStatus.Status,
					Status:        baseModel.WO_STATUS_RELEASED,
				}
				err = serialOrderStatusRecDao.InsertOne(&serialOrderStatusRec)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("写入工单状态变更历史失败, error:" + err.Error())
				}
				serialOrder.SerialOrderStatus.Status = baseModel.WO_STATUS_RELEASED
				err = serialOrderStatusDao.UpdateOne(&serialOrder.SerialOrderStatus)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("更新工单状态失败, error:" + err.Error())
				}
				poUpdateData := omModel.SerialOrderPOLst{
					Status: baseModel.WO_STATUS_RELEASED,
				}
				err = serialOrderPoDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderPOLst_SerialOrderId.NewPredicate(grmi.Equal, serialOrder.SerialOrderId)}, &poUpdateData, []string{omMeta.SerialOrderPOLst_Status.Name}...)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("更新工单工序状态失败, error:" + err.Error())
				}
				stepUpdateData := omModel.SerialOrderStepLst{
					Status: baseModel.WO_STATUS_RELEASED,
				}
				err = serialOrderStepDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderStepLst_SerialOrderId.NewPredicate(grmi.Equal, serialOrder.SerialOrderId)}, &stepUpdateData, []string{omMeta.SerialOrderStepLst_Status.Name}...)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("更新工单工步状态失败, error:" + err.Error())
				}
				opDetailUpdateData := omModel.SerialOrderOPDetail{
					Status: baseModel.WO_STATUS_RELEASED,
				}
				err = serialOrderOPDetailDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderOPDetail_SerialOrderId.NewPredicate(grmi.Equal, serialOrder.SerialOrderId)}, &opDetailUpdateData, []string{omMeta.SerialOrderOPDetail_Status.Name}...)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("更新工单详细操作状态失败, error:" + err.Error())
				}
				//	对预装工单的处理
				preSerialOrderLi, err := serialOrderDao.Select([]grmi.Predicate{
					omMeta.SerialOrder_OrderType.NewPredicate(grmi.Equal, baseModel.ORDER_TYPE_PRE),
					omMeta.SerialOrder_GenerateFlag.NewPredicate(grmi.Equal, 0),
					omMeta.SerialOrder_MainOrderId.NewPredicate(grmi.Equal, serialOrder.SerialOrderId),
				}, nil)
				if err != nil {
					return grmi.NewBusinessError("查询工单下的预装工单失败, 错误：" + err.Error())
				}
				for _, preOrder := range preSerialOrderLi {
					preOrder.PlanStartTime = grmi.DateTime(planStartTime)
					preOrder.PlanEndTime = grmi.DateTime(planEndTime)
					preOrder.PlanStartDate = grmi.Date(planStartTime)
					preOrder.PlanEndDate = grmi.Date(planEndTime)
					preOrder.SchedKey = dealedSchedKey
					err = serialOrderDao.UpdateOne(&preOrder)
					if err != nil {
						return grmi.NewBusinessError("更新预装工单数据失败, 错误：" + err.Error())
					}
					statusRec := omModel.SerialOrderStatusRecLst{
						SerialOrderId: preOrder.SerialOrderId,
						Status:        baseModel.WO_STATUS_RELEASED,
						PrevStatus:    preOrder.SerialOrderStatus.Status,
					}
					preOrder.SerialOrderStatus.Status = baseModel.WO_STATUS_RELEASED
					err = serialOrderStatusRecDao.InsertOne(&statusRec)
					if err != nil {
						_ = session.Rollback()
						return grmi.NewBusinessError("插入预装工单状态变更记录失败, error:" + err.Error())
					}
					err = serialOrderStatusDao.UpdateOneWithStatus(&preOrder.SerialOrderStatus, baseModel.WO_STATUS_UNPLANNED)
					if err != nil {
						_ = session.Rollback()
						return grmi.NewBusinessError("更新预装工单状态失败， error:" + err.Error())
					}
					poUpdateData := &omModel.SerialOrderPOLst{
						Status: baseModel.WO_STATUS_RELEASED,
					}
					err = serialOrderPoDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderPOLst_SerialOrderId.NewPredicate(grmi.Equal, preOrder.SerialOrderId)}, poUpdateData, omMeta.SerialOrderPOLst_Status.Name)
					if err != nil {
						_ = session.Rollback()
						return grmi.NewBusinessError("更新预装工单工序状态失败, error:" + err.Error())
					}
					stepUpdateData := &omModel.SerialOrderStepLst{
						Status: baseModel.WO_STATUS_RELEASED,
					}
					err = serialOrderStepDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderStepLst_SerialOrderId.NewPredicate(grmi.Equal, preOrder.SerialOrderId)}, stepUpdateData, omMeta.SerialOrderStepLst_Status.Name)
					if err != nil {
						_ = session.Rollback()
						return grmi.NewBusinessError("更新预装工单工步状态失败, error:" + err.Error())
					}
					opDetailUpdateData := &omModel.SerialOrderOPDetail{
						Status: baseModel.WO_STATUS_RELEASED,
					}
					err = serialOrderOPDetailDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderOPDetail_SerialOrderId.NewPredicate(grmi.Equal, preOrder.SerialOrderId)}, opDetailUpdateData, omMeta.SerialOrderOPDetail_Status.Name)
					if err != nil {
						_ = session.Rollback()
						return grmi.NewBusinessError("更新预装工单详细操作状态失败, error:" + err.Error())
					}
				}
			}
			custOrderStatusRec := model.CustOrderStatusHistory{
				CustOrderId: custOrderId,
				FromStatus:  orderData.OrderStatus.Status,
				ToStatus:    baseModel.WO_STATUS_RELEASED,
				ChangeTime:  grmi.DateTime(time.Now()),
			}
			err = custOrderStatusRecDao.InsertOne(&custOrderStatusRec)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("插入客户订单状态变更历史失败, error:" + err.Error())
			}
			orderData.OrderStatus.Status = baseModel.WO_STATUS_RELEASED
			err = custOrderStatusDao.UpdateOne(&orderData.OrderStatus)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("更新客户订单状态失败, error:" + err.Error())
			}
			_ = session.Commit()
			return nil
		}
		project, err := projectDao.SelectOne(orderData.ProjectId)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("获取车型项目失败, error:" + err.Error())
		}
		if project == nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("车型项目不存在, 车型项目ID:" + orderData.ProjectId)
		}

		// 临时工单列表
		serialOrderLi := make([]omModel.SerialOrder, 0)
		// 临时工单状态列表
		serialOrderStatusLi := make([]omModel.SerialOrderStatus, 0)

		// 创建序列工单和工单状态
		for i := 0; i < orderData.PlanQty; i++ {
			syncKey = custOrderId + "-" + strconv.Itoa(i)
			serialNumber, err := snrDao.GetNextSnrWithTime(project.SerialOrderSnr, orderData.PlanStartDate.Restore())
			if err != nil {
				_ = session.Rollback()
				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)
			}
		}
		// 将工单数据落库
		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("插入序列工单数据失败, 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)
			}
			tempSerialOrderStatusLi = append(tempSerialOrderStatusLi, serialOrderStatus)
		}
		if len(tempSerialOrderStatusLi) != 0 {
			err = serialOrderStatusDao.Insert(&tempSerialOrderStatusLi)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("插入序列工单状态数据失败, error:" + err.Error())
			}
		}
		custOrderStatusRec := model.CustOrderStatusHistory{
			CustOrderId: custOrderId,
			FromStatus:  orderData.OrderStatus.Status,
			ToStatus:    baseModel.WO_STATUS_RELEASED,
			ChangeTime:  grmi.DateTime(time.Now()),
		}
		err = custOrderStatusRecDao.InsertOne(&custOrderStatusRec)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("插入客户订单状态变更历史失败, error:" + err.Error())
		}
		// 更新客户订单状态
		orderData.OrderStatus.Status = baseModel.WO_STATUS_RELEASED
		err = custOrderStatusDao.UpdateOne(&orderData.OrderStatus)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("更新客户订单状态失败, error:" + 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()
	return nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/CustOrderService.LockCustOrder
 *
 ******************************************************************************/
func (impl *CustOrderServiceImplement) LockCustOrderForGantt(user *global.User, custOrderIdLi []string) error {
	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "LockCustOrder", "锁定客户订单")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	if err := session.Begin(); err != nil {
		return err
	}
	today := time.Now().Format("060102")
	todayInt, _ := strconv.Atoi(today)
	custOrderDao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	projectDao := meDal.NewProjectDAO(session, user.PlantNr, user.UserId)
	snrDao := baseDal.NewSnrDAO(session, user.PlantNr, user.UserId)
	workLineDao := baseDal.NewWorkLineDAO(session, user.PlantNr, user.UserId)
	custOrderStatusDao := dal.NewCustOrderStatusDAO(session, user.PlantNr, user.UserId)
	custOrderStatusRecDao := dal.NewCustOrderStatusHistoryDAO(session, user.PlantNr, user.UserId)
	serialOrderDao := omDal.NewSerialOrderDAO(session, user.PlantNr, user.UserId)
	serialOrderStatusDao := omDal.NewSerialOrderStatusDAO(session, user.PlantNr, user.UserId)
	serialOrderStatusRecDao := omDal.NewSerialOrderStatusRecLstDAO(session, user.PlantNr, user.UserId)
	serialOrderPoDao := omDal.NewSerialOrderPOLstDAO(session, user.PlantNr, user.UserId)
	serialOrderStepDao := omDal.NewSerialOrderStepLstDAO(session, user.PlantNr, user.UserId)
	serialOrderOPDetailDao := omDal.NewSerialOrderOPDetailDAO(session, user.PlantNr, user.UserId)
	productFamilyRelateDao := meDal.NewProductFamilyRelateDAO(session, user.PlantNr, user.UserId)
	// 用于生成工艺的serialOrder map
	productSerialOrderMap := make(map[string][]*omModel.SerialOrder)
	for _, custOrderId := range custOrderIdLi {
		// 校验客户订单是否存在及状态
		orderData, err := custOrderDao.SelectOneWithStatus(custOrderId)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("查询客户订单失败, error:" + err.Error())
		}
		if orderData == nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("客户订单不存在, 订单ID:" + custOrderId)
		}
		if orderData.CustOrderStatus.Status != baseModel.WO_STATUS_PLANNED {
			_ = session.Rollback()
			return grmi.NewBusinessError("客户订单当前状态不是已计划, 订单ID:" + custOrderId)
		}
		// 如果客户订单是拆分出来的客户订单 则只是重置所归属的工单及工艺状态
		if orderData.CtrlPara1 == 1 {
			serialOrderDataLi, err := serialOrderDao.Select([]grmi.Predicate{omMeta.SerialOrder_CustOrderId.NewPredicate(grmi.Equal, custOrderId)}, nil)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("查询客户订单下的工单失败， error:" + err.Error())
			}
			for _, serialOrder := range serialOrderDataLi {
				serialOrderStatusRec := omModel.SerialOrderStatusRecLst{
					SerialOrderId: serialOrder.SerialOrderId,
					PrevStatus:    serialOrder.SerialOrderStatus.Status,
					Status:        baseModel.WO_STATUS_RELEASED,
				}
				err = serialOrderStatusRecDao.InsertOne(&serialOrderStatusRec)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("写入工单状态变更历史失败, error:" + err.Error())
				}
				serialOrder.SerialOrderStatus.Status = baseModel.WO_STATUS_RELEASED
				err = serialOrderStatusDao.UpdateOne(&serialOrder.SerialOrderStatus)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("更新工单状态失败, error:" + err.Error())
				}
				poUpdateData := omModel.SerialOrderPOLst{
					Status: baseModel.WO_STATUS_RELEASED,
				}
				err = serialOrderPoDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderPOLst_SerialOrderId.NewPredicate(grmi.Equal, serialOrder.SerialOrderId)}, &poUpdateData, []string{omMeta.SerialOrderPOLst_Status.Name}...)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("更新工单工序状态失败, error:" + err.Error())
				}
				stepUpdateData := omModel.SerialOrderStepLst{
					Status: baseModel.WO_STATUS_RELEASED,
				}
				err = serialOrderStepDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderStepLst_SerialOrderId.NewPredicate(grmi.Equal, serialOrder.SerialOrderId)}, &stepUpdateData, []string{omMeta.SerialOrderStepLst_Status.Name}...)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("更新工单工步状态失败, error:" + err.Error())
				}
				opDetailUpdateData := omModel.SerialOrderOPDetail{
					Status: baseModel.WO_STATUS_RELEASED,
				}
				err = serialOrderOPDetailDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderOPDetail_SerialOrderId.NewPredicate(grmi.Equal, serialOrder.SerialOrderId)}, &opDetailUpdateData, []string{omMeta.SerialOrderOPDetail_Status.Name}...)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("更新工单详细操作状态失败, error:" + err.Error())
				}
			}
			_ = session.Commit()
			return nil
		}
		project, err := projectDao.SelectOne(orderData.CustOrder.ProjectId)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("获取车型项目失败, error:" + err.Error())
		}
		if project == nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("车型项目不存在, 车型项目ID:" + orderData.CustOrder.ProjectId)
		}
		// 获取客户订单的车型配置下的所有座椅
		productLi, err := productFamilyRelateDao.SelectProductByFamilyIdForCreateSerialOrder(orderData.CustOrder.ProjectId, orderData.CustOrder.ProductFamilyId)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("通过车型配置查询关联座椅产品失败, error:" + err.Error())
		}
		if len(productLi) == 0 {
			_ = session.Rollback()
			return grmi.NewBusinessError("该客户订单的车型配置未关联座椅产品")
		}
		// 临时工单列表
		serialOrderLi := make([]omModel.SerialOrder, 0)
		// 临时工单状态列表
		serialOrderStatusLi := make([]omModel.SerialOrderStatus, 0)
		// 通过客户订单的时间间隔进行切割 分配给每一个序列工单
		duration := orderData.CustOrder.PlanEndTime.Restore().Sub(time.Now())
		totalQty := orderData.CustOrder.PlanQty * len(productLi)
		var current int
		perDuration := duration.Seconds() / float64(totalQty)
		workLineMap := make(map[string]*baseModel.WorkLine)
		var isFirstPieceToggle bool
		var syncKey string
		// 创建序列工单和工单状态
		for i := 0; i < orderData.CustOrder.PlanQty; i++ {
			syncKey = custOrderId + "-" + strconv.Itoa(i+1)
			//serialNumberStr, err := snrDao.GetNextSnr(project.SerialOrderSnr)
			//if err != nil {
			//	_ = session.Rollback()
			//	return grmi.NewBusinessError("生成工单流水号失败, error:" + err.Error())
			//}
			//serialNumber, err := strconv.Atoi(serialNumberStr)
			//if err != nil {
			//	_ = session.Rollback()
			//	return grmi.NewBusinessError("流水号规则错误, error:" + err.Error())
			//}
			//first := serialNumber / 34
			//if first > 34 {
			//	_ = session.Rollback()
			//	return grmi.NewBusinessError("超过流水号支持的范围")
			//}
			//second := serialNumber % 34
			//firstStr := baseModel.NUMBER_MAP[first]
			//secondStr := baseModel.NUMBER_MAP[second]

			serialNumber, err := snrDao.GetNextSnrWithTime(project.SerialOrderSnr, orderData.CustOrder.PlanStartDate.Restore())
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("生成工单流水号失败, error:" + err.Error())
			}
			for _, product := range productLi {
				workLine, exist := workLineMap[product.DefaultWorkLineId]
				if !exist {
					workLine, err = workLineDao.SelectOne(product.DefaultWorkLineId)
					if err != nil {
						_ = session.Rollback()
						return grmi.NewBusinessError("查询插线数据失败, error:" + err.Error())
					}
					if workLine == nil {
						_ = session.Rollback()
						return grmi.NewBusinessError("产线绑定的默认产线不存在, 产线ID:" + product.DefaultWorkLineId)
					}
					workLineMap[product.DefaultWorkLineId] = workLine
				}
				//machineCode := product.MachineCode
				//serialOrderId := machineCode + yearStr + monthStr + dayStr + firstStr + secondStr + "0" + product.ColorValue
				schedKeyStr, err := snrDao.GetNextSnr(workLine.SchedKeySnr)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("生成产线调度Key流水号失败, error:" + err.Error())
				}
				schedKey, err := strconv.Atoi(schedKeyStr)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("调度Key流水号规则错误, 产线ID:" + workLine.WorkLineid)
				}
				dealedSchedKey := int64(todayInt*1000000 + schedKey*100)
				planStartTime := orderData.CustOrder.PlanStartTime.Restore().Add(time.Duration(int(perDuration)*current) * time.Second)
				planEndTime := orderData.CustOrder.PlanStartTime.Restore().Add(time.Duration(int(perDuration)*(current+1)) * time.Second)
				planStartDate := grmi.Date(planStartTime)
				planEndDate := grmi.Date(planEndTime)

				serialOrderId := product.MachineCode + serialNumber + product.ProductType + product.ColorValue

				if i == 0 {
					isFirstPieceToggle = true
				}
				serialOrder := omModel.SerialOrder{
					SerialOrderId:      serialOrderId,
					ArtId:              product.ProductId,
					ProjectId:          orderData.CustOrder.ProjectId,
					Descr:              product.Descr,
					CustOrderId:        orderData.CustOrder.CustOrderId,
					OrderType:          baseModel.ODER_TYPE_SEQ,
					PlanResourceId:     product.DefaultWorkLineId,
					UsedResourceId:     product.DefaultWorkLineId,
					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_LOCKED,
				}
				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)
			}
		}
		// 将工单数据落库
		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("插入序列工单数据失败, 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)
			}
			tempSerialOrderStatusLi = append(tempSerialOrderStatusLi, serialOrderStatus)
		}
		if len(tempSerialOrderStatusLi) != 0 {
			err = serialOrderStatusDao.Insert(&tempSerialOrderStatusLi)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("插入序列工单状态数据失败, error:" + err.Error())
			}
		}
		custOrderStatusRec := model.CustOrderStatusHistory{
			CustOrderId: custOrderId,
			FromStatus:  orderData.CustOrderStatus.Status,
			ToStatus:    baseModel.WO_STATUS_LOCKED,
			ChangeTime:  grmi.DateTime(time.Now()),
		}
		err = custOrderStatusRecDao.InsertOne(&custOrderStatusRec)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("插入客户订单状态变更历史失败, error:" + err.Error())
		}
		// 更新客户订单状态
		orderData.CustOrderStatus.Status = baseModel.WO_STATUS_LOCKED
		err = custOrderStatusDao.UpdateOne(&orderData.CustOrderStatus)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("更新客户订单状态失败, error:" + err.Error())
		}
	}
	_ = session.Commit()
	return nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/CustOrderService.ReleaseCustOrder
 *
 ******************************************************************************/
//func (impl *CustOrderServiceImplement) ReleaseCustOrder(session *xorm.Session, releaseQty int, custOrder *model.CustOrder) (*model.CustOrder, error) {
//	// 废弃
//	userId := "scheduler"
//	user := &global.User{
//		PlantNr: baseModel.PlantNr,
//		UserId:  userId,
//	}
//	serialOrderDao := omDal.NewSerialOrderDAO(session, baseModel.PlantNr, userId)
//	productFamilyRelateDao := meDal.NewProductFamilyRelateDAO(session, baseModel.PlantNr, userId)
//	serialOrderStatusHistoryDao := omDal.NewSerialOrderStatusRecLstDAO(session, baseModel.PlantNr, userId)
//	serialOrderStatusDao := omDal.NewSerialOrderStatusDAO(session, baseModel.PlantNr, userId)
//	workLineProcessDao := baseDal.NewWorkLineProcessLstDAO(session, baseModel.PlantNr, userId)
//	projectDao := meDal.NewProjectDAO(session, baseModel.PlantNr, userId)
//	operationDao := baseDal.NewOperationDAO(session, baseModel.PlantNr, userId)
//	PODao := omDal.NewSerialOrderPOLstDAO(session, baseModel.PlantNr, userId)
//	stepDao := omDal.NewSerialOrderStepLstDAO(session, baseModel.PlantNr, userId)
//	articleWithAttrDao := baseDal.NewArticleAtcodLstDAO(session, baseModel.PlantNr, userId)
//	scanRuleDao := baseDal.NewScanRuleInfoDAO(session, baseModel.PlantNr, userId)
//	guideDao := baseDal.NewGuideRuleInfoDAO(session, baseModel.PlantNr, userId)
//	bomHeadDao := meDal.NewBomHeadDAO(session, baseModel.PlantNr, userId)
//	labelTemplateDetailDao := baseDal.NewLabelTemplateDetailDAO(session, baseModel.PlantNr, userId)
//	printRuleDao := baseDal.NewPrintBasicRuleInfoDAO(session, baseModel.PlantNr, userId)
//	articleDao := baseDal.NewArticleDAO(session, baseModel.PlantNr, userId)
//	custOrderQtyDao := dal.NewCustOrderQtyDAO(session, baseModel.PlantNr, userId)
//	custOrderStatusDao := dal.NewCustOrderStatusDAO(session, baseModel.PlantNr, userId)
//	custOrderStatusHistoryDao := dal.NewCustOrderStatusHistoryDAO(session, baseModel.PlantNr, userId)
//	// 创建serialOrder service接口
//	serialOrderSvr := omSvr.NewSerialOrderService()
//	// 提出客户订单状态 和 客户订单数量
//	custOrderQty := &custOrder.OrderQty
//	custOrderStatus := &custOrder.OrderStatus
//	// 获取客户订单中车型配置关联的总成
//	productLi, err := productFamilyRelateDao.SelectProductByFamilyIdForCreateSerialOrder(custOrder.ProjectId, custOrder.ProductFamilyId)
//	if err != nil {
//		return nil, grmi.NewBusinessError("获取车型配置关联的产品失败, error:" + err.Error())
//	}
//	productQty := len(productLi)
//	// 组装通用工艺规则数据
//	// 获取项目数据 用于获取流水号
//	project, err := projectDao.SelectOne(custOrder.ProjectId)
//	if err != nil {
//		return nil, grmi.NewBusinessError("获取项目数据失败, error:" + err.Error())
//	}
//	if project == nil {
//		return nil, grmi.NewBusinessError("不存在该项目数据, 项目ID: " + custOrder.ProjectId)
//	}
//	// 获取所有的标签打印模板 并组建MAP
//	labelTemplateLi, err := labelTemplateDetailDao.SelectAllTemplate()
//	if err != nil {
//		return nil, grmi.NewBusinessError("查询标签模板失败,error:" + err.Error())
//	}
//	labelTemplateMap := make(map[string]*baseModel.LabelTemplateHead)
//	for _, template := range labelTemplateLi {
//		labelTemplateMap[template.LabelTemplateId] = &template
//	}
//	productArtQtyMap := make(map[string]map[string]int)
//	productArtItemMap := make(map[string][]string)
//	productArticleMap := make(map[string]*baseModel.Article)
//	// 组装BOM切片 获取关联的所有零件ID
//	for _, product := range productLi {
//		article, err := articleDao.SelectOne(product.ProductId, product.ProjectId)
//		if err != nil {
//			return nil, grmi.NewBusinessError("查询工单总成失败, error:" + err.Error())
//		}
//		if article == nil {
//			return nil, grmi.NewBusinessError("工单总成不存在, 总成ID:" + product.ProductId)
//		}
//		productArticleMap[product.ProductId] = article
//		bomHead, err := bomHeadDao.SelectOne(product.ProductId)
//		if err != nil {
//			return nil, grmi.NewBusinessError("查询物料BOM失败, error:" + err.Error())
//		}
//		if bomHead == nil {
//			_ = session.Rollback()
//			return nil, grmi.NewBusinessError("不存在对应的物料BOM, 物料ID:" + product.ProductId)
//		}
//		var Me meModel.BomLst
//		Me.PlantNr = baseModel.PlantNr
//		Me.BomId = bomHead.BomId
//		bomList, err := Me.SetMenu(bomHead.MatNr)
//		if err != nil {
//			return nil, grmi.NewBusinessError("获取BOM细则失败, error:" + err.Error())
//		}
//		if len(bomList) == 0 {
//			return nil, grmi.NewBusinessError("未获取到BOM细则, 物料ID:" + bomHead.BomId)
//		}
//		bomHead.BomLstLi = bomList
//		// 获取关联的所有零件ID
//		artMap := serialOrderSvr.ExtractArtId(bomHead)
//		artIdLi := make([]string, 0, len(artMap))
//		for innerArtId := range artMap {
//			artIdLi = append(artIdLi, innerArtId)
//		}
//		productArtQtyMap[product.ProductId] = artMap
//		productArtItemMap[product.ProductId] = artIdLi
//	}
//	// 获取所有的扫码校验规则 组建MAP数据结构
//	scanRuleLi, err := scanRuleDao.Select([]grmi.Predicate{baseMeta.ScanRuleInfo_ProjectId.NewPredicate(grmi.Equal, custOrder.ProjectId)}, nil)
//	if err != nil {
//		return nil, grmi.NewBusinessError("查询扫码校验条码失败, error:" + err.Error())
//	}
//	scanRuleMap := make(map[int]baseModel.ScanRuleInfo)
//	for _, scanRule := range scanRuleLi {
//		scanRuleMap[scanRule.OperationId] = scanRule
//	}
//	// 获取所有指导操作的规则 组建MAP数据结构
//	guideRuleLi, err := guideDao.Select([]grmi.Predicate{baseMeta.GuideRuleInfo_ProjectId.NewPredicate(grmi.Equal, custOrder.ProjectId)}, nil)
//	if err != nil {
//		return nil, grmi.NewBusinessError("查询指导操作规则失败, error:" + err.Error())
//	}
//	guideRuleMap := make(map[int]baseModel.GuideRuleInfo, len(guideRuleLi))
//	for _, guideRule := range guideRuleLi {
//		guideRuleMap[guideRule.OperationId] = guideRule
//	}
//	// 获取所有物料属性关联关系
//	attributeLi, err := articleWithAttrDao.SelectAllWithAttrValue()
//	if err != nil {
//		return nil, grmi.NewBusinessError("查询零件属性失败,error:" + err.Error())
//	}
//	attributeMap := make(map[int][]baseModel.ArticleWithAttrValue)
//	for _, data := range attributeLi {
//		_, exist := attributeMap[data.ArticleAtcodLst.AttrCode]
//		if !exist {
//			attributeMap[data.ArticleAtcodLst.AttrCode] = make([]baseModel.ArticleWithAttrValue, 0)
//		}
//		attributeMap[data.ArticleAtcodLst.AttrCode] = append(attributeMap[data.ArticleAtcodLst.AttrCode], data)
//	}
//	allocateMap := make(map[string][]baseModel.ArtQtyAllocate)
//	checkRuleMap := make(map[string]baseModel.ArtCheckRule)
//	opcBasicMap := make(map[int][]baseModel.OPCBasicComInfo)
//	twMap := make(map[int][]baseModel.TightenWrenchInfo)
//	// 进行派工
//	// 1. 获取需要派工的台套SyncKey
//	// 2. 通过SyncKey查询serialOrder 通过custOrderId和状态过滤serialOrder然后比对数量
//	// 3. 进行serialOrder状态变更和历史保存
//	// 4. 生成工艺数据
//	for i := 1; i <= releaseQty; i++ {
//		currentRelease := custOrderQty.ReleasedQty + i
//		syncKey := custOrder.CustOrderId + "-" + strconv.Itoa(currentRelease)
//		serialOrderLi, err := serialOrderDao.SelectBySyncKey(custOrder.CustOrderId, syncKey)
//		if err != nil {
//			return nil, grmi.NewBusinessError("通过台套Key查询序列订单失败, error:" + err.Error())
//		}
//		if len(serialOrderLi) != productQty {
//			return nil, grmi.NewBusinessError("通过台套Key获取到的序列订单数量和车型配置关联需生产的产品数量不一致, 序列订单数量:" + strconv.Itoa(len(serialOrderLi)))
//		}
//		for _, serialOrder := range serialOrderLi {
//			serialOrderHistory := omModel.SerialOrderStatusRecLst{
//				SerialOrderId: serialOrder.SerialOrderId,
//				PrevStatus:    serialOrder.SerialOrderStatus.Status,
//				Status:        baseModel.WO_STATUS_RELEASED,
//			}
//			err = serialOrderStatusHistoryDao.InsertOne(&serialOrderHistory)
//			if err != nil {
//				return nil, grmi.NewBusinessError("写入序列工单状态变更历史失败, error:" + err.Error())
//			}
//			serialOrder.SerialOrderStatus.Status = baseModel.WO_STATUS_RELEASED
//			err = serialOrderStatusDao.UpdateOne(&serialOrder.SerialOrderStatus)
//			if err != nil {
//				return nil, grmi.NewBusinessError("更新序列工单状态失败, error:" + err.Error())
//			}
//			artMap := productArtQtyMap[serialOrder.ArtId]
//			// 生成序列工单对应的工艺数据
//			usedPoLi, err := workLineProcessDao.SelectProcessByWorkLine(serialOrder.PlanResourceId)
//			if err != nil {
//				return nil, grmi.NewBusinessError("获取产线关联的工序失败, error:" + err.Error())
//			}
//			if len(usedPoLi) == 0 {
//				return nil, grmi.NewBusinessError("该产线未关联工序, 产线ID:" + serialOrder.PlanResourceId)
//			}
//			poIdLi := make([]string, 0, len(usedPoLi))
//			poIdLiInterface := make([]interface{}, 0, len(usedPoLi))
//			for _, poData := range usedPoLi {
//				poIdLi = append(poIdLi, poData.PO)
//				poIdLiInterface = append(poIdLiInterface, poData.PO)
//			}
//			artIdLi := productArtItemMap[serialOrder.ArtId]
//			opLi, err := operationDao.GetMeOperation(artIdLi, serialOrder.ProjectId, poIdLi, serialOrder.PlanResourceId)
//			if err != nil {
//				return nil, grmi.NewBusinessError("获取工艺操作失败,error:" + err.Error())
//			}
//			if len(opLi) == 0 {
//				return nil, grmi.NewBusinessError("未获取到工艺数据")
//			}
//			// 获取所有使用工序扫码校验规则 组建MAP数据结构
//			printRuleLi, err := printRuleDao.Select([]grmi.Predicate{baseMeta.PrintBasicRuleInfo_ProjectId.NewPredicate(grmi.Equal, custOrder.ProjectId), baseMeta.PrintBasicRuleInfo_PO.NewPredicate(grmi.Include, poIdLiInterface...)}, []grmi.Field{baseMeta.PrintBasicRuleInfo_OperationId})
//			printRuleMap := make(map[int][]baseModel.PrintBasicRuleInfo)
//			for _, data := range printRuleLi {
//				_, exist := printRuleMap[data.OperationId]
//				if !exist {
//					printRuleMap[data.OperationId] = make([]baseModel.PrintBasicRuleInfo, 0)
//				}
//				printRuleMap[data.OperationId] = append(printRuleMap[data.OperationId], data)
//			}
//
//			var PO string
//			processPos := 1
//			opPos := 1
//			for _, op := range opLi {
//				// 生成工序操作状态表
//				if PO != op.Process.PO {
//					PO = op.Process.PO
//					serialOrderWorkPlace := omModel.SerialOrderPOLst{
//						SerialOrderId: serialOrder.SerialOrderId,
//						PO:            PO,
//						Status:        baseModel.WO_STATUS_RELEASED,
//						HasDependOn:   op.Process.HasDependOn,
//					}
//					err = PODao.InsertOne(&serialOrderWorkPlace)
//					if err != nil {
//						return nil, grmi.NewBusinessError("插入serialOrder工序数据失败,error:" + err.Error())
//					}
//					processPos++
//				}
//				serialOrderStep := omModel.SerialOrderStepLst{
//					PO:            op.Process.PO,
//					OperationId:   op.OperationId,
//					SerialOrderId: serialOrder.SerialOrderId,
//					StepNo:        op.Operation.StepNo,
//					Pos:           opPos,
//					SubArtId:      op.ArticleAtcodLst.ArtId,
//					StepDesc:      op.Operation.StepDesc,
//					AttrCode:      op.ArticleAtcodLst.AttrCode,
//					AttrValue:     op.ArticleAtcodLst.AttrValue,
//					StepType:      op.Operation.StepType,
//					Status:        baseModel.WO_STATUS_RELEASED,
//				}
//				opPos++
//				err = stepDao.InsertOne(&serialOrderStep)
//				if err != nil {
//					return nil, grmi.NewBusinessError("插入序列工单工艺数据失败, error:" + err.Error())
//				}
//				if serialOrderStep.StepType == baseModel.STEP_CHECK_RULE { // 生成扫码校验的工艺数据
//					scanRule, exist := scanRuleMap[serialOrderStep.OperationId]
//					if !exist {
//						return nil, grmi.NewBusinessError("未获取到扫描校验详细规则, 工艺ID:" + strconv.Itoa(serialOrderStep.OperationId))
//					}
//
//					checkRuleMapPointer, allocateMapPointer, err := serialOrderSvr.ScanCodeCheck(user, session, checkRuleMap, allocateMap, artMap, &scanRule, &op, &serialOrderStep, op.Operation.ActivateInBKStation)
//					if err != nil {
//						return nil, err
//					}
//					checkRuleMap = *checkRuleMapPointer
//					allocateMap = *allocateMapPointer
//				} else if serialOrderStep.StepType == baseModel.STEP_OPC_RULE { // 生成OPC通讯的工艺数据
//					opcBasicMapPointer, err := serialOrderSvr.OPCCommunication(user, session, opcBasicMap, &serialOrderStep, attributeMap, artMap, op.Operation.ActivateInBKStation)
//					if err != nil {
//						return nil, err
//					}
//					opcBasicMap = *opcBasicMapPointer
//				} else if serialOrderStep.StepType == baseModel.STEP_TW_RULE { // 生成开发协议的工艺数据
//					twMapPointer, err := serialOrderSvr.TightenWrenchInfo(user, session, twMap, &serialOrderStep, op.Operation.ActivateInBKStation, productArticleMap[serialOrder.ArtId])
//					if err != nil {
//						return nil, err
//					}
//					twMap = *twMapPointer
//				} else if serialOrderStep.StepType == baseModel.STEP_GUIDE_RULE {
//					guideRule, exist := guideRuleMap[serialOrderStep.OperationId]
//					if !exist {
//						return nil, grmi.NewBusinessError("未获取到指导操作的详细规则")
//					}
//					err = serialOrderSvr.GuideRuleInfo(user, session, &guideRule, &serialOrderStep, op.Operation.ActivateInBKStation)
//					if err != nil {
//						return nil, err
//					}
//				} else if serialOrderStep.StepType == baseModel.STEP_PRINT_RULE {
//					ruleLi, exist := printRuleMap[serialOrderStep.OperationId]
//					if !exist {
//						return nil, grmi.NewBusinessError("未获取到打印规则")
//					}
//					generateRuleLi := make([]baseModel.PrintBasicRuleInfo, 0)
//					for _, rule := range ruleLi {
//						if rule.Action == baseModel.PRINT_RULE_ACTION_UPDATE {
//							generateRuleLi = append(generateRuleLi, rule)
//						}
//					}
//					if len(generateRuleLi) > 1 {
//						return nil, grmi.NewBusinessError("改工步匹配到超过1条生成打印标识的打印规则")
//					}
//					var generateRule *baseModel.PrintBasicRuleInfo
//					var printTemplate *baseModel.LabelTemplateHead
//					if len(generateRuleLi) == 1 {
//						generateRule = &generateRuleLi[0]
//						printTemplate, exist = labelTemplateMap[generateRule.TemplateId]
//						if !exist {
//							return nil, grmi.NewBusinessError("存在单据打印规则中配置的标签模板, 模板ID:" + generateRule.TemplateId)
//						}
//					}
//					article := productArticleMap[serialOrder.ArtId]
//					err = serialOrderSvr.PrintRuleInfo(user, session, &serialOrderStep, generateRule, printTemplate, article, op.Operation.ActivateInBKStation)
//					if err != nil {
//						return nil, err
//					}
//				} else {
//					return nil, grmi.NewBusinessError("获取到的工艺数据系统暂不支持该操作类型:" + serialOrderStep.StepType)
//				}
//			}
//		}
//	}
//	custOrderQty.ReleasedQty += releaseQty
//	err = custOrderQtyDao.UpdateOne(custOrderQty)
//	if err != nil {
//		return nil, grmi.NewBusinessError("更新客户订单数量数据失败, error:" + err.Error())
//	}
//	if custOrderStatus.Status == baseModel.WO_STATUS_LOCKED {
//		//maxPos, err := custOrderStatusHistoryDao.GetMaxPos(custOrder.CustOrderId)
//		//if err != nil {
//		//	return nil, grmi.NewBusinessError("获取客户订单状态变更位置数据失败, error:" + err.Error())
//		//}
//		statusHistory := model.CustOrderStatusHistory{
//			CustOrderId: custOrder.CustOrderId,
//			//Pos: maxPos+1,
//			StatusChangeType: model.STATUS__CHANGE_TYPE_SCHUDLER,
//			FromStatus:       baseModel.WO_STATUS_LOCKED,
//			ToStatus:         baseModel.WO_STATUS_RELEASED,
//			ChangeTime:       grmi.DateTime(time.Now()),
//		}
//		err = custOrderStatusHistoryDao.InsertOne(&statusHistory)
//		if err != nil {
//			return nil, grmi.NewBusinessError("保存客户订单状态变更历史失败, error:" + err.Error())
//		}
//		custOrderStatus.Status = baseModel.WO_STATUS_RELEASED
//		err = custOrderStatusDao.UpdateOne(custOrderStatus)
//		if err != nil {
//			return nil, grmi.NewBusinessError("更新客户订单状态失败, error:" + err.Error())
//		}
//	}
//	return custOrder, nil
//}

// ReportWort 处理MES的报工数据
func (impl *CustOrderServiceImplement) ReportWort(user *global.User) {
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	log, _ := logger.NewLogger("Schuler", "ReportWork")
	uid, err := uuid.NewV1()
	if err != nil {
		return
	}
	reportId := uid.String()
	log.Info("报工同步开始, 报工任务ID:" + reportId)
	// 从serialOrder状态变更表中获取MES操作完成的serialOrder
	serialOrderStatusRecDao := omDal.NewSerialOrderStatusRecLstDAO(session, user.PlantNr, user.UserId)
	serialOrderDao := omDal.NewSerialOrderDAO(session, user.PlantNr, user.UserId)
	event, err := serialOrderStatusRecDao.SelectClosedEvent()
	if err != nil {
		log.Error("报工同步阶段, 查询报工事件失败, 错误:" + err.Error() + ", 报工任务ID:" + reportId)
		return
	}
	if event == nil {
		log.Info("报工完成, 未获取到新的报工事件, 报工任务ID:" + reportId)
		return
	}
	log.Info("报工同步阶段, 处理工单ID:" + event.SerialOrder.SerialOrderId + ", 报工任务ID:" + reportId)
	// 查询serialOrder关联的客户订单
	custOrderDao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	custOrderStatusDao := dal.NewCustOrderStatusDAO(session, user.PlantNr, user.UserId)
	custOrderStatusHistoryDao := dal.NewCustOrderStatusHistoryDAO(session, user.PlantNr, user.UserId)
	custOrder, err := custOrderDao.SelectOne(event.SerialOrder.CustOrderId)
	if err != nil {
		log.Error("报工同步阶段, 查询关联的客户订单失败, 错误:" + err.Error() + ", 报工任务ID:" + reportId)
		return
	}
	if custOrder == nil {
		log.Error("报工同步阶段, 查询关联的客户订单不存在, 客户订单ID:" + event.SerialOrder.CustOrderId + ", 报工任务ID:" + reportId)
		return
	}
	if custOrder.OrderStatus.Status >= baseModel.WO_STATUS_FINISHED {
		log.Error("报工同步阶段, 关联的客户订单已完成, 客户订单ID:" + event.SerialOrder.CustOrderId + ", 报工任务ID:" + reportId)
		return
	}
	// 开启事务 开始处理客户订单数量
	if err = session.Begin(); err != nil {
		log.Error("报工同步阶段, 开启事务失败, 错误:" + err.Error() + ", 报工任务ID:" + reportId)
		return
	}
	event.SerialOrderStatusRecLst.OutputStatus = omModel.ORDER_DEALED
	err = serialOrderStatusRecDao.UpdateOne(&event.SerialOrderStatusRecLst)
	if err != nil {
		_ = session.Rollback()
		log.Error("报工同步阶段, 更新工单状态变更记录处理状态失败, 错误:" + err.Error() + ", 报工任务ID:" + reportId)
		return
	}
	//serialOrder := event.SerialOrder
	serialOrderLi, err := serialOrderDao.Select([]grmi.Predicate{omMeta.SerialOrder_SyncKey.NewPredicate(grmi.Equal, event.SerialOrder.SyncKey)}, nil)
	var carComplete = true
	var completeQty int
	for _, serialOrder := range serialOrderLi {
		if serialOrder.SerialOrderStatus.Status < baseModel.WO_STATUS_FINISHED {
			carComplete = false
		} else if serialOrder.SerialOrderStatus.Status == baseModel.WO_STATUS_FINISHED {
			completeQty += 1
		}
	}
	// 客户订单下的工单数量+1
	custOrder.OrderQty.SerialOrderActQty += 1
	// 如果客户订单下的同一台套工单都完成 ActQty +1
	if carComplete {
		custOrder.OrderQty.ActQty += 1
	}
	// 如果客户订单下的同一台套只完成一个 说明该工单是这个台套的第一个完成的工单 RunningQty+1
	if completeQty == 1 {
		custOrder.OrderQty.RunningQty += 1
	}
	// 关单
	if custOrder.OrderQty.ActQty == custOrder.OrderQty.PlanQty {
		custOrderStatsusHistory := model.CustOrderStatusHistory{
			CustOrderId:      custOrder.CustOrderId,
			StatusChangeType: model.STATUS_CHANGE_TYPE_REPORT,
			FromStatus:       custOrder.OrderStatus.Status,
			ToStatus:         baseModel.WO_STATUS_FINISHED,
			ChangeTime:       grmi.DateTime(time.Now()),
		}
		err = custOrderStatusHistoryDao.InsertOne(&custOrderStatsusHistory)
		if err != nil {
			_ = session.Rollback()
			log.Error("报工同步阶段, 插入客户订单状态变更记录失败, 错误:" + err.Error() + ", 报工任务ID:" + reportId)
			return
		}
		custOrder.OrderStatus.Status = baseModel.WO_STATUS_FINISHED
		err = custOrderStatusDao.UpdateOne(&custOrder.OrderStatus)
		if err != nil {
			_ = session.Rollback()
			log.Error("报工同步阶段, 更新客户订单状态失败, 错误:" + err.Error() + ", 报工任务ID:" + reportId)
			return
		}
		custOrder.ActEndTime = event.SerialOrderStatusRecLst.CreateTime
		err = custOrderDao.UpdateOne(custOrder)
		if err != nil {
			_ = session.Rollback()
			log.Error("报工同步阶段, 更新客户订单关闭时间失败, 错误:" + err.Error() + ", 报工任务ID:" + reportId)
		}
		log.Info("报工同步阶段, 客户订单关闭， 处理客户订单ID:" + custOrder.CustOrderId + ", 处理工单ID:" + event.SerialOrder.SerialOrderId + ", 报工任务ID:" + reportId)
		_ = session.Commit()
		return
	}
	if custOrder.OrderStatus.Status == baseModel.WO_STATUS_RELEASED {
		custOrderStatsusHistory := model.CustOrderStatusHistory{
			CustOrderId:      custOrder.CustOrderId,
			StatusChangeType: model.STATUS_CHANGE_TYPE_REPORT,
			FromStatus:       custOrder.OrderStatus.Status,
			ToStatus:         baseModel.WO_STATUS_RUNNING,
			ChangeTime:       grmi.DateTime(time.Now()),
		}
		err = custOrderStatusHistoryDao.InsertOne(&custOrderStatsusHistory)
		if err != nil {
			_ = session.Rollback()
			log.Error("报工同步阶段, 插入客户订单状态变更记录失败, 错误:" + err.Error() + ", 报工任务ID:" + reportId)
			return
		}
		custOrder.OrderStatus.Status = baseModel.WO_STATUS_RUNNING
		err = custOrderStatusDao.UpdateOne(&custOrder.OrderStatus)
		if err != nil {
			_ = session.Rollback()
			log.Error("报工同步阶段, 更新客户订单状态失败, 错误:" + err.Error() + ", 报工任务ID:" + reportId)
			return
		}
		custOrder.ActStartTime = event.SerialOrderStatusRecLst.CreateTime
		err = custOrderDao.UpdateOne(custOrder)
		if err != nil {
			_ = session.Rollback()
			log.Error("报工同步阶段, 更新客户订单开始时间失败, 错误:" + err.Error() + ", 报工任务ID:" + reportId)
		}
		log.Info("报工同步阶段, 客户订单已置为运行中， 处理客户订单ID:" + custOrder.CustOrderId + ", 处理工单ID:" + event.SerialOrder.SerialOrderId + ", 报工任务ID:" + reportId)
		_ = session.Commit()
		return
	}
	log.Info("报工同步阶段, 客户订单已经在运行中， 处理客户订单ID:" + custOrder.CustOrderId + ", 处理工单ID:" + event.SerialOrder.SerialOrderId + ", 报工任务ID:" + reportId)
	_ = session.Commit()
	return
}

// CancelCustOrderQty 取消客户订单数量
func (impl *CustOrderServiceImplement) CancelCustOrderQty(user *global.User, custOrderId string, cancelQty int) error {
	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "CancelCustOrderQty", "取消客户订单数量")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	custOrderDao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	custOrderQtyDao := dal.NewCustOrderQtyDAO(session, user.PlantNr, user.UserId)
	custOrderStatusDao := dal.NewCustOrderStatusDAO(session, user.PlantNr, user.UserId)
	custOrderStatusHistoryDao := dal.NewCustOrderStatusHistoryDAO(session, user.PlantNr, user.UserId)
	serialOrderDao := omDal.NewSerialOrderDAO(session, user.PlantNr, user.UserId)
	serialOrderStatusDao := omDal.NewSerialOrderStatusDAO(session, user.PlantNr, user.UserId)
	serialOrderStatusRecDao := omDal.NewSerialOrderStatusRecLstDAO(session, user.PlantNr, user.UserId)
	productFamilyRelateDao := meDal.NewProductFamilyRelateDAO(session, user.PlantNr, user.UserId)
	serialOrderPoDao := omDal.NewSerialOrderPOLstDAO(session, user.PlantNr, user.UserId)
	serialOrderStepDao := omDal.NewSerialOrderStepLstDAO(session, user.PlantNr, user.UserId)
	serialOrderOPDetailDao := omDal.NewSerialOrderOPDetailDAO(session, user.PlantNr, user.UserId)
	// 校验客户订单数据及状态
	custOrder, err := custOrderDao.SelectOne(custOrderId)
	if err != nil {
		return grmi.NewBusinessError("查询客户订单失败, error:" + err.Error())
	}
	if custOrder == nil {
		return grmi.NewBusinessError("客户订单不存在, 客户订单ID:" + custOrderId)
	}
	if custOrder.OrderStatus.Status <= baseModel.WO_STATUS_PLANNED || custOrder.OrderStatus.Status >= baseModel.WO_STATUS_FINISHED {
		return grmi.NewBusinessError("当前客户订单的状态不允许取消数量")
	}
	if custOrder.OrderQty.PlanQty-custOrder.OrderQty.RunningQty-custOrder.OrderQty.CancelQty < cancelQty {
		return grmi.NewBusinessError("取消数量已经大于客户订单允许取消的数量")
	}
	//originCancelQty := custOrder.OrderQty.CancelQty
	productLi, err := productFamilyRelateDao.SelectProductByFamilyIdForCreateSerialOrder(custOrder.ProjectId, custOrder.ProductFamilyId)
	if err != nil {
		return grmi.NewBusinessError("查询派生下的总成失败, error:" + err.Error())
	}
	productNum := len(productLi)
	serialOrderDataLi, err := serialOrderDao.SelectUnOnGoingSerialOrder(custOrderId)
	if err != nil {
		return grmi.NewBusinessError("查询工单数据失败, error:" + err.Error())
	}
	syncKeyMap := make(map[string][]omModel.VOmSerialorder)
	syncKeyLi := make([]string, 0)
	for _, serialOrderData := range serialOrderDataLi {
		_, exist := syncKeyMap[serialOrderData.SerialOrder.SyncKey]
		if !exist {
			syncKeyLi = append(syncKeyLi, serialOrderData.SerialOrder.SyncKey)
			syncKeyMap[serialOrderData.SerialOrder.SyncKey] = make([]omModel.VOmSerialorder, 0)
		}
		syncKeyMap[serialOrderData.SerialOrder.SyncKey] = append(syncKeyMap[serialOrderData.SerialOrder.SyncKey], serialOrderData)
	}
	var count int
	splitSyncKeyLi := make([]string, 0)
	for _, syncKey := range syncKeyLi {
		if len(syncKeyMap[syncKey]) == productNum {
			splitSyncKeyLi = append(splitSyncKeyLi, syncKey)
			count++
		}
	}
	if count < cancelQty {
		return grmi.NewBusinessError("当前客户订单可取消数量小于需要取消数量")
	}

	if err = session.Begin(); err != nil {
		return grmi.NewBusinessError("开启事务失败, error:" + err.Error())
	}
	impl.QuickSort(splitSyncKeyLi)
	for i := 0; i < cancelQty; i++ {
		cancelSyncKey := splitSyncKeyLi[i]
		orderDataLi, err := serialOrderDao.Select([]grmi.Predicate{omMeta.SerialOrder_SyncKey.NewPredicate(grmi.Equal, cancelSyncKey)}, nil)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("查询工单数据失败, error:" + err.Error())
		}
		for _, serialOrderData := range orderDataLi {
			serialOrderStatus := serialOrderData.SerialOrderStatus
			statusRec := omModel.SerialOrderStatusRecLst{
				SerialOrderId: serialOrderData.SerialOrderId,
				PrevStatus:    serialOrderStatus.Status,
				Status:        baseModel.WO_STATUS_CANCELED,
				Remark1:       "SPLIT",
			}
			err = serialOrderStatusRecDao.InsertOne(&statusRec)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("写入工单状态变更记录失败, error:" + err.Error())
			}
			serialOrderStatus.Status = baseModel.WO_STATUS_CANCELED
			err = serialOrderStatusDao.UpdateOneWithStatus(&serialOrderStatus, baseModel.WO_STATUS_RELEASED)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("更新工单状态失败, error:" + err.Error())
			}
			poUpdateData := omModel.SerialOrderPOLst{
				Status: baseModel.WO_STATUS_CANCELED,
			}
			err = serialOrderPoDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderPOLst_SerialOrderId.NewPredicate(grmi.Equal, serialOrderData.SerialOrderId)}, &poUpdateData, []string{omMeta.SerialOrderPOLst_Status.Name}...)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("更新工单工序状态失败, error:" + err.Error())
			}
			stepUpdateData := omModel.SerialOrderStepLst{
				Status: baseModel.WO_STATUS_CANCELED,
			}
			err = serialOrderStepDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderStepLst_SerialOrderId.NewPredicate(grmi.Equal, serialOrderData.SerialOrderId)}, &stepUpdateData, []string{omMeta.SerialOrderStepLst_Status.Name}...)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("更新工单工步状态失败, error:" + err.Error())
			}
			opDetailUpdateData := omModel.SerialOrderOPDetail{
				Status: baseModel.WO_STATUS_CANCELED,
			}
			err = serialOrderOPDetailDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderOPDetail_SerialOrderId.NewPredicate(grmi.Equal, serialOrderData.SerialOrderId)}, &opDetailUpdateData, []string{omMeta.SerialOrderOPDetail_Status.Name}...)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("更新工单详细操作状态失败, error:" + err.Error())
			}
			// 对拆分的预装工单做取消处理
			preSerialOrderLi, err := serialOrderDao.Select([]grmi.Predicate{
				omMeta.SerialOrder_OrderType.NewPredicate(grmi.Equal, baseModel.ORDER_TYPE_PRE),
				omMeta.SerialOrder_GenerateFlag.NewPredicate(grmi.Equal, 0),
				omMeta.SerialOrder_MainOrderId.NewPredicate(grmi.Equal, serialOrderData.SerialOrderId),
			}, nil)
			if err != nil {
				return grmi.NewBusinessError("查询工单下的预装工单失败, 错误：" + err.Error())
			}
			for _, preOrder := range preSerialOrderLi {
				if preOrder.SerialOrderStatus.Status > baseModel.WO_STATUS_RELEASED {
					return grmi.NewBusinessError("预装工单已经不允许取消, 工单ID:" + preOrder.SerialOrderId)
				}
				originStatus := preOrder.SerialOrderStatus.Status
				statusRec = omModel.SerialOrderStatusRecLst{
					SerialOrderId: preOrder.SerialOrderId,
					Status:        baseModel.WO_STATUS_CANCELED,
					PrevStatus:    preOrder.SerialOrderStatus.Status,
				}
				preOrder.SerialOrderStatus.Status = baseModel.WO_STATUS_CANCELED
				err = serialOrderStatusRecDao.InsertOne(&statusRec)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("插入预装工单状态变更记录失败, error:" + err.Error())
				}
				err = serialOrderStatusDao.UpdateOneWithStatus(&preOrder.SerialOrderStatus, baseModel.WO_STATUS_RELEASED)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("更新预装工单状态失败， error:" + err.Error())
				}
				if originStatus == baseModel.WO_STATUS_RELEASED {
					poUpdateData := &omModel.SerialOrderPOLst{
						Status: baseModel.WO_STATUS_CANCELED,
					}
					err = serialOrderPoDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderPOLst_SerialOrderId.NewPredicate(grmi.Equal, preOrder.SerialOrderId)}, poUpdateData, omMeta.SerialOrderPOLst_Status.Name)
					if err != nil {
						_ = session.Rollback()
						return grmi.NewBusinessError("更新预装工单工序状态失败, error:" + err.Error())
					}
					stepUpdateData := &omModel.SerialOrderStepLst{
						Status: baseModel.WO_STATUS_CANCELED,
					}
					err = serialOrderStepDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderStepLst_SerialOrderId.NewPredicate(grmi.Equal, preOrder.SerialOrderId)}, stepUpdateData, omMeta.SerialOrderStepLst_Status.Name)
					if err != nil {
						_ = session.Rollback()
						return grmi.NewBusinessError("更新预装工单工步状态失败, error:" + err.Error())
					}
					opDetailUpdateData := &omModel.SerialOrderOPDetail{
						Status: baseModel.WO_STATUS_CANCELED,
					}
					err = serialOrderOPDetailDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderOPDetail_SerialOrderId.NewPredicate(grmi.Equal, preOrder.SerialOrderId)}, opDetailUpdateData, omMeta.SerialOrderOPDetail_Status.Name)
					if err != nil {
						_ = session.Rollback()
						return grmi.NewBusinessError("更新预装工单详细操作状态失败, error:" + err.Error())
					}
				}
			}
		}
	}
	// 处理客户订单数量数据
	custOrder.OrderQty.CancelQty += cancelQty
	err = custOrderQtyDao.UpdateOne(&custOrder.OrderQty)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("更新客户订单数量数据失败, error:" + err.Error())
	}
	// 通过数量判断是否需要处理客户订单状态
	if custOrder.OrderQty.CancelQty+custOrder.OrderQty.ActQty == custOrder.OrderQty.PlanQty {
		if custOrder.OrderQty.CancelQty == custOrder.OrderQty.PlanQty {
			custOrderHistory := model.CustOrderStatusHistory{
				CustOrderId:      custOrderId,
				StatusChangeType: model.STATUS_CHANGE_TYPE_OPERATION,
				FromStatus:       custOrder.OrderStatus.Status,
				ToStatus:         baseModel.ORDER_STATUS_CANCELED,
				ChangeTime:       grmi.DateTime(time.Now()),
			}
			err = custOrderStatusHistoryDao.InsertOne(&custOrderHistory)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("插入客户订单状态变更历史失败, error:" + err.Error())
			}
			custOrder.OrderStatus.Status = baseModel.ORDER_STATUS_CANCELED
			err = custOrderStatusDao.UpdateOne(&custOrder.OrderStatus)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("更新客户订单状态失败, error:" + err.Error())
			}
		} else {
			custOrderHistory := model.CustOrderStatusHistory{
				CustOrderId:      custOrderId,
				StatusChangeType: model.STATUS_CHANGE_TYPE_OPERATION,
				FromStatus:       custOrder.OrderStatus.Status,
				ToStatus:         baseModel.ORDER_STATUS_CLOSED,
				ChangeTime:       grmi.DateTime(time.Now()),
			}
			err = custOrderStatusHistoryDao.InsertOne(&custOrderHistory)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("插入客户订单状态变更历史失败, error:" + err.Error())
			}
			custOrder.OrderStatus.Status = baseModel.ORDER_STATUS_CLOSED
			err = custOrderStatusDao.UpdateOne(&custOrder.OrderStatus)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("更新客户订单状态失败, error:" + err.Error())
			}
		}
	}
	//// 生成需要取消的台套Key
	//cancelSyncKeyLi := make([]string, 0, cancelQty)
	//for i := 0; i < cancelQty; i++ {
	//	cancelKey := custOrder.OrderQty.PlanQty - originCancelQty - i - 1
	//	syncKey := custOrder.CustOrderId + "-" + strconv.Itoa(cancelKey)
	//	cancelSyncKeyLi = append(cancelSyncKeyLi, syncKey)
	//}
	//// 查询台套Key下的序列工单
	//serialOrderIdLi, err := serialOrderDao.SelectSerialOrderIdBySyncKey(cancelSyncKeyLi)
	//if err != nil {
	//	_ = session.Rollback()
	//	return grmi.NewBusinessError("通过台套Key查询序列工单数据失败, error:" + err.Error())
	//}
	//// 校验序列工单的状态是否都是40一下
	//statusLi, err := serialOrderStatusDao.SelectSerialOrderStatusBySerialOrderId(serialOrderIdLi)
	//if err != nil {
	//	_ = session.Rollback()
	//	return grmi.NewBusinessError("查询工单状态失败, error:" + err.Error())
	//}
	//for _, status := range statusLi {
	//	if status > 40 {
	//		_ = session.Rollback()
	//		return grmi.NewBusinessError("待取消的序列工单状态存在40及以上")
	//	}
	//}
	//// 更新序列工单状态 同时写入状态变更记录
	//serialOrderStatusRecLi := make([]omModel.SerialOrderStatusRecLst, 0, 20)
	//for _, serialOrderId := range serialOrderIdLi {
	//	serialOrderStatusRec := omModel.SerialOrderStatusRecLst{
	//		SerialOrderId: serialOrderId,
	//		PrevStatus:    baseModel.WO_STATUS_RELEASED,
	//		Status:        baseModel.WO_STATUS_CANCELED,
	//	}
	//	serialOrderStatusRecLi = append(serialOrderStatusRecLi, serialOrderStatusRec)
	//	if len(serialOrderStatusRecLi) == 20 {
	//		err = serialOrderStatusRecDao.Insert(&serialOrderStatusRecLi)
	//		if err != nil {
	//			_ = session.Rollback()
	//			return grmi.NewBusinessError("插入工单状态变更记录失败, error:" + err.Error())
	//		}
	//		serialOrderStatusRecLi = make([]omModel.SerialOrderStatusRecLst, 0, 20)
	//	}
	//}
	//if len(serialOrderStatusRecLi) > 0 {
	//	err = serialOrderStatusRecDao.Insert(&serialOrderStatusRecLi)
	//	if err != nil {
	//		_ = session.Rollback()
	//		return grmi.NewBusinessError("插入工单状态变更记录失败, error:" + err.Error())
	//	}
	//}
	//statusUpdateData := omModel.SerialOrderStatus{
	//	Status: baseModel.WO_STATUS_CANCELED,
	//}
	//idLi := make([]interface{}, 0, len(serialOrderIdLi))
	//for _, serialOrderId := range serialOrderIdLi {
	//	idLi = append(idLi, serialOrderId)
	//}
	//err = serialOrderStatusDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderStatus_SerialOrderId.NewPredicate(grmi.Include, idLi...)}, &statusUpdateData, []string{omMeta.SerialOrderStatus_Status.Name}...)
	//if err != nil {
	//	_ = session.Rollback()
	//	return grmi.NewBusinessError("更新工单状态失败, error:" + err.Error())
	//}
	//poUpdateData := omModel.SerialOrderPOLst{
	//	Status: baseModel.WO_STATUS_CANCELED,
	//}
	//serialOrderPoDao := omDal.NewSerialOrderPOLstDAO(session, user.PlantNr, user.UserId)
	//err = serialOrderPoDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderPOLst_SerialOrderId.NewPredicate(grmi.Include, idLi...)}, &poUpdateData, []string{omMeta.SerialOrderPOLst_Status.Name}...)
	//if err != nil {
	//	_ = session.Rollback()
	//	return grmi.NewBusinessError("更新工单工序状态失败, error:" + err.Error())
	//}
	//serialOrderStepDao := omDal.NewSerialOrderStepLstDAO(session, user.PlantNr, user.UserId)
	//stepUpdateData := omModel.SerialOrderStepLst{
	//	Status: baseModel.WO_STATUS_CANCELED,
	//}
	//err = serialOrderStepDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderStepLst_SerialOrderId.NewPredicate(grmi.Include, idLi...)}, &stepUpdateData, []string{omMeta.SerialOrderStepLst_Status.Name}...)
	//if err != nil {
	//	_ = session.Rollback()
	//	return grmi.NewBusinessError("更新工单工步状态失败, error:" + err.Error())
	//}
	//serialOrderOPDetailDao := omDal.NewSerialOrderOPDetailDAO(session, user.PlantNr, user.UserId)
	//opDetailUpdateData := omModel.SerialOrderOPDetail{
	//	Status: baseModel.WO_STATUS_CANCELED,
	//}
	//err = serialOrderOPDetailDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderOPDetail_SerialOrderId.NewPredicate(grmi.Include, idLi...)}, &opDetailUpdateData, []string{omMeta.SerialOrderOPDetail_Status.Name}...)
	//if err != nil {
	//	_ = session.Rollback()
	//	return grmi.NewBusinessError("更新工单详细操作状态失败, error:" + err.Error())
	//}
	_ = session.Commit()
	return nil
}

// CancelCustOrder 取消客户订单
func (impl *CustOrderServiceImplement) CancelCustOrder(user *global.User, custOrderId string) error {
	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "CancelCustOrder", "取消客户订单")

	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)
	custOrderStatusHistoryDao := dal.NewCustOrderStatusHistoryDAO(session, user.PlantNr, user.UserId)
	// 校验客户订单数据及状态
	custOrder, err := custOrderDao.SelectOne(custOrderId)
	if err != nil {
		return grmi.NewBusinessError("查询客户订单失败, error:" + err.Error())
	}
	if custOrder == nil {
		return grmi.NewBusinessError("客户订单不存在, 客户订单ID:" + custOrderId)
	}
	if custOrder.OrderStatus.Status != baseModel.WO_STATUS_UNPLANNED {
		return grmi.NewBusinessError("当前客户订单状态不是未计划, 不允许取消")
	}
	if err = session.Begin(); err != nil {
		return grmi.NewBusinessError("开启事务失败, error:" + err.Error())
	}
	custOrder.OrderStatus.Status = baseModel.WO_STATUS_CANCELED
	err = custOrderStatusDao.UpdateOne(&custOrder.OrderStatus)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("更新客户订单状态失败, error:" + err.Error())
	}
	custOrderStatusHistory := model.CustOrderStatusHistory{
		CustOrderId:      custOrderId,
		StatusChangeType: model.STATUS_CHANGE_TYPE_OPERATION,
		FromStatus:       baseModel.WO_STATUS_UNPLANNED,
		ToStatus:         baseModel.WO_STATUS_CANCELED,
		ChangeTime:       grmi.DateTime(time.Now()),
	}
	err = custOrderStatusHistoryDao.InsertOne(&custOrderStatusHistory)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("插入客户订单状态变更历史失败, error:" + err.Error())
	}
	_ = session.Commit()
	return nil
}

// WithdrawCustOrder 回撤已计划的客户订单
func (impl *CustOrderServiceImplement) WithdrawCustOrder(user *global.User, custOrderId string) error {
	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "WithdrawCustOrder", "回撤已计划的客户订单")
	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)
	custOrderStatusHistoryDao := dal.NewCustOrderStatusHistoryDAO(session, user.PlantNr, user.UserId)
	// 校验客户订单数据及状态
	custOrder, err := custOrderDao.SelectOne(custOrderId)
	if err != nil {
		return grmi.NewBusinessError("查询客户订单失败, error:" + err.Error())
	}
	if custOrder == nil {
		return grmi.NewBusinessError("客户订单不存在, 客户订单ID:" + custOrderId)
	}
	if custOrder.OrderStatus.Status != baseModel.WO_STATUS_PLANNED {
		return grmi.NewBusinessError("当前客户订单状态不是已计划, 不允许回撤")
	}
	if err = session.Begin(); err != nil {
		return grmi.NewBusinessError("开启事务失败, error:" + err.Error())
	}
	custOrder.OrderStatus.Status = baseModel.WO_STATUS_UNPLANNED
	err = custOrderStatusDao.UpdateOne(&custOrder.OrderStatus)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("更新客户订单状态失败, error:" + err.Error())
	}
	custOrderStatusHistory := model.CustOrderStatusHistory{
		CustOrderId:      custOrderId,
		StatusChangeType: model.STATUS_CHANGE_TYPE_OPERATION,
		FromStatus:       baseModel.WO_STATUS_PLANNED,
		ToStatus:         baseModel.WO_STATUS_UNPLANNED,
		ChangeTime:       grmi.DateTime(time.Now()),
	}
	err = custOrderStatusHistoryDao.InsertOne(&custOrderStatusHistory)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("插入客户订单状态变更历史失败, error:" + err.Error())
	}
	_ = session.Commit()
	return nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/CustOrderService.Select
 *
 ******************************************************************************/
func (impl *CustOrderServiceImplement) PageSelect(user *global.User, urlParameters map[string]string) (grmi.PagingResult, error) {

	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "SelectCustOrder", "查询CustOrder")

	condition := DefaultConditionOfCustOrderAndPaging
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	custOrderId := urlParameters["custOrderId"]
	statusStr := urlParameters["status"]
	startTimeStr := urlParameters["start"]
	endTimeStr := urlParameters["end"]
	workLineId := urlParameters["workLineId"]
	pageNumberStr := urlParameters["pageNumber"]
	pageSizeStr := urlParameters["pageSize"]
	projectId := urlParameters["projectId"]
	productFamilyId := urlParameters["productFamilyId"]
	pageNumber, err := strconv.Atoi(pageNumberStr)
	if err != nil {
		pageNumber = 1
	}
	pageSize, err := strconv.Atoi(pageSizeStr)
	if err != nil {
		pageSize = 10
	}
	status, _ := strconv.Atoi(statusStr)

	dao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	condition.Fill(urlParameters)
	result, err := dao.PageSelect(custOrderId, workLineId, status, projectId, productFamilyId, startTimeStr, endTimeStr, int64(pageSize), int64(pageNumber))
	if err != nil {
		return grmi.EmptyPagingResult, err
	}
	return result, nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/CustOrderService.Select
 *
 ******************************************************************************/
func (impl *CustOrderServiceImplement) Dashboard(user *global.User, workLineId string) (interface{}, error) {
	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "SelectCustOrder", "查询CustOrder")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	daoWorkLine := baseDal.NewWorkLineDAO(session, user.PlantNr, user.UserId)
	daoDayModel := baseDal.NewDayModelDAO(session, user.PlantNr, user.UserId)
	//daoWeekModel := baseDal.NewWeekModelLstDAO(session, user.PlantNr, user.UserId)
	daoWeekModelLst := baseDal.NewWeekModelLstDAO(session, user.PlantNr, user.UserId)
	//daoWorkCalendar := baseDal.NewWorkCalendarDAO(session, user.PlantNr, user.UserId)
	daoWorkCalendarLst := baseDal.NewWorkCalendarLstDAO(session, user.PlantNr, user.UserId)
	daoWorkShift := baseDal.NewWorkShiftDAO(session, user.PlantNr, user.UserId)
	dashlisDao := baseDal.NewRPDashBoardLstDAO(session, user.PlantNr, user.UserId)
	dashlist, err := dashlisDao.Select([]grmi.Predicate{baseMeta.RPDashBoardLst_DashboardId.NewPredicate(grmi.Equal, 1)}, nil)
	if err != nil {
		return nil, err
	}
	var personNum int    //当班人数
	var timeBeat float64 //节拍
	var days int         //展示天数
	var ippmTarge int    //IPPM
	for _, v := range dashlist {
		if v.ParamName == "TimeBeat" {
			timeBeat = v.FloatParam1
		}
		if v.ParamName == "PersonNum" {
			personNum = v.IntParam1
		}
		if v.ParamName == "Days" {
			days = v.IntParam1
		}
		if v.ParamName == "IppmTarge" {
			ippmTarge = v.IntParam1
		}
	}
	if personNum <= 0 {
		return nil, errors.New("当班人数不能为空!")
	}
	if timeBeat <= 0 {
		return nil, errors.New("节拍不能为空!")
	}
	if days <= 0 {
		return nil, errors.New("日期长度不能为空!")
	}
	// 获取产线今天的时间模型
	workLine, err := daoWorkLine.SelectOne(workLineId)
	if err != nil {
		return nil, grmi.NewBusinessError("查询产线失败, error:" + err.Error())
	}
	if workLine == nil {
		return nil, grmi.NewBusinessError("产线不存在")
	}
	var dayModelNr int
	// 优先使用产线工作日历
	if workLine.WorkCalendarNr != 0 {
		workCalendarLstLi, err := daoWorkCalendarLst.Select([]grmi.Predicate{baseMeta.WorkCalendarLst_WorkCalendarNr.NewPredicate(grmi.Equal, workLine.WorkCalendarNr)}, []grmi.Field{baseMeta.WorkCalendarLst_WorkDate})
		if err != nil {
			return nil, grmi.NewBusinessError("查询产线工作日历子项失败, error:" + err.Error())
		}
		for _, workCalendarLst := range workCalendarLstLi {
			if workCalendarLst.WorkDate == grmi.Date(time.Now()) {
				dayModelNr = workCalendarLst.DayModelNr
				break
			}
		}
	}
	// 如果产线工作日不存在当天 则使用周模型
	if dayModelNr == 0 {
		weekModelLstLi, err := daoWeekModelLst.Select([]grmi.Predicate{baseMeta.WeekModelLst_WeekModelNr.NewPredicate(grmi.Equal, workLine.WeekModelNr)}, []grmi.Field{baseMeta.WeekModelLst_WorkDate})
		if err != nil {
			return nil, grmi.NewBusinessError("查询周模型子项失败, error:" + err.Error())
		}
		weeKDay := time.Now().Weekday()
		for _, weekModelLst := range weekModelLstLi {
			if weekModelLst.WorkDate.Restore().Weekday() == weeKDay {
				dayModelNr = weekModelLst.DayModelNr
				break
			}
		}
	}
	if dayModelNr == 0 {
		return nil, grmi.NewBusinessError("未获取到匹配今天的时间模型")
	}
	dayModel, err := daoDayModel.SelectOne(dayModelNr)
	if err != nil {
		return nil, grmi.NewBusinessError("查询日模型失败, error:" + err.Error())
	}
	if dayModel == nil {
		return nil, grmi.NewBusinessError("关联的日模型不存在")
	}
	var dayModelStartTime int
	var dayModelEndTime int
	nowTime := time.Now()
	var WorkShift int
	_ = WorkShift
	//构建开始时间和结束时间
	startDayTime := utils.GetZeroTime(time.Now())
	if dayModel.WorkShiftToggle {
		if dayModel.S1WorkShiftNr == 0 {
			return nil, grmi.NewBusinessError("绑定的日模型错误")
		}

		s1WorkShift, err := daoWorkShift.SelectOne(dayModel.S1WorkShiftNr)
		if err != nil {
			return nil, err
		}
		if s1WorkShift != nil {
			if dayModelStartTime > 0 {
				if dayModelStartTime > dayModel.S1Beg {
					dayModelStartTime = dayModel.S1Beg
				}
			} else {
				dayModelStartTime = dayModel.S1Beg
			}
			if dayModelEndTime != 0 {
				if dayModelEndTime < dayModel.S1End {
					dayModelEndTime = dayModel.S1End
				}
			} else {
				dayModelEndTime = dayModel.S1End
			}
			dayModelStartHour1 := startDayTime.Add(time.Duration(dayModel.S1Beg) * time.Second)
			dayModelEndHour1 := startDayTime.Add(time.Duration(dayModel.S1End) * time.Second)
			if nowTime.Unix() >= dayModelStartHour1.Unix() && nowTime.Unix() <= dayModelEndHour1.Unix() {
				WorkShift = 1
			}
		}

		if dayModel.S2WorkShiftNr != 0 {
			s2WorkShift, err := daoWorkShift.SelectOne(dayModel.S2WorkShiftNr)
			if err != nil {
				return nil, err
			}
			if s2WorkShift != nil {
				dayModel.S2WorkShift = *s2WorkShift
				if dayModelStartTime > 0 {
					if dayModelStartTime > dayModel.S2Beg {
						dayModelStartTime = dayModel.S2Beg
					}
				} else {
					dayModelStartTime = dayModel.S2Beg
				}
				if dayModelEndTime != 0 {
					if dayModelEndTime < dayModel.S2End {
						dayModelEndTime = dayModel.S2End
					}
				} else {
					dayModelEndTime = dayModel.S2End
				}

				dayModelStartHour2 := startDayTime.Add(time.Duration(dayModel.S2Beg) * time.Second)
				dayModelEndHour2 := startDayTime.Add(time.Duration(dayModel.S2End) * time.Second)
				if nowTime.Unix() >= dayModelStartHour2.Unix() && nowTime.Unix() <= dayModelEndHour2.Unix() {
					WorkShift = 2
				}
			}

		}
		if dayModel.S3WorkShiftNr != 0 {
			s3WorkShift, err := daoWorkShift.SelectOne(dayModel.S3WorkShiftNr)
			if err != nil {
				return nil, err
			}
			if s3WorkShift != nil {
				dayModel.S3WorkShift = *s3WorkShift

				if dayModelStartTime > 0 {
					if dayModelStartTime > dayModel.S3Beg {
						dayModelStartTime = dayModel.S3Beg
					}
				} else {
					dayModelStartTime = dayModel.S3Beg
				}
				if dayModelEndTime != 0 {
					if dayModelEndTime < dayModel.S3End {
						dayModelEndTime = dayModel.S3End
					}
				} else {
					dayModelEndTime = dayModel.S3End
				}
				dayModelStartHour3 := startDayTime.Add(time.Duration(dayModel.S3Beg) * time.Second)
				dayModelEndHour3 := startDayTime.Add(time.Duration(dayModel.S3End) * time.Second)
				if nowTime.Unix() >= dayModelStartHour3.Unix() && nowTime.Unix() <= dayModelEndHour3.Unix() {
					WorkShift = 3
				}
			}

		}
	} else {
		if dayModelStartTime > 0 {
			if dayModelStartTime > dayModel.S1Beg {
				dayModelStartTime = dayModel.S1Beg
			}
		} else {
			dayModelStartTime = dayModel.S1Beg
		}
		if dayModelEndTime != 0 {
			if dayModelEndTime < dayModel.S1End {
				dayModelEndTime = dayModel.S1End
			}
		} else {
			dayModelEndTime = dayModel.S1End
		}
		dayModelStartHour1 := startDayTime.Add(time.Duration(dayModel.S1Beg) * time.Second)
		dayModelEndHour1 := startDayTime.Add(time.Duration(dayModel.S1End) * time.Second)
		if nowTime.Unix() >= dayModelStartHour1.Unix() && nowTime.Unix() <= dayModelEndHour1.Unix() {
			WorkShift = 1
		}

		if dayModelStartTime > 0 {
			if dayModelStartTime > dayModel.S2Beg {
				dayModelStartTime = dayModel.S2Beg
			}
		} else {
			dayModelStartTime = dayModel.S2Beg
		}
		if dayModelEndTime != 0 {
			if dayModelEndTime < dayModel.S2End {
				dayModelEndTime = dayModel.S2End
			}
		} else {
			dayModelEndTime = dayModel.S2End
		}

		dayModelStartHour2 := startDayTime.Add(time.Duration(dayModel.S2Beg) * time.Second)
		dayModelEndHour2 := startDayTime.Add(time.Duration(dayModel.S2End) * time.Second)
		if nowTime.Unix() >= dayModelStartHour2.Unix() && nowTime.Unix() <= dayModelEndHour2.Unix() {
			WorkShift = 2
		}

		if dayModelStartTime > 0 {
			if dayModelStartTime > dayModel.S3Beg {
				dayModelStartTime = dayModel.S3Beg
			}
		} else {
			dayModelStartTime = dayModel.S3Beg
		}
		if dayModelEndTime != 0 {
			if dayModelEndTime < dayModel.S3End {
				dayModelEndTime = dayModel.S3End
			}
		} else {
			dayModelEndTime = dayModel.S3End
		}
		dayModelStartHour3 := startDayTime.Add(time.Duration(dayModel.S3Beg) * time.Second)
		dayModelEndHour3 := startDayTime.Add(time.Duration(dayModel.S3End) * time.Second)
		if nowTime.Unix() >= dayModelStartHour3.Unix() && nowTime.Unix() <= dayModelEndHour3.Unix() {
			WorkShift = 3
		}
	}
	if dayModelEndTime < dayModelStartTime {
		return nil, errors.New("日模型开始时间大于结束时间")
	}
	dayModelStartHour := startDayTime.Add(time.Duration(dayModelStartTime) * time.Second)
	dayModelEndHour := startDayTime.Add(time.Duration(dayModelEndTime) * time.Second)
	endDayTime := utils.GetZeroTime(time.Now().AddDate(0, 0, 1))

	DayModelHours, err := utils.GetHoursData(dayModelStartHour, dayModelEndHour)
	if err != nil {
		return nil, err
	}
	DashboardData := model.DashboardPic{}
	var err1, err2, err3, err4, err5, err6 error
	var wg sync.WaitGroup
	wg.Add(6)
	//图例001
	go func(wg *sync.WaitGroup) {
		DashboardData.DashboardDataPic1, err1 = impl.SelectPic1(user, dayModel, workLineId)
		wg.Done() // 操作完成，减少一个计数
	}(&wg )

	//图例002
	go func(wg *sync.WaitGroup) {
		DashboardData.DashboardDataPic2, err2 = impl.SelectDefectNumber(user, days, workLineId)
		wg.Done() // 操作完成，减少一个计数
	}(&wg)

	//图例003
	go func(wg *sync.WaitGroup) {
		DashboardData.DashboardDataPic3, err3 = impl.SelectPic3(user, DayModelHours, dayModelStartHour, dayModelEndHour, startDayTime, endDayTime, timeBeat, personNum, workLineId)
		wg.Done() // 操作完成，减少一个计数
	}(&wg)

	//图例004
	go func(wg *sync.WaitGroup) {
		DashboardData.DashboardDataPic4, err4 = impl.CountTarget(user, workLineId)
		wg.Done() // 操作完成，减少一个计数
	}(&wg)

	//计算当前节拍,及其平均
	go func(wg *sync.WaitGroup) {
		DashboardData.TeamTemPo, DashboardData.PerHourTemPo, err5 = impl.SelectTeamTemPo(user, dayModel, personNum, startDayTime, WorkShift, workLineId)
		wg.Done() // 操作完成，减少一个计数
	}(&wg)

	go func(wg *sync.WaitGroup) {
		DashboardData.DashboardDataStatus, err6 = impl.SelectAndonInfo(user)
		wg.Done() // 操作完成，减少一个计数
	}(&wg)
	wg.Wait()
	if err1 != nil {
		return nil, err1
	}
	if err2 != nil {
		return nil, err2
	}
	if err3 != nil {
		return nil, err3
	}

	if err4 != nil {
		return nil, err4
	}

	if err5 != nil {
		return nil, err5
	}

	if err6 != nil {
		return nil, err6
	}
	//当班人数
	DashboardData.TemPoPerson = personNum
	//节拍
	DashboardData.CurrentTempo = timeBeat
	DashboardData.IppmTarge = ippmTarge

	DashboardData.DateTimeNow = utils.TimeFormat(time.Now(), "yyyy-MM-dd HH:00")
	return DashboardData, err

}

// InitDayModelList 生成日模型时间双向连表
func (impl *CustOrderServiceImplement) InitDayModelList(dayModel *baseModel.DayModel, date time.Time) *list.List {
	dayModelList := list.New()
	dayModelList = dayModelList.Init()
	var element model.ListElement
	if dayModel.WorkShiftToggle {
		s1WorkShift := dayModel.S1WorkShift
		s2WorkShift := dayModel.S2WorkShift
		s3WorkShift := dayModel.S3WorkShift
		element.Start = date.Add(time.Duration(s1WorkShift.SBeg) * time.Second)
		if s1WorkShift.SB1Beg != 0 {
			var end time.Time
			element.End = date.Add(time.Duration(s1WorkShift.SB1Beg) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
			end = date.Add(time.Duration(s1WorkShift.SB1End) * time.Second)
			if s1WorkShift.SB2Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(s1WorkShift.SB2Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(s1WorkShift.SB2End) * time.Second)
			}
			if s1WorkShift.SB3Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(s1WorkShift.SB3Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(s1WorkShift.SB3End) * time.Second)
			}
			if s1WorkShift.SB4Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(s1WorkShift.SB4Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(s1WorkShift.SB4End) * time.Second)
			}
			if s1WorkShift.SB5Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(s1WorkShift.SB5Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(s1WorkShift.SB5End) * time.Second)
			}
			element.Start = end
			element.End = date.Add(time.Duration(s1WorkShift.SEnd) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
		} else {
			element.End = date.Add(time.Duration(s1WorkShift.SEnd) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
		}
		if s2WorkShift.SB1Beg != 0 {
			var end time.Time
			element.End = date.Add(time.Duration(s2WorkShift.SB1Beg) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
			end = date.Add(time.Duration(s2WorkShift.SB1End) * time.Second)
			if s2WorkShift.SB2Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(s2WorkShift.SB2Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(s2WorkShift.SB2End) * time.Second)
			}
			if s2WorkShift.SB3Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(s2WorkShift.SB3Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(s2WorkShift.SB3End) * time.Second)
			}
			if s2WorkShift.SB4Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(s2WorkShift.SB4Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(s2WorkShift.SB4End) * time.Second)
			}
			if s2WorkShift.SB5Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(s2WorkShift.SB5Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(s2WorkShift.SB5End) * time.Second)
			}
			element.Start = end
			element.End = date.Add(time.Duration(s2WorkShift.SEnd) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
		} else {
			element.End = date.Add(time.Duration(s2WorkShift.SEnd) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
		}
		if s3WorkShift.SB1Beg != 0 {
			var end time.Time
			element.End = date.Add(time.Duration(s3WorkShift.SB1Beg) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
			end = date.Add(time.Duration(s3WorkShift.SB1End) * time.Second)
			if s3WorkShift.SB2Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(s3WorkShift.SB2Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(s3WorkShift.SB2End) * time.Second)
			}
			if s3WorkShift.SB3Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(s3WorkShift.SB3Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(s3WorkShift.SB3End) * time.Second)
			}
			if s3WorkShift.SB4Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(s3WorkShift.SB4Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(s3WorkShift.SB4End) * time.Second)
			}
			if s3WorkShift.SB5Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(s3WorkShift.SB5Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(s3WorkShift.SB5End) * time.Second)
			}
			element.Start = end
			element.End = date.Add(time.Duration(s3WorkShift.SEnd) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
		} else {
			element.End = date.Add(time.Duration(s3WorkShift.SEnd) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
		}
	} else {

		element.Start = date.Add(time.Duration(dayModel.S1Beg) * time.Second)
		if dayModel.S1B1Beg != 0 {
			var end time.Time
			element.End = date.Add(time.Duration(dayModel.S1B1Beg) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
			end = date.Add(time.Duration(dayModel.S1B1End) * time.Second)
			if dayModel.S1B2Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(dayModel.S1B2Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(dayModel.S1B2End) * time.Second)
			}
			if dayModel.S1B3Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(dayModel.S1B3Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(dayModel.S1B3End) * time.Second)
			}
			if dayModel.S1B4Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(dayModel.S1B4Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(dayModel.S1B4End) * time.Second)
			}
			if dayModel.S1B5Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(dayModel.S1B5Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(dayModel.S1B5End) * time.Second)
			}
			element.Start = end
			element.End = date.Add(time.Duration(dayModel.S1End) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
		} else {
			element.End = date.Add(time.Duration(dayModel.S1End) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
		}

		element.Start = date.Add(time.Duration(dayModel.S2Beg) * time.Second)
		if dayModel.S2B1Beg != 0 {
			var end time.Time
			element.End = date.Add(time.Duration(dayModel.S2B1Beg) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
			end = date.Add(time.Duration(dayModel.S2B1End) * time.Second)
			if dayModel.S2B2Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(dayModel.S2B2Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(dayModel.S2B2End) * time.Second)
			}
			if dayModel.S2B3Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(dayModel.S2B3Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(dayModel.S2B3End) * time.Second)
			}
			if dayModel.S2B4Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(dayModel.S2B4Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(dayModel.S2B4End) * time.Second)
			}
			if dayModel.S2B5Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(dayModel.S2B5Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(dayModel.S2B5End) * time.Second)
			}
			element.Start = end
			element.End = date.Add(time.Duration(dayModel.S2End) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
		} else {
			element.End = date.Add(time.Duration(dayModel.S2End) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
		}
		element.Start = date.Add(time.Duration(dayModel.S3Beg) * time.Second)
		if dayModel.S3B1Beg != 0 {
			var end time.Time
			element.End = date.Add(time.Duration(dayModel.S3B1Beg) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
			end = date.Add(time.Duration(dayModel.S3B1End) * time.Second)
			if dayModel.S3B2Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(dayModel.S3B2Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(dayModel.S3B2End) * time.Second)
			}
			if dayModel.S3B3Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(dayModel.S3B3Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(dayModel.S3B3End) * time.Second)
			}
			if dayModel.S3B4Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(dayModel.S3B4Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(dayModel.S3B4End) * time.Second)
			}
			if dayModel.S3B5Beg != 0 {
				element.Start = end
				element.End = date.Add(time.Duration(dayModel.S3B5Beg) * time.Second)
				element.Duration = element.End.Sub(element.Start)
				dayModelList.PushBack(element)
				end = date.Add(time.Duration(dayModel.S3B5End) * time.Second)
			}
			element.Start = end
			element.End = date.Add(time.Duration(dayModel.S3End) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
		} else {
			element.End = date.Add(time.Duration(dayModel.S3End) * time.Second)
			element.Duration = element.End.Sub(element.Start)
			dayModelList.PushBack(element)
		}
	}
	return dayModelList
}

// SelectDefectNumber dashboard右上角 查询缺陷数据
func (impl *CustOrderServiceImplement) SelectDefectNumber(user *global.User, days int, workLineId string) ([]model.DefectItem, error) {
	result := make([]model.DefectItem, 0, days)
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	defectRecordDao := qmDal.NewDefectRecordDAO(session, user.PlantNr, user.UserId)
	repairInfoDao := baseDal.NewRepairInfoDAO(session, user.UserId)
	custOrderDao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	serialOrderDao := omDal.NewSerialOrderDAO(session, user.PlantNr, user.UserId)
	productFamilyRelateDao := meDal.NewProductFamilyRelateDAO(session, user.PlantNr, user.UserId)
	productFamilyMap := make(map[string]int)
	now := time.Now()
	custOrderMap := make(map[string]*model.CustOrder)
	for i := 0; i < days; i++ {
		var defectItem model.DefectItem
		day := now.AddDate(0, 0, -1*i).Format(grmi.DateOutFormat)
		start := day + " " + "00:00:00"
		end := day + " " + "23:59:59"
		defectRecordLi, err := defectRecordDao.Select([]grmi.Predicate{
			qmMeta.DefectRecord_CreateTime.NewPredicate(grmi.GreaterOrEqual, start),
			qmMeta.DefectRecord_CreateTime.NewPredicate(grmi.LessOrEqual, end),
		}, []grmi.Field{qmMeta.DefectRecord_SerialOrderId})
		if err != nil {
			return nil, grmi.NewBusinessError("查询缺陷记录失败，错误:" + err.Error())
		}
		serialOrderMap := make(map[string]interface{})
		for _, defectRecord := range defectRecordLi {
			_, exist := serialOrderMap[defectRecord.SerialOrderId]
			if !exist {
				serialOrderMap[defectRecord.SerialOrderId] = nil
			}
		}
		repairInfoLi, err := repairInfoDao.Select([]grmi.Predicate{
			baseMeta.RepairInfo_CreateTime.NewPredicate(grmi.GreaterOrEqual, start),
			baseMeta.RepairInfo_CreateTime.NewPredicate(grmi.LessOrEqual, end),
		}, []grmi.Field{baseMeta.RepairInfo_SerialOrderId})
		if err != nil {
			return nil, grmi.NewBusinessError("查询返修记录失败, 错误:" + err.Error())
		}
		for _, repairInfo := range repairInfoLi {
			_, exist := serialOrderMap[repairInfo.SerialOrderId]
			if !exist {
				serialOrderMap[repairInfo.SerialOrderId] = nil
			}
		}
		// 判断缺陷的这些工单归属的
		for serialOrderId := range serialOrderMap {
			serialOrder, err := serialOrderDao.SelectOne(serialOrderId)
			if err != nil {
				return nil, grmi.NewBusinessError("查询工单数据失败, 错误:" + err.Error())
			}
			if serialOrder == nil {
				delete(serialOrderMap, serialOrderId)
				continue
			}
			if serialOrder.CustOrderId == "" {
				delete(serialOrderMap, serialOrderId)
				continue
			}
			custOrder, exist := custOrderMap[serialOrder.CustOrderId]
			if !exist {
				custOrder, err = custOrderDao.SelectOne(serialOrder.CustOrderId)
				if err != nil {
					return nil, grmi.NewBusinessError("查询客户订单失败, 错误:" + err.Error())
				}
				if custOrder == nil {
					delete(serialOrderMap, serialOrderId)
					continue
				}
				custOrderMap[serialOrder.CustOrderId] = custOrder
			}
			if custOrder.WorkLineId != workLineId {
				delete(serialOrderMap, serialOrderId)
			}
		}
		defectNumber := len(serialOrderMap)
		custOrderLi, err := custOrderDao.JoinSelect([]grmi.Predicate{
			meta.CustOrder_PlanStartTime.NewPredicate(grmi.GreaterOrEqual, start),
			meta.CustOrder_PlanStartTime.NewPredicate(grmi.LessThen, end),
		}, []grmi.Field{meta.CustOrder_PlanStartTime})
		if err != nil {
			return nil, grmi.NewBusinessError("查询客户订单失败, 错误:" + err.Error())
		}
		var planQty int
		for _, custOrder := range custOrderLi {
			packNum, exist := productFamilyMap[custOrder.ProductFamilyId]
			if !exist {
				productLi, err := productFamilyRelateDao.SelectProductByFamilyId(custOrder.ProjectId, custOrder.ProductFamilyId)
				if err != nil {
					return nil, grmi.NewBusinessError("查询派生数据失败, 错误:" + err.Error())
				}
				packNum = len(productLi)
				productFamilyMap[custOrder.ProductFamilyId] = packNum
			}
			planQty += packNum * (custOrder.OrderQty.PlanQty - custOrder.OrderQty.CancelQty)
		}
		var percent int64
		if planQty == 0 {
			percent = 0
		} else {
			percent = int64(float64(defectNumber) / float64(planQty) * 1000000)
		}
		defectItem.Number = percent
		defectItem.Date = day
		result = append(result, defectItem)
	}
	return result, nil
}

func (impl *CustOrderServiceImplement) CountTarget(user *global.User, workLineId string) (model.TargetItem, error) {
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	now := time.Now()
	result := model.TargetItem{}
	custOrderDao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	packDao := jitDal.NewPackOrderDAO(session, user.PlantNr, user.UserId)
	workLineDao := baseDal.NewWorkLineDAO(session, user.PlantNr, user.UserId)
	workLineLi, err := workLineDao.Select([]grmi.Predicate{baseMeta.WorkLine_GroupLineId.NewPredicate(grmi.Equal, workLineId)}, nil)
	if err != nil {
		return result, grmi.NewBusinessError("查询工厂产线数据失败, error:" + err.Error())
	}
	if len(workLineLi) == 0 {
		return result, grmi.NewBusinessError("未查询到实体产线")
	}
	var workLineIds []string
	for _, v := range workLineLi {
		workLineIds = append(workLineIds, v.WorkLineid)
	}
	today := now.Format(grmi.DateOutFormat)
	start := today + " " + "00:00:00"
	end := today + " " + "23:59:59"
	custOrderLi, err := custOrderDao.JoinSelect([]grmi.Predicate{
		meta.CustOrder_WorkLineId.NewPredicate(grmi.Equal, workLineId),
		meta.CustOrder_PlanStartTime.NewPredicate(grmi.GreaterOrEqual, start),
		meta.CustOrder_PlanStartTime.NewPredicate(grmi.LessThen, end),
	}, []grmi.Field{meta.CustOrder_PlanStartTime})
	if err != nil {
		return result, err
	}
	//计算计划数量
	for _, custOrderData := range custOrderLi {
		result.Target += custOrderData.OrderQty.PlanQty - custOrderData.OrderQty.CancelQty

	}
	//计算打包数量
	packList, err := packDao.SelectUserClosePackOrder(start, end, workLineIds)
	if err != nil {
		return result, err
	}
	result.Current = len(packList)
	return result, nil
}

//计算当班节拍数量
func (impl *CustOrderServiceImplement) SelectTeamTemPo(user *global.User, dayModel *baseModel.DayModel, num int, startDayTime time.Time, WorkShift int, workLineId string) (TeamTemPoNumber float64, PerTeamTemPoNumber float64, err error) {
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	packOrderDao := jitDal.NewPackOrderDAO(session, user.PlantNr, user.UserId)
	workLineDao := baseDal.NewWorkLineDAO(session, user.PlantNr, user.UserId)
	workLineLi, err := workLineDao.Select([]grmi.Predicate{baseMeta.WorkLine_GroupLineId.NewPredicate(grmi.Equal, workLineId)}, nil)
	if err != nil {
		return 0, 0, grmi.NewBusinessError("查询工厂产线数据失败, error:" + err.Error())
	}
	if len(workLineLi) == 0 {
		return 0, 0, grmi.NewBusinessError("未查询到实体产线")
	}
	var workLineIds []string
	for _, v := range workLineLi {
		workLineIds = append(workLineIds, v.WorkLineid)
	}

	//计算当班平均节拍
	switch WorkShift {
	case 1:
		//查询当班开始和结束时间
		WorkShift1StartTime := startDayTime.Add(time.Duration(dayModel.S1Beg) * time.Second)
		WorkShift1EndTime := startDayTime.Add(time.Duration(dayModel.S1End) * time.Second)

		startTime := utils.TimeFormat(WorkShift1StartTime, "yyyy-MM-dd HH:mm:ss")
		endTime := utils.TimeFormat(WorkShift1EndTime, "yyyy-MM-dd HH:mm:ss")

		packData, err := packOrderDao.SelectUserClosePackOrder(startTime, endTime, workLineIds)
		if err != nil {
			return 0, 0, err
		}
		countPack := len(packData)
		packTimes := time.Now().Unix() - WorkShift1StartTime.Unix()
		if countPack > 0 {
			TeamTemPoNumber = utils.Decimal(float64(packTimes)/float64(countPack), 2)
			PerTeamTemPoNumber = utils.Decimal(float64(countPack)/float64(num), 4)
		} else {
			TeamTemPoNumber = 0
			PerTeamTemPoNumber = 0
		}
		return TeamTemPoNumber, PerTeamTemPoNumber, nil
	case 2:
		//查询当班开始和结束时间

		WorkShift2StartTime := startDayTime.Add(time.Duration(dayModel.S2Beg) * time.Second)
		WorkShift2EndTime := startDayTime.Add(time.Duration(dayModel.S2End) * time.Second)

		startTime := utils.TimeFormat(WorkShift2StartTime, "yyyy-MM-dd HH:mm:ss")
		endTime := utils.TimeFormat(WorkShift2EndTime, "yyyy-MM-dd HH:mm:ss")

		packData, err := packOrderDao.SelectUserClosePackOrder(startTime, endTime, workLineIds)
		if err != nil {
			return 0, 0, err
		}
		countPack := len(packData)
		packTimes := time.Now().Unix() - WorkShift2StartTime.Unix()
		if countPack > 0 {
			TeamTemPoNumber = utils.Decimal(float64(packTimes)/float64(countPack), 2)
			PerTeamTemPoNumber = utils.Decimal(float64(countPack)/float64(num), 4)
		} else {
			TeamTemPoNumber = 0
			PerTeamTemPoNumber = 0
		}
		return TeamTemPoNumber, PerTeamTemPoNumber, nil
	case 3:
		//查询当班开始和结束时间

		WorkShift3StartTime := startDayTime.Add(time.Duration(dayModel.S3Beg) * time.Second)
		WorkShift3EndTime := startDayTime.Add(time.Duration(dayModel.S3End) * time.Second)

		startTime := utils.TimeFormat(WorkShift3StartTime, "yyyy-MM-dd HH:mm:ss")
		endTime := utils.TimeFormat(WorkShift3EndTime, "yyyy-MM-dd HH:mm:ss")

		packData, err := packOrderDao.SelectUserClosePackOrder(startTime, endTime, workLineIds)
		if err != nil {
			return 0, 0, err
		}
		countPack := len(packData)
		packTimes := time.Now().Unix() - WorkShift3StartTime.Unix()
		if countPack > 0 {
			TeamTemPoNumber = utils.Decimal(float64(packTimes)/float64(countPack), 2)
			PerTeamTemPoNumber = utils.Decimal(float64(countPack)/float64(num), 4)
		} else {
			TeamTemPoNumber = 0
			PerTeamTemPoNumber = 0
		}
		return TeamTemPoNumber, PerTeamTemPoNumber, nil
	}
	return 0, 0, nil
}

//图例1
func (impl *CustOrderServiceImplement) SelectPic1(user *global.User, dayModel *baseModel.DayModel, workLineId string) (result model.CutLine1, err error) {
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	custOrderDao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	productFamilyDao := meDal.NewProductFamilyDAO(session, user.PlantNr, user.UserId)
	productFamilyRelateDao := meDal.NewProductFamilyRelateDAO(session, user.PlantNr, user.UserId)
	serialOrderDao := omDal.NewSerialOrderDAO(session, user.PlantNr, user.UserId)
	productFamilyMap := make(map[string]*meModel.ProductFamily)
	productFamilyRelateMap := make(map[string]map[string]interface{})
	productFamilyMeterMap := make(map[string]float64)
	now := time.Now()
	//now, _ := time.ParseInLocation(grmi.DateTimeOutFormat, "2022-03-30 23:00:00", utils.TimezoneLocation)
	endTime := now.Format(grmi.DateOutFormat) + " 23:59:59"
	todayStart := now.Format(grmi.DateOutFormat) + " 00:00:00"
	dateTimeLi := make([]int, 0, now.Hour())
	todayStartTime, _ := time.ParseInLocation(grmi.DateTimeOutFormat, todayStart, utils.TimezoneLocation)
	var num int
	for {
		if todayStartTime.Add(time.Hour * time.Duration(num)).After(now) {
			break
		}
		dateTimeLi = append(dateTimeLi, num)
		num++
	}
	timeModelList := impl.InitDayModelList(dayModel, todayStartTime)
	// 查询正在正在生产的客户订单
	custOrderLi, err := custOrderDao.SelectRunningCustOrder(workLineId)

	if err != nil {
		return result, grmi.NewBusinessError("查询正在生产的客户订单失败, 错误:" + err.Error())
	}

	var currentMeter int
	if len(custOrderLi) == 0 {
		currentMeter = 0
	} else {
		custOrder := custOrderLi[0]
		productFamily, err := productFamilyDao.SelectOne(custOrder.ProductFamilyId)
		if err != nil {
			return result, grmi.NewBusinessError("查询派生数据失败, 错误:" + err.Error())
		}
		if productFamily == nil {
			return result, grmi.NewBusinessError("客户订单派生不存在, 派生ID:" + custOrder.ProductFamilyId)
		}
		if productFamily.Jph == 0 {
			return result, grmi.NewBusinessError("派生JPH为0 派生ID:" + custOrder.ProductFamilyId)
		}
		currentMeter = int(float64(3600) / productFamily.Jph)
		productFamilyMeterMap[custOrder.ProductFamilyId] = float64(3600) / productFamily.Jph
		productFamilyMap[custOrder.ProductFamilyId] = productFamily
		productLi, err := productFamilyRelateDao.SelectProductByFamilyId(custOrder.ProjectId, custOrder.ProductFamilyId)
		if err != nil {
			return result, grmi.NewBusinessError("查询派生下总成数据失败, 错误:" + err.Error())
		}
		if len(productLi) == 0 {
			return result, grmi.NewBusinessError("派生下未关联需要生产的座椅总成, 派生ID:" + custOrder.ProductFamilyId)
		}
		productFamilyRelateMap[custOrder.ProductFamilyId] = make(map[string]interface{}, len(productLi))
		for _, product := range productLi {
			productFamilyRelateMap[custOrder.ProductFamilyId][product.ProductId] = nil
		}
	}

	// 查询客户订单 两类:
	// 1.  今天开始时间 < 实际结束时间 < 当前时间 状态 > 26 && != 98
	// 2. 实际结束时间为空 实际开始时间 < 当前时间 状态 > 26 && != 98
	custOrderDataLi, err := custOrderDao.SelectProduceOrder(todayStart, endTime, workLineId)
	if err != nil {
		return result, grmi.NewBusinessError("查询客户订单失败, 错误:" + err.Error())
	}

	productFamilyAccomplishMap := make(map[int]map[string]model.HourProductData)
	for _, custOrderData := range custOrderDataLi {
		productFamilyId := custOrderData.CustOrder.ProductFamilyId
		productFamily, exist := productFamilyMap[productFamilyId]
		if !exist {
			productFamily, err = productFamilyDao.SelectOne(productFamilyId)
			if err != nil {
				return result, grmi.NewBusinessError("查询派生数据失败, 错误:" + err.Error())
			}
			if productFamily == nil {
				return result, grmi.NewBusinessError("客户订单中派生不存在, 派生Id:" + productFamilyId + ", 客户订单Id:" + custOrderData.CustOrder.CustOrderId)
			}
			if productFamily.Jph == 0 {
				return result, grmi.NewBusinessError("派生JPH为0 派生ID:" + productFamilyId)
			}
			productLi, err := productFamilyRelateDao.SelectProductByFamilyId(custOrderData.CustOrder.ProjectId, productFamilyId)
			if err != nil {
				return result, grmi.NewBusinessError("查询派生下总成数据失败, 错误:" + err.Error())
			}
			if len(productLi) == 0 {
				return result, grmi.NewBusinessError("派生下未关联需要生产的座椅总成, 派生ID:" + productFamilyId)
			}
			productFamilyRelateMap[productFamilyId] = make(map[string]interface{}, len(productLi))
			for _, product := range productLi {
				productFamilyRelateMap[productFamilyId][product.ProductId] = nil
			}
			productFamilyMap[productFamilyId] = productFamily
			productFamilyMeterMap[productFamilyId] = float64(3600) / productFamily.Jph
		}
		// 查询客户订单下的工单
		serialOrderDataLi, err := serialOrderDao.SelectByCustOrderIdForDashboard(custOrderData.CustOrder.CustOrderId, todayStart, endTime)
		if err != nil {
			return result, grmi.NewBusinessError("查询客户订单下工单失败, 错误:" + err.Error())
		}
		// 记录生产每个台套下面的工单数量
		syncKeyMap := make(map[string][]omModel.SerialOrder)
		syncKeyAccomplishTimeMap := make(map[string]time.Time)
		for _, serialOrder := range serialOrderDataLi {
			_, exist = syncKeyMap[serialOrder.SyncKey]
			if !exist {
				syncKeyMap[serialOrder.SyncKey] = make([]omModel.SerialOrder, 0, len(productFamilyRelateMap[productFamilyId]))
			}
			syncKeyMap[serialOrder.SyncKey] = append(syncKeyMap[serialOrder.SyncKey], serialOrder)
		}
		// 找到每个台套的最后完成时间
		for syncKey, orderLi := range syncKeyMap {
			if len(orderLi) == len(productFamilyRelateMap[productFamilyId]) {
				var match = true
				orderArtIdMap := make(map[string]interface{})
				for _, order := range orderLi {
					orderArtIdMap[order.ArtId] = nil
				}
				for artId, _ := range productFamilyRelateMap[productFamilyId] {
					_, exist = orderArtIdMap[artId]
					if !exist {
						match = false
						break
					}
				}
				if !match {
					continue
				}
				var accomplishTime time.Time
				for _, serialOrder := range orderLi {
					if serialOrder.ActEndTime.Restore().After(accomplishTime) {
						accomplishTime = serialOrder.ActEndTime.Restore()
					}
				}
				syncKeyAccomplishTimeMap[syncKey] = accomplishTime
			}
		}
		// 记录每个小时完成的数量和时间
		for _, accomplishTime := range syncKeyAccomplishTimeMap {
			hour := accomplishTime.Hour()
			hourProductMap, exist := productFamilyAccomplishMap[hour]
			if !exist {
				productFamilyAccomplishMap[hour] = make(map[string]model.HourProductData)
				hourProductMap = productFamilyAccomplishMap[hour]
			}
			productFamilyData, exist := hourProductMap[productFamilyId]
			if !exist {
				hourProductMap[productFamilyId] = model.HourProductData{
					ProductFamilyId: productFamilyId,
					Qty:             1,
					LastDoneTime:    accomplishTime,
				}
			} else {
				productFamilyData.Qty++
				if productFamilyData.LastDoneTime.Before(accomplishTime) {
					productFamilyData.LastDoneTime = accomplishTime
				}
				hourProductMap[productFamilyId] = productFamilyData
			}
			productFamilyAccomplishMap[hour] = hourProductMap
		}
	}
	displayHourLi := make([]string, 0, len(productFamilyAccomplishMap))
	for hour, _ := range productFamilyAccomplishMap {
		displayHourLi = append(displayHourLi, strconv.Itoa(hour)+"时")
	}
	result = model.CutLine1{
		TimeLi:             displayHourLi,
		Standard:           1.0,
		ProductFamilyMeter: currentMeter,
		ProduceData:        make([]float64, 0, len(displayHourLi)),
	}
	for hour := 0; hour < 24; hour++ {
		hourData, exist := productFamilyAccomplishMap[hour]
		if !exist {
			continue
		}
		var hourPercent float64
		productDataLi := make([]model.HourProductData, 0, len(hourData))
		for _, data := range hourData {
			productDataLi = append(productDataLi, data)
		}
		impl.QuickSortProductData(productDataLi)
		currentTime := todayStartTime.Add(time.Hour * time.Duration(hour))
		var hourAllUsedTime int
		for _, productFamilyProductData := range productDataLi {
			usedTime := impl.GetUsefulTime(currentTime, productFamilyProductData.LastDoneTime, timeModelList)
			currentTime = productFamilyProductData.LastDoneTime
			hourAllUsedTime += usedTime
		}
		currentTime = todayStartTime.Add(time.Hour * time.Duration(hour))
		for _, productFamilyProductData := range productDataLi {
			usedTime := impl.GetUsefulTime(currentTime, productFamilyProductData.LastDoneTime, timeModelList)
			currentTime = productFamilyProductData.LastDoneTime
			meter := productFamilyMeterMap[productFamilyProductData.ProductFamilyId]
			var percent float64
			if productFamilyProductData.Qty != 0 && usedTime != 0 && hourAllUsedTime != 0 {
				percent = meter / (float64(usedTime) / float64(productFamilyProductData.Qty)) * (float64(usedTime) / float64(hourAllUsedTime))
			}
			hourPercent += percent
		}
		result.ProduceData = append(result.ProduceData, hourPercent)
	}
	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() {
		listElement := element.Value.(model.ListElement)
		if listElement.End.Before(start) {
			continue
		} else if listElement.Start.After(end) {
			continue
		} else if (listElement.Start.After(start) || listElement.Start.Equal(start)) && (listElement.End.Before(end) || listElement.End.Equal(end)) {
			duration += int(listElement.End.Sub(listElement.Start).Seconds())
		} else if listElement.Start.Before(start) && listElement.End.After(start) {
			duration += int(listElement.End.Sub(start).Seconds())
		} else if listElement.Start.After(start) && listElement.End.After(end) {
			duration += int(end.Sub(listElement.Start).Seconds())
		}
	}
	return duration
}

//图例3
func (impl *CustOrderServiceImplement) SelectPic3(user *global.User, DayModelHours []string, dayModelStartHour time.Time, dayModelEndHour time.Time, startDayTime time.Time, endDayTime time.Time, timeBeat float64, personNum int, workLineId string) (model.PerDashboardData, error) {
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	packDao := jitDal.NewPackOrderDAO(session, user.PlantNr, user.UserId)
	//图例003
	DashboardData3 := model.PerDashboardData{}
	//图例001
	workLineDao := baseDal.NewWorkLineDAO(session, user.PlantNr, user.UserId)
	workLineLi, err := workLineDao.Select([]grmi.Predicate{baseMeta.WorkLine_GroupLineId.NewPredicate(grmi.Equal, workLineId)}, nil)
	if err != nil {
		return DashboardData3, grmi.NewBusinessError("查询工厂产线数据失败, error:" + err.Error())
	}
	if len(workLineLi) == 0 {
		return DashboardData3, grmi.NewBusinessError("未查询到实体产线")
	}
	var workLineIds []string
	for _, v := range workLineLi {
		workLineIds = append(workLineIds, v.WorkLineid)
	}
	//查询当天所有的包装单情况
	jitData, err := packDao.SelectUserClosePackOrder(utils.TimeFormat(startDayTime, "yyyy-MM-dd HH:mm:ss"), utils.TimeFormat(endDayTime, "yyyy-MM-dd HH:mm:ss"), workLineIds)
	if err != nil {
		return DashboardData3, err
	}
	jitMap := make(map[string]int)

	for _, v := range jitData {

		key := utils.TimeFormat(v.OpenTime.Restore(), "yyyy-MM-dd HH:00")

		if dayModelStartHour.Unix() > v.OpenTime.Restore().Unix() {
			key = utils.TimeFormat(dayModelStartHour, "yyyy-MM-dd HH:00")
		}

		if dayModelEndHour.Unix() < v.OpenTime.Restore().Unix() {
			key = utils.TimeFormat(dayModelEndHour, "yyyy-MM-dd HH:00")
		}

		_, ok := jitMap[key]
		if ok {
			jitMap[key] += 1
		} else {
			jitMap[key] = 1
		}
	}
	for _, v := range DayModelHours {
		key := v
		val, ok := jitMap[key]
		one := model.DashboardData{}
		one.Date = v
		if ok {
			one.Val = utils.Decimal(float64(val)/float64(personNum), 2)
		} else {
			one.Val = 0
		}
		DashboardData3.DashboardData1 = append(DashboardData3.DashboardData1, one)

		two := model.DashboardData{}
		two.Date = v
		two.Val = utils.Decimal(float64((3600/timeBeat)/float64(personNum))*100, 2)

		DashboardData3.DashboardData2 = append(DashboardData3.DashboardData2, two)
	}
	return DashboardData3, nil
}

//查询状态
func (impl *CustOrderServiceImplement) SelectAndonInfo(user *global.User) (int, error) {
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	andonDao := baseDal.NewAndonInfoDAO(session, user.UserId)
	andonInfo, err := andonDao.Select([]grmi.Predicate{baseMeta.AndonInfo_IsActive.NewPredicate(grmi.Equal, 1)}, nil)
	if err != nil {
		return 0, err
	}
	if len(andonInfo) > 0 {
		return 1, nil
	}
	return 0, nil
}

func (impl *CustOrderServiceImplement) SelectCanCancelQty(user *global.User, custOrderId string) (int, error) {
	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "SelectCanCancelQty", "查询可以取消的数量")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	custOrderDao := dal.NewCustOrderDAO(session, user.PlantNr, user.UserId)
	serialOrderDao := omDal.NewSerialOrderDAO(session, user.PlantNr, user.UserId)
	productFamilyRelateDao := meDal.NewProductFamilyRelateDAO(session, user.PlantNr, user.UserId)
	custOrder, err := custOrderDao.SelectOne(custOrderId)
	if err != nil {
		return 0, grmi.NewBusinessError("查询客户订单失败, error:" + err.Error())
	}
	if custOrder == nil {
		return 0, grmi.NewBusinessError("客户订单不存在")
	}
	productLi, err := productFamilyRelateDao.SelectProductByFamilyIdForCreateSerialOrder(custOrder.ProjectId, custOrder.ProductFamilyId)
	if err != nil {
		return 0, grmi.NewBusinessError("查询派生下的总成失败, error:" + err.Error())
	}
	productNum := len(productLi)
	serialOrderDataLi, err := serialOrderDao.SelectUnOnGoingSerialOrder(custOrderId)
	if err != nil {
		return 0, grmi.NewBusinessError("查询工单数据失败, error:" + err.Error())
	}
	syncKeyMap := make(map[string][]omModel.VOmSerialorder)
	syncKeyLi := make([]string, 0)
	for _, serialOrderData := range serialOrderDataLi {
		_, exist := syncKeyMap[serialOrderData.SerialOrder.SyncKey]
		if !exist {
			syncKeyLi = append(syncKeyLi, serialOrderData.SerialOrder.SyncKey)
			syncKeyMap[serialOrderData.SerialOrder.SyncKey] = make([]omModel.VOmSerialorder, 0)
		}
		syncKeyMap[serialOrderData.SerialOrder.SyncKey] = append(syncKeyMap[serialOrderData.SerialOrder.SyncKey], serialOrderData)
	}
	var count int
	for _, syncKey := range syncKeyLi {
		if len(syncKeyMap[syncKey]) == productNum {
			count++
		}
	}
	return count, nil
}

func (impl *CustOrderServiceImplement) SplitOrderQty(user *global.User, custOrderId string, qty int) error {
	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "SelectCanCancelQty", "查询可以取消的数量")

	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)
	custOrderQtyDao := dal.NewCustOrderQtyDAO(session, user.PlantNr, user.UserId)
	custOrderStatusHistoryDao := dal.NewCustOrderStatusHistoryDAO(session, user.PlantNr, user.UserId)
	serialOrderDao := omDal.NewSerialOrderDAO(session, user.PlantNr, user.UserId)
	serialOrderStatusDao := omDal.NewSerialOrderStatusDAO(session, user.PlantNr, user.UserId)
	serialOrderStatusRecDao := omDal.NewSerialOrderStatusRecLstDAO(session, user.PlantNr, user.UserId)
	serialOrderPoDao := omDal.NewSerialOrderPOLstDAO(session, user.PlantNr, user.UserId)
	serialOrderStepDao := omDal.NewSerialOrderStepLstDAO(session, user.PlantNr, user.UserId)
	serialOrderOPDetailDao := omDal.NewSerialOrderOPDetailDAO(session, user.PlantNr, user.UserId)
	productFamilyRelateDao := meDal.NewProductFamilyRelateDAO(session, user.PlantNr, user.UserId)
	snrDao := baseDal.NewSnrDAO(session, user.PlantNr, user.UserId)
	projectDao := meDal.NewProjectDAO(session, user.PlantNr, user.UserId)
	custOrder, err := custOrderDao.SelectOne(custOrderId)
	if err != nil {
		return grmi.NewBusinessError("查询客户订单失败, error:" + err.Error())
	}
	if custOrder == nil {
		return grmi.NewBusinessError("客户订单不存在")
	}
	if custOrder.OrderStatus.Status >= baseModel.WO_STATUS_FINISHED {
		return grmi.NewBusinessError("该客户订单不允许拆单")
	}
	if custOrder.OrderQty.PlanQty-custOrder.OrderQty.CancelQty < qty {
		return grmi.NewBusinessError("客户订单允许拆分的数量不足")
	}
	project, err := projectDao.SelectOne(custOrder.ProjectId)
	if err != nil {
		return grmi.NewBusinessError("查询项目数据失败, error:" + err.Error())
	}
	if project == nil {
		return grmi.NewBusinessError("客户订单绑定的项目不存在")
	}
	if custOrder.OrderStatus.Status < baseModel.WO_STATUS_LOCKED {
		if err = session.Begin(); err != nil {
			return grmi.NewBusinessError("开启事务失败, error:" + err.Error())
		}
		newCustOrderId, err := snrDao.GetNextSnr(project.CustOrderSnr)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("生成新的客户订单流水号失败, error:" + err.Error())
		}
		newCustOrder := model.CustOrder{
			SourceId:           custOrderId,
			CustOrderId:        newCustOrderId,
			ProductFamilyId:    custOrder.ProductFamilyId,
			PartId:             custOrder.PartId,
			OemOrderId:         custOrder.OemOrderId,
			OrderType:          custOrder.OrderType,
			OrderInfo:          custOrder.OrderInfo,
			OrderTime:          custOrder.OrderTime,
			DeliveryTime:       custOrder.DeliveryTime,
			ProjectId:          custOrder.ProjectId,
			ConfigValue:        custOrder.ConfigValue,
			ModelValue:         custOrder.ModelValue,
			ColorValue:         custOrder.ColorValue,
			HandleStatus:       custOrder.HandleStatus,
			VinPrefix:          custOrder.VinPrefix,
			VinNrFrom:          custOrder.VinNrFrom,
			VinNrTo:            custOrder.VinNrTo,
			Vin:                custOrder.Vin,
			PlanQty:            qty,
			DeliveryDate:       custOrder.DeliveryDate,
			DeliveryDateTime:   custOrder.DeliveryDateTime,
			OemSeq:             custOrder.OemSeq,
			AssemblyLine:       custOrder.AssemblyLine,
			UnloadingPoint:     custOrder.UnloadingPoint,
			CalloffId:          custOrder.CalloffId,
			CalloffDateTime:    custOrder.CalloffDateTime,
			ConsigneePlant:     custOrder.ConsigneePlant,
			ConsigneeCompany:   custOrder.ConsigneeCompany,
			ConsumeCompany:     custOrder.ConsumeCompany,
			ConsumePlant:       custOrder.ConsumePlant,
			UnloadingPlace:     custOrder.UnloadingPlace,
			VehicleIdSet:       custOrder.VehicleIdSet,
			VehicleId:          custOrder.VehicleId,
			FixStartTimeToggle: custOrder.FixStartTimeToggle,
			WorkLineId:         custOrder.WorkLineId,
			QuantityPerHour:    custOrder.QuantityPerHour,
			CtrlPara1:          1,
		}
		err = custOrderDao.InsertOne(&newCustOrder)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("写入拆分出新的客户订单失败, error:" + err.Error())
		}
		newCustOrderStatus := model.CustOrderStatus{
			CustOrderId: newCustOrderId,
			Status:      baseModel.WO_STATUS_UNPLANNED,
		}
		err = custOrderStatusDao.InsertOne(&newCustOrderStatus)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("写入拆分出新的客户订单状态数据失败, error:" + err.Error())
		}
		newCustOrderQty := model.CustOrderQty{
			CustOrderId: newCustOrderId,
			PlanQty:     qty,
		}
		err = custOrderQtyDao.InsertOne(&newCustOrderQty)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("写入拆分出新的客户订单数量数据失败, error:" + err.Error())
		}
		custOrder.PlanQty = custOrder.PlanQty - qty
		err = custOrderDao.UpdateOne(custOrder)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("更新客户订单数据失败, error:" + err.Error())
		}
		custOrder.OrderQty.PlanQty = custOrder.OrderQty.PlanQty - qty
		custOrder.OrderQty.ReleasedQty = custOrder.OrderQty.ReleasedQty - qty
		err = custOrderQtyDao.UpdateOne(&custOrder.OrderQty)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("更新客户订单数量数据失败, error:" + err.Error())
		}
		if custOrder.OrderQty.PlanQty == custOrder.OrderQty.CancelQty {
			custOrderStatusRec := model.CustOrderStatusHistory{
				CustOrderId:      custOrderId,
				StatusChangeType: "SPLIT",
				FromStatus:       custOrder.OrderStatus.Status,
				ToStatus:         baseModel.WO_STATUS_CANCELED,
				ChangeTime:       grmi.DateTime(time.Now()),
			}
			err = custOrderStatusHistoryDao.InsertOne(&custOrderStatusRec)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("写入客户订单状态变更历史失败, error:" + err.Error())
			}
			custOrder.OrderStatus.Status = baseModel.WO_STATUS_CANCELED
			err = custOrderStatusDao.UpdateOne(&custOrder.OrderStatus)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("更新客户订单状态失败, error:" + err.Error())
			}
		} else if custOrder.OrderQty.PlanQty == custOrder.OrderQty.ActQty+custOrder.OrderQty.CancelQty {
			custOrderStatusRec := model.CustOrderStatusHistory{
				CustOrderId:      custOrderId,
				StatusChangeType: "SPLIT",
				FromStatus:       custOrder.OrderStatus.Status,
				ToStatus:         baseModel.WO_STATUS_FINISHED,
				ChangeTime:       grmi.DateTime(time.Now()),
			}
			err = custOrderStatusHistoryDao.InsertOne(&custOrderStatusRec)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("写入客户订单状态变更历史失败, error:" + err.Error())
			}
			custOrder.OrderStatus.Status = baseModel.WO_STATUS_FINISHED
			err = custOrderStatusDao.UpdateOne(&custOrder.OrderStatus)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("更新客户订单状态失败, error:" + err.Error())
			}
		}
	}

	productLi, err := productFamilyRelateDao.SelectProductByFamilyIdForCreateSerialOrder(custOrder.ProjectId, custOrder.ProductFamilyId)
	if err != nil {
		return grmi.NewBusinessError("查询派生下的总成失败, error:" + err.Error())
	}
	productNum := len(productLi)
	serialOrderDataLi, err := serialOrderDao.SelectUnOnGoingSerialOrder(custOrderId)
	if err != nil {
		return grmi.NewBusinessError("查询工单数据失败, error:" + err.Error())
	}
	syncKeyMap := make(map[string][]omModel.VOmSerialorder)
	syncKeyLi := make([]string, 0)
	for _, serialOrderData := range serialOrderDataLi {
		_, exist := syncKeyMap[serialOrderData.SerialOrder.SyncKey]
		if !exist {
			syncKeyLi = append(syncKeyLi, serialOrderData.SerialOrder.SyncKey)
			syncKeyMap[serialOrderData.SerialOrder.SyncKey] = make([]omModel.VOmSerialorder, 0)
		}
		syncKeyMap[serialOrderData.SerialOrder.SyncKey] = append(syncKeyMap[serialOrderData.SerialOrder.SyncKey], serialOrderData)
	}
	var count int
	splitSyncKeyLi := make([]string, 0)
	for _, syncKey := range syncKeyLi {
		if len(syncKeyMap[syncKey]) == productNum {
			splitSyncKeyLi = append(splitSyncKeyLi, syncKey)
			count++
		}
	}
	impl.QuickSort(splitSyncKeyLi)
	if count < qty {
		return grmi.NewBusinessError("当前客户订单可取消数量小于需要取消数量")
	}
	if err = session.Begin(); err != nil {
		return grmi.NewBusinessError("开启事务失败, error:" + err.Error())
	}
	newCustOrderId, err := snrDao.GetNextSnr(project.CustOrderSnr)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("生成新的客户订单流水号失败, error:" + err.Error())
	}
	newCustOrder := model.CustOrder{
		SourceId:           custOrderId,
		CustOrderId:        newCustOrderId,
		ProductFamilyId:    custOrder.ProductFamilyId,
		PartId:             custOrder.PartId,
		OemOrderId:         custOrder.OemOrderId,
		OrderType:          custOrder.OrderType,
		OrderInfo:          custOrder.OrderInfo,
		OrderTime:          custOrder.OrderTime,
		DeliveryTime:       custOrder.DeliveryTime,
		ProjectId:          custOrder.ProjectId,
		ConfigValue:        custOrder.ConfigValue,
		ModelValue:         custOrder.ModelValue,
		ColorValue:         custOrder.ColorValue,
		HandleStatus:       custOrder.HandleStatus,
		VinPrefix:          custOrder.VinPrefix,
		VinNrFrom:          custOrder.VinNrFrom,
		VinNrTo:            custOrder.VinNrTo,
		Vin:                custOrder.Vin,
		PlanQty:            qty,
		DeliveryDate:       custOrder.DeliveryDate,
		DeliveryDateTime:   custOrder.DeliveryDateTime,
		OemSeq:             custOrder.OemSeq,
		AssemblyLine:       custOrder.AssemblyLine,
		UnloadingPoint:     custOrder.UnloadingPoint,
		CalloffId:          custOrder.CalloffId,
		CalloffDateTime:    custOrder.CalloffDateTime,
		ConsigneePlant:     custOrder.ConsigneePlant,
		ConsigneeCompany:   custOrder.ConsigneeCompany,
		ConsumeCompany:     custOrder.ConsumeCompany,
		ConsumePlant:       custOrder.ConsumePlant,
		UnloadingPlace:     custOrder.UnloadingPlace,
		VehicleIdSet:       custOrder.VehicleIdSet,
		VehicleId:          custOrder.VehicleId,
		FixStartTimeToggle: custOrder.FixStartTimeToggle,
		WorkLineId:         custOrder.WorkLineId,
		QuantityPerHour:    custOrder.QuantityPerHour,
		CtrlPara1:          1,
	}
	err = custOrderDao.InsertOne(&newCustOrder)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("写入拆分出新的客户订单失败, error:" + err.Error())
	}
	newCustOrderStatus := model.CustOrderStatus{
		CustOrderId: newCustOrderId,
		Status:      baseModel.WO_STATUS_UNPLANNED,
	}
	err = custOrderStatusDao.InsertOne(&newCustOrderStatus)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("写入拆分出新的客户订单状态数据失败, error:" + err.Error())
	}
	newCustOrderQty := model.CustOrderQty{
		CustOrderId: newCustOrderId,
		PlanQty:     qty,
	}
	err = custOrderQtyDao.InsertOne(&newCustOrderQty)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("写入拆分出新的客户订单数量数据失败, error:" + err.Error())
	}
	custOrder.PlanQty = custOrder.PlanQty - qty
	err = custOrderDao.UpdateOne(custOrder)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("更新客户订单数据失败, error:" + err.Error())
	}
	custOrder.OrderQty.PlanQty = custOrder.OrderQty.PlanQty - qty
	custOrder.OrderQty.ReleasedQty = custOrder.OrderQty.ReleasedQty - qty
	err = custOrderQtyDao.UpdateOne(&custOrder.OrderQty)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("更新客户订单数量数据失败, error:" + err.Error())
	}
	if custOrder.OrderQty.PlanQty == custOrder.OrderQty.CancelQty {
		custOrderStatusRec := model.CustOrderStatusHistory{
			CustOrderId:      custOrderId,
			StatusChangeType: "SPLIT",
			FromStatus:       custOrder.OrderStatus.Status,
			ToStatus:         baseModel.WO_STATUS_CANCELED,
			ChangeTime:       grmi.DateTime(time.Now()),
		}
		err = custOrderStatusHistoryDao.InsertOne(&custOrderStatusRec)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("写入客户订单状态变更历史失败, error:" + err.Error())
		}
		custOrder.OrderStatus.Status = baseModel.WO_STATUS_CANCELED
		err = custOrderStatusDao.UpdateOne(&custOrder.OrderStatus)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("更新客户订单状态失败, error:" + err.Error())
		}
	} else if custOrder.OrderQty.PlanQty == custOrder.OrderQty.ActQty+custOrder.OrderQty.CancelQty {
		custOrderStatusRec := model.CustOrderStatusHistory{
			CustOrderId:      custOrderId,
			StatusChangeType: "SPLIT",
			FromStatus:       custOrder.OrderStatus.Status,
			ToStatus:         baseModel.WO_STATUS_FINISHED,
			ChangeTime:       grmi.DateTime(time.Now()),
		}
		err = custOrderStatusHistoryDao.InsertOne(&custOrderStatusRec)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("写入客户订单状态变更历史失败, error:" + err.Error())
		}
		custOrder.OrderStatus.Status = baseModel.WO_STATUS_FINISHED
		err = custOrderStatusDao.UpdateOne(&custOrder.OrderStatus)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("更新客户订单状态失败, error:" + err.Error())
		}
	}
	for i := 0; i < qty; i++ {
		cancelSyncKey := splitSyncKeyLi[i]
		orderDataLi, err := serialOrderDao.Select([]grmi.Predicate{omMeta.SerialOrder_SyncKey.NewPredicate(grmi.Equal, cancelSyncKey)}, nil)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("查询工单数据失败, error:" + err.Error())
		}
		for _, serialOrderData := range orderDataLi {
			serialOrderData.CustOrderId = newCustOrderId
			resultLi := strings.Split(serialOrderData.SyncKey, "-")
			if len(resultLi) < 2 {
				_ = session.Rollback()
				return grmi.NewBusinessError("工单SyncKey格式错误，工单ID:" + serialOrderData.SerialOrderId)
			}
			serialOrderData.SyncKey = newCustOrderId + "-" + resultLi[len(resultLi)-1]
			err = serialOrderDao.UpdateOne(&serialOrderData)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("更新工单数据失败, error:" + err.Error())
			}
			serialOrderStatus := serialOrderData.SerialOrderStatus
			statusRec := omModel.SerialOrderStatusRecLst{
				SerialOrderId: serialOrderData.SerialOrderId,
				PrevStatus:    serialOrderStatus.Status,
				Status:        baseModel.WO_STATUS_UNPLANNED,
				Remark1:       "SPLIT",
			}
			err = serialOrderStatusRecDao.InsertOne(&statusRec)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("写入工单状态变更记录失败, error:" + err.Error())
			}
			serialOrderStatus.Status = baseModel.WO_STATUS_UNPLANNED
			err = serialOrderStatusDao.UpdateOneWithStatus(&serialOrderStatus, baseModel.WO_STATUS_RELEASED)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("更新工单状态失败, error:" + err.Error())
			}
			poUpdateData := omModel.SerialOrderPOLst{
				Status: baseModel.WO_STATUS_UNPLANNED,
			}
			err = serialOrderPoDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderPOLst_SerialOrderId.NewPredicate(grmi.Equal, serialOrderData.SerialOrderId)}, &poUpdateData, []string{omMeta.SerialOrderPOLst_Status.Name}...)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("更新工单工序状态失败, error:" + err.Error())
			}
			stepUpdateData := omModel.SerialOrderStepLst{
				Status: baseModel.WO_STATUS_UNPLANNED,
			}
			err = serialOrderStepDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderStepLst_SerialOrderId.NewPredicate(grmi.Equal, serialOrderData.SerialOrderId)}, &stepUpdateData, []string{omMeta.SerialOrderStepLst_Status.Name}...)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("更新工单工步状态失败, error:" + err.Error())
			}
			opDetailUpdateData := omModel.SerialOrderOPDetail{
				Status: baseModel.WO_STATUS_UNPLANNED,
			}
			err = serialOrderOPDetailDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderOPDetail_SerialOrderId.NewPredicate(grmi.Equal, serialOrderData.SerialOrderId)}, &opDetailUpdateData, []string{omMeta.SerialOrderOPDetail_Status.Name}...)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("更新工单详细操作状态失败, error:" + err.Error())
			}
			// 对预装工单进行处理
			preSerialOrderLi, err := serialOrderDao.Select([]grmi.Predicate{
				omMeta.SerialOrder_OrderType.NewPredicate(grmi.Equal, baseModel.ORDER_TYPE_PRE),
				omMeta.SerialOrder_GenerateFlag.NewPredicate(grmi.Equal, 0),
				omMeta.SerialOrder_MainOrderId.NewPredicate(grmi.Equal, serialOrderData.SerialOrderId),
			}, nil)
			if err != nil {
				return grmi.NewBusinessError("查询工单下的预装工单失败, 错误：" + err.Error())
			}
			for _, preOrder := range preSerialOrderLi {
				preOrder.CustOrderId = newCustOrderId
				err = serialOrderDao.UpdateOne(&preOrder)
				if err != nil {
					return grmi.NewBusinessError("更新预装工单数据失败, 错误:" + err.Error())
				}
				if preOrder.SerialOrderStatus.Status > baseModel.WO_STATUS_RELEASED {
					return grmi.NewBusinessError("预装工单已经不允许取消, 工单ID:" + preOrder.SerialOrderId)
				}
				originStatus := preOrder.SerialOrderStatus.Status
				statusRec = omModel.SerialOrderStatusRecLst{
					SerialOrderId: preOrder.SerialOrderId,
					Status:        baseModel.WO_STATUS_UNPLANNED,
					PrevStatus:    preOrder.SerialOrderStatus.Status,
				}
				preOrder.SerialOrderStatus.Status = baseModel.WO_STATUS_UNPLANNED
				err = serialOrderStatusRecDao.InsertOne(&statusRec)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("插入预装工单状态变更记录失败, error:" + err.Error())
				}
				err = serialOrderStatusDao.UpdateOneWithStatus(&preOrder.SerialOrderStatus, baseModel.WO_STATUS_RELEASED)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("更新预装工单状态失败， error:" + err.Error())
				}
				if originStatus == baseModel.WO_STATUS_RELEASED {
					poUpdateData := &omModel.SerialOrderPOLst{
						Status: baseModel.WO_STATUS_UNPLANNED,
					}
					err = serialOrderPoDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderPOLst_SerialOrderId.NewPredicate(grmi.Equal, preOrder.SerialOrderId)}, poUpdateData, omMeta.SerialOrderPOLst_Status.Name)
					if err != nil {
						_ = session.Rollback()
						return grmi.NewBusinessError("更新预装工单工序状态失败, error:" + err.Error())
					}
					stepUpdateData := &omModel.SerialOrderStepLst{
						Status: baseModel.WO_STATUS_UNPLANNED,
					}
					err = serialOrderStepDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderStepLst_SerialOrderId.NewPredicate(grmi.Equal, preOrder.SerialOrderId)}, stepUpdateData, omMeta.SerialOrderStepLst_Status.Name)
					if err != nil {
						_ = session.Rollback()
						return grmi.NewBusinessError("更新预装工单工步状态失败, error:" + err.Error())
					}
					opDetailUpdateData := &omModel.SerialOrderOPDetail{
						Status: baseModel.WO_STATUS_UNPLANNED,
					}
					err = serialOrderOPDetailDao.UpdateWhere([]grmi.Predicate{omMeta.SerialOrderOPDetail_SerialOrderId.NewPredicate(grmi.Equal, preOrder.SerialOrderId)}, opDetailUpdateData, omMeta.SerialOrderOPDetail_Status.Name)
					if err != nil {
						_ = session.Rollback()
						return grmi.NewBusinessError("更新预装工单详细操作状态失败, error:" + err.Error())
					}
				}
			}
		}
	}
	_ = session.Commit()
	return nil
}

// AnalysisPlanFromExcel 解析Excel
func (impl *CustOrderServiceImplement) AnalysisPlanFromExcel(user *global.User, filepath string) error {
	grmi.Log(user, "/services/pln/implments/CustOrder.service.impl.go", "AnalysisPlanFromExcel", "从Excel解析需求")

	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)
	custOrderQtyDao := dal.NewCustOrderQtyDAO(session, user.PlantNr, user.UserId)
	productFamilyDao := meDal.NewProductFamilyDAO(session, user.PlantNr, user.UserId)
	projectDao := meDal.NewProjectDAO(session, user.PlantNr, user.UserId)
	snrDao := baseDal.NewSnrDAO(session, user.PlantNr, user.UserId)
	file, err := excelize.OpenFile(filepath)
	if err != nil {
		return grmi.NewBusinessError("读取文件失败, error:" + err.Error())
	}
	rowsIterator, err := file.Rows("Sheet1")
	if err != nil {
		return grmi.NewBusinessError("读取Sheet1页失败, error:" + err.Error())
	}
	today, _ := time.ParseInLocation(grmi.DateTimeOutFormat, time.Now().Format(grmi.DateOutFormat)+" 00:00:00", utils.TimezoneLocation)
	rowIndex := 0
	projectMap := make(map[string]*meModel.Project)
	productFamilyMap := make(map[string]*meModel.ProductFamily)
	planDateCustOrderMap := make(map[string][]model.CustOrder, 0)
	for rowsIterator.Next() {
		rowIndex++
		// 第一行标题行
		if rowIndex == 1 {
			_, err = rowsIterator.Columns()
			if err != nil {
				return grmi.NewBusinessError("去读excel行数据失败, error:" + err.Error())
			}
			continue
		}

		row, err := rowsIterator.Columns()
		if err != nil {
			return grmi.NewBusinessError("去读excel行数据失败, error:" + err.Error())
		}
		if len(row) != 4 {
			return grmi.NewBusinessError("excel数据列数不合规, 行数:" + strconv.Itoa(rowIndex))
		}
		productFamilyId := row[0]
		projectId := row[1]
		qty, err := strconv.Atoi(row[2])
		if err != nil {
			return grmi.NewBusinessError("解析数量失败， 行数:" + strconv.Itoa(rowIndex))
		}
		if qty == 0 {
			return grmi.NewBusinessError("需求数量为0, 行数:" + strconv.Itoa(rowIndex))
		}
		planDateStr := row[3]
		planDate, err := time.ParseInLocation(grmi.DateOutFormat, planDateStr, utils.TimezoneLocation)
		if err != nil {
			return grmi.NewBusinessError("解析计划日期失败, 行数:" + strconv.Itoa(rowIndex))
		}
		if planDate.Before(today) {
			return grmi.NewBusinessError("计划日期不能早于今天")
		}
		productFamily, exist := productFamilyMap[productFamilyId]
		if !exist {
			productFamily, err = productFamilyDao.SelectOne(productFamilyId)
			if err != nil {
				return grmi.NewBusinessError("查询派生数据失败, 错误:" + err.Error())
			}
			if productFamily == nil {
				return grmi.NewBusinessError("派生不存在, 派生ID:" + productFamilyId + ", 行数:" + strconv.Itoa(rowIndex))
			}
			productFamilyMap[productFamilyId] = productFamily
		}
		project, exist := projectMap[projectId]
		if !exist {
			project, err = projectDao.SelectOne(projectId)
			if err != nil {
				return grmi.NewBusinessError("查询项目数据失败, 错误:" + err.Error())
			}
			if project == nil {
				return grmi.NewBusinessError("项目不存在, 项目ID:" + projectId + ", 行数:" + strconv.Itoa(rowIndex))
			}
			projectMap[projectId] = project
		}
		custOrder := model.CustOrder{
			ProductFamilyId: productFamilyId,
			PartId:          productFamilyId,
			OrderType:       baseModel.ODER_TYPE_INTERVAL,
			OrderInfo:       productFamily.Descr,
			OrderTime:       grmi.DateTime(time.Now()),
			ProjectId:       projectId,
			ConfigValue:     productFamily.ConfigValue,
			ModelValue:      productFamily.ModelValue,
			ColorValue:      productFamily.ColorValue,
			PlanQty:         qty,
			WorkLineId:      productFamily.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())
		}
		if len(existCustOrderLi) != 0 {
			return grmi.NewBusinessError("计划日期中存在跨天的客户订单，无法计划客户订单, 日期:" + planDate)
		}
		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()
		}
		if startPlanTime.Before(time.Now()) {
			startPlanTime = time.Now()
		}
		// 按照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
			}
		}
		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 index, custOrder := range custOrderLi {
			project := projectMap[custOrder.ProjectId]
			custOrderId, err := snrDao.GetNextSnr(project.CustOrderSnr)
			if err != nil {
				_ = session.Rollback()
				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,
			}
			custOrderQtyLi = append(custOrderQtyLi, custOrderQty)
			tempCustOrderLi = append(tempCustOrderLi, custOrder)
			if index != 0 && index%20 == 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())
				}
				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())
			}
		}
	}
	_ = session.Commit()
	return nil
}

func (impl *CustOrderServiceImplement) QuickSort(values []string) {
	if len(values) <= 1 {
		return
	}
	mid, i := values[0], 1
	tempLi := strings.Split(mid, "-")
	midNum, _ := strconv.Atoi(tempLi[len(tempLi)-1])
	head, tail := 0, len(values)-1
	for head < tail {
		tempLi = strings.Split(values[i], "-")
		iNum, _ := strconv.Atoi(tempLi[len(tempLi)-1])
		if iNum < midNum {
			values[i], values[tail] = values[tail], values[i]
			tail--
		} else {
			values[i], values[head] = values[head], values[i]
			head++
			i++
		}
	}
	values[head] = mid
	impl.QuickSort(values[:head])
	impl.QuickSort(values[head+1:])
}

func (impl *CustOrderServiceImplement) QuickSortProductData(values []model.HourProductData) {
	if len(values) <= 1 {
		return
	}
	mid, i := values[0], 1
	midTime := mid.LastDoneTime
	head, tail := 0, len(values)-1
	for head < tail {
		iTime := values[i].LastDoneTime
		if iTime.Before(midTime) {
			values[i], values[tail] = values[tail], values[i]
			tail--
		} else {
			values[i], values[head] = values[head], values[i]
			head++
			i++
		}
	}
	values[head] = mid
	impl.QuickSortProductData(values[:head])
	impl.QuickSortProductData(values[head+1:])
}
