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

package implments

import (
	"LAPP_ACURA_MOM_BACKEND/conf"
	baseDal "LAPP_ACURA_MOM_BACKEND/dao/base"
	dal "LAPP_ACURA_MOM_BACKEND/dao/jit"
	meDal "LAPP_ACURA_MOM_BACKEND/dao/me"
	omDal "LAPP_ACURA_MOM_BACKEND/dao/om"
	"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"
	meta "LAPP_ACURA_MOM_BACKEND/meta/jit"
	baseModel "LAPP_ACURA_MOM_BACKEND/models/base"
	model "LAPP_ACURA_MOM_BACKEND/models/jit"
	omModel "LAPP_ACURA_MOM_BACKEND/models/om"
	"LAPP_ACURA_MOM_BACKEND/utils"
	"fmt"
	json "github.com/json-iterator/go"
	"github.com/kataras/iris/v12"
	"strconv"
	"time"
)

/******************************************************************************
 *
 * @Description              : ShipOrder的默认查询条件
 *
 * @Author                   : 代码生成器创建
 *
 * @Date                     : 2021-10-19 10:26:40
 *
 ******************************************************************************/
var DefaultConditionOfShipOrder = grmi.NewCondition(
	map[string]grmi.ConditionItem{
		meta.ShipOrder_ShipOrderId.UrlParameterName:       grmi.NewConditionItem(meta.ShipOrder_ShipOrderId, grmi.Equal, true),
		meta.ShipOrder_ShipTemplateId.UrlParameterName:    grmi.NewConditionItem(meta.ShipOrder_ShipTemplateId, grmi.Equal, false),
		meta.ShipOrder_ProjectId.UrlParameterName:         grmi.NewConditionItem(meta.ShipOrder_ProjectId, grmi.Equal, false),
		meta.ShipOrder_ShipType.UrlParameterName:          grmi.NewConditionItem(meta.ShipOrder_ShipType, grmi.Equal, false),
		meta.ShipOrder_OrderInfo.UrlParameterName:         grmi.NewConditionItem(meta.ShipOrder_OrderInfo, grmi.Equal, false),
		meta.ShipOrder_PrinterId.UrlParameterName:         grmi.NewConditionItem(meta.ShipOrder_PrinterId, grmi.Equal, false),
		meta.ShipOrder_TemplateFile.UrlParameterName:      grmi.NewConditionItem(meta.ShipOrder_TemplateFile, grmi.Equal, false),
		meta.ShipOrder_PlanQty.UrlParameterName:           grmi.NewConditionItem(meta.ShipOrder_PlanQty, grmi.Equal, false),
		meta.ShipOrder_ActQty.UrlParameterName:            grmi.NewConditionItem(meta.ShipOrder_ActQty, grmi.Equal, false),
		meta.ShipOrder_OpenTime.UrlParameterName:          grmi.NewConditionItem(meta.ShipOrder_OpenTime, grmi.Approximate, false),
		meta.ShipOrder_CloseTime.UrlParameterName:         grmi.NewConditionItem(meta.ShipOrder_CloseTime, grmi.Approximate, false),
		meta.ShipOrder_Operator.UrlParameterName:          grmi.NewConditionItem(meta.ShipOrder_Operator, grmi.Equal, false),
		meta.ShipOrder_FormalShipOrderId.UrlParameterName: grmi.NewConditionItem(meta.ShipOrder_FormalShipOrderId, grmi.Equal, false),
		meta.ShipOrder_SourceId.UrlParameterName:          grmi.NewConditionItem(meta.ShipOrder_SourceId, grmi.Equal, false),
		meta.ShipOrder_PlateNumber.UrlParameterName:       grmi.NewConditionItem(meta.ShipOrder_PlateNumber, grmi.Equal, false),
		meta.ShipOrder_CheckCarSet.UrlParameterName:       grmi.NewConditionItem(meta.ShipOrder_CheckCarSet, grmi.Equal, false),
		meta.ShipOrder_CtrlPara1.UrlParameterName:         grmi.NewConditionItem(meta.ShipOrder_CtrlPara1, grmi.Equal, false),
		meta.ShipOrder_CtrlPara2.UrlParameterName:         grmi.NewConditionItem(meta.ShipOrder_CtrlPara2, grmi.Equal, false),
		meta.ShipOrder_CtrlStr1.UrlParameterName:          grmi.NewConditionItem(meta.ShipOrder_CtrlStr1, grmi.Equal, false),
		meta.ShipOrder_CtrlStr2.UrlParameterName:          grmi.NewConditionItem(meta.ShipOrder_CtrlStr2, grmi.Equal, false),
		meta.ShipOrder_CtrlTime1.UrlParameterName:         grmi.NewConditionItem(meta.ShipOrder_CtrlTime1, grmi.Approximate, false),
		meta.ShipOrder_CtrlTime2.UrlParameterName:         grmi.NewConditionItem(meta.ShipOrder_CtrlTime2, grmi.Approximate, false),
		meta.ShipOrder_LastModify.UrlParameterName:        grmi.NewConditionItem(meta.ShipOrder_LastModify, grmi.Approximate, false),
		meta.ShipOrder_LastUser.UrlParameterName:          grmi.NewConditionItem(meta.ShipOrder_LastUser, grmi.Equal, false),
		meta.ShipOrder_CreateTime.UrlParameterName:        grmi.NewConditionItem(meta.ShipOrder_CreateTime, grmi.Approximate, false),
	},
	nil,
)

/******************************************************************************
 *
 * @Description              : ShipOrder的默认分页查询条件
 *
 * @Author                   : 代码生成器创建
 *
 * @Date                     : 2021-10-19 10:26:40
 *
 ******************************************************************************/
var DefaultConditionOfShipOrderAndPaging = grmi.NewCondition(
	DefaultConditionOfShipOrder.Items,
	grmi.NewPaging(),
)

/******************************************************************************
 *
 * @Struct Name              : ShipOrderServiceImplement
 *-----------------------------------------------------------------------------
 *
 * @Description              : ShipOrder的服务实现
 *
 * @Author                   : 代码生成器创建
 *
 * @Date                     : 2021-10-19 10:26:40
 *
 ******************************************************************************/
type ShipOrderServiceImplement struct {
}

/******************************************************************************
 *
 * @Function Name            : NewShipOrderDAOImplement
 *-----------------------------------------------------------------------------
 *
 * @Description              : 创建一个ShipOrderDAOImplement实例
 *
 * @Return Value             : ShipOrderDAOImplement实例
 *
 * @Author                   : 代码生成器创建
 *
 * @Date                     : 2021-10-19 10:26:40
 *
 ******************************************************************************/
func NewShipOrderServiceImplement() *ShipOrderServiceImplement {
	return &ShipOrderServiceImplement{}
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/jit/ShipOrderService.InsertOne
 *
 ******************************************************************************/
func (impl *ShipOrderServiceImplement) InsertOne(user *global.User, entity *model.ShipOrder) error {

	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "InsertOneShipOrder", "插入一个ShipOrder")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewShipOrderDAO(session, user.PlantNr, user.UserId)
	record, err := dao.SelectOne(entity.ShipOrderId)
	if err != nil {
		return err
	}
	if record != nil {
		return grmi.NewBusinessError("已经存在相同主键的记录!")
	}
	err = dao.InsertOne(entity)
	if err != nil {
		return err
	}
	return nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/jit/ShipOrderService.DeleteOne
 *
 ******************************************************************************/
func (impl *ShipOrderServiceImplement) DeleteOne(user *global.User, shipOrderId string) error {

	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "DeleteOneShipOrder", "删除一个ShipOrder")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	if err := session.Begin(); err != nil {
		return grmi.NewBusinessError("开始事务失败, error:" + err.Error())
	}
	dao := dal.NewShipOrderDAO(session, user.PlantNr, user.UserId)
	statusDao := dal.NewShipOrderStatusDAO(session, user.PlantNr, user.UserId)
	itemDao := dal.NewShipOrderItemLstDAO(session, user.PlantNr, user.UserId)
	dataLstDao := dal.NewShipOrderDataLstDAO(session, user.PlantNr, user.UserId)
	packOrderStatusHistoryDao := dal.NewPackOrderStatusHistoryDAO(session, user.PlantNr, user.UserId)
	packOrderStatusDao := dal.NewPackOrderStatusDAO(session, user.PlantNr, user.UserId)
	record, err := dao.SelectOne(shipOrderId)
	if err != nil {
		_ = session.Rollback()
		return err
	}
	if record == nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("不存在指定记录!")
	}
	if record.ShipType != model.SHIP_TYPE_ADVANCE {
		_ = session.Rollback()
		return grmi.NewBusinessError("该发运单不是预发运单，不允许删除")
	}
	status, err := statusDao.SelectOne(shipOrderId)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("查询发运单状态失败, error:" + err.Error())
	}
	if status == nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("未查询到状态数据")
	}

	// 如果发运单已经开始 重置已进发运单的包装单状态
	if status.Status != model.SHIP_STATUS_PLANNED {
		scanDataLstLi, err := dataLstDao.Select([]grmi.Predicate{
			meta.ShipOrderDataLst_ShipOrderId.NewPredicate(grmi.Equal, shipOrderId),
		}, nil)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("查询发运单数据项失败, 错误:" + err.Error())
		}
		for _, scanData := range scanDataLstLi {
			packOrderStatus, err := packOrderStatusDao.SelectOne(scanData.PackOrderId)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("查询包装单状态数据失败，错误:" + err.Error())
			}
			if packOrderStatus == nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("包装单状态数据不存在， 包装单ID:" + scanData.PackOrderId)
			}
			maxPos, err := packOrderStatusHistoryDao.GetMaxPos(scanData.PackOrderId)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("查询包装单状态变更数据失败, 错误:" + err.Error())
			}
			packOrderStatusHistory := model.PackOrderStatusHistory{
				PackOrderId:      scanData.PackOrderId,
				Pos:              maxPos + 1,
				StatusChangeType: model.PACK_STATUS_CHANGE_TYPE_SHIP,
				FromStatus:       packOrderStatus.LoadStatus,
				ToStatus:         model.PACK_STATUS_PLANNED,
				ChangeTime:       grmi.DateTime(time.Now()),
				TriggerPara1:     "DELETE",
			}
			err = packOrderStatusHistoryDao.InsertOne(&packOrderStatusHistory)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("保存包装单状态变变更历史失败, 错误:" + err.Error())
			}
			packOrderStatus.LoadStatus = model.PACK_STATUS_PLANNED
			err = packOrderStatusDao.UpdateOne(packOrderStatus)
			if err != nil {
				_ = session.Rollback()
				return grmi.NewBusinessError("更新包装单加载状态失败, 错误:" + err.Error())
			}
		}
	}
	err = dao.DeleteOne(shipOrderId)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("删除原有发运单数据失败, error:" + err.Error())
	}
	err = itemDao.DeleteWhere([]grmi.Predicate{meta.ShipOrderItemLst_ShipOrderId.NewPredicate(grmi.Equal, shipOrderId)})
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("删除发运单子项失败, error:" + err.Error())
	}
	err = dataLstDao.DeleteWhere([]grmi.Predicate{meta.ShipOrderDataLst_ShipOrderId.NewPredicate(grmi.Equal, shipOrderId)})
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("删除发运单数据项失败, error:" + err.Error())
	}
	_ = session.Commit()
	return nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/jit/ShipOrderService.SelectOne
 *
 ******************************************************************************/
func (impl *ShipOrderServiceImplement) SelectOne(user *global.User, shipOrderId string) (*model.ShipOrder, error) {

	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "SelectOneShipOrder", "查询一个ShipOrder")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewShipOrderDAO(session, user.PlantNr, user.UserId)
	itemDao := dal.NewShipOrderItemLstDAO(session, user.PlantNr, user.UserId)
	packOrderItemDao := dal.NewPackOrderItemLstDAO(session, user.PlantNr, user.UserId)
	result, err := dao.SelectOne(shipOrderId)
	if err != nil {
		return nil, err
	}
	if result == nil {
		return nil, nil
	}
	lstLi, err := itemDao.SelectItemListWithData(shipOrderId)
	if err != nil {
		return nil, grmi.NewBusinessError("查询发运单子项失败, error:" + err.Error())
	}
	for index, lst := range lstLi {
		if lst.ShipOrderDataLst.PackOrderId != "" {
			packOrderItemLi, err := packOrderItemDao.Select([]grmi.Predicate{meta.PackOrderItemLst_PackOrderId.NewPredicate(grmi.Equal, lst.ShipOrderDataLst.PackOrderId),
				meta.PackOrderItemLst_Status.NewPredicate(grmi.Equal, model.PACK_STATUS_CLOSED)}, []grmi.Field{meta.PackOrderItemLst_Pos})
			if err != nil {
				return nil, grmi.NewBusinessError("查询包装单子项失败, error:" + err.Error())
			}
			lst.ShipOrderDataLst.PackOrderItemLi = packOrderItemLi
		} else {
			lst.ShipOrderDataLst.PackOrderItemLi = make([]model.PackOrderItemLst, 0)
		}
		lstLi[index] = lst
	}
	result.ItemDataLi = lstLi
	return result, nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/jit/ShipOrderService.UpdateOne
 *
 ******************************************************************************/
func (impl *ShipOrderServiceImplement) UpdateOne(user *global.User, entity *model.ShipOrder) error {

	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "UpdateOneShipOrder", "修改一个ShipOrder")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	if err := session.Begin(); err != nil {
		return grmi.NewBusinessError("开启事务失败, error:" + err.Error())
	}
	shipOrderDao := dal.NewShipOrderDAO(session, user.PlantNr, user.UserId)
	shipOrderItemDao := dal.NewShipOrderItemLstDAO(session, user.PlantNr, user.UserId)
	packTemplateDao := dal.NewPackTemplateDAO(session, user.PlantNr, user.UserId)
	shipOrderData, err := shipOrderDao.SelectOneWithStatus(entity.ShipOrderId)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("查询发运单数据失败, error:" + err.Error())
	}
	if shipOrderData == nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("该发运单不存在, 发运单ID:" + entity.ShipOrderId)
	}
	if shipOrderData.ShipOrderStatus.Status != model.SHIP_STATUS_PLANNED {
		_ = session.Rollback()
		return grmi.NewBusinessError("该发运单已经操作了，不允许修改")
	}
	if shipOrderData.ShipOrder.ShipType != model.SHIP_TYPE_ADVANCE {
		_ = session.Rollback()
		return grmi.NewBusinessError("该发运单不是预发运单，不允许修改")
	}

	itemLi := entity.ShipOrderItemLstLi
	entity.Operator = user.UserId
	err = shipOrderDao.UpdateOne(entity)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("保存发运单数据失败, error:" + err.Error())
	}
	err = shipOrderItemDao.DeleteWhere([]grmi.Predicate{meta.ShipOrderItemLst_ShipOrderId.NewPredicate(grmi.Equal, entity.ShipOrderId)})
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("删除原来的发运单子项失败， error:" + err.Error())
	}
	for index, item := range itemLi {
		packTemplate, err := packTemplateDao.SelectOne(item.PackTemplateId)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("查询发运单子项绑定的包装类型失败, error:" + err.Error())
		}
		if packTemplate == nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("发运单子项绑定的包装类型ID不存在， ID:" + item.PackTypeId)
		}
		if item.PackTypeId != packTemplate.PackTypeId {
			_ = session.Rollback()
			return grmi.NewBusinessError("包装模板ID和包装类型ID不匹配")
		}
		item.ShipOrderId = entity.ShipOrderId
		item.Pos = index + 1
		item.Status = model.SHIP_STATUS_PLANNED
		err = shipOrderItemDao.InsertOne(&item)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("保存发运单子项失败, error:" + err.Error())
		}
	}
	_ = session.Commit()
	return nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/jit/ShipOrderService.Insert
 *
 ******************************************************************************/
func (impl *ShipOrderServiceImplement) Insert(user *global.User, entities *[]model.ShipOrder) error {

	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "InsertShipOrder", "插入多个ShipOrder")

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

	for _, entity := range *entities {
		record, err := dao.SelectOne(entity.ShipOrderId)
		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/jit/ShipOrderService.Delete
 *
 ******************************************************************************/
func (impl *ShipOrderServiceImplement) Delete(user *global.User, entities *[]model.ShipOrder) error {

	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "DeleteShipOrder", "删除多个ShipOrder")

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

	for _, entity := range *entities {
		record, err := dao.SelectOne(entity.ShipOrderId)
		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/jit/ShipOrderService.Select
 *
 ******************************************************************************/
func (impl *ShipOrderServiceImplement) Select(user *global.User, urlParameters map[string]string) ([]model.ShipOrder, error) {

	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "SelectShipOrder", "查询ShipOrder")

	condition := DefaultConditionOfShipOrderAndPaging
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	predicates, err := condition.BuildPredicates(urlParameters)
	if err != nil {
		return nil, err
	}
	dao := dal.NewShipOrderDAO(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/jit/ShipOrderService.SelectAndPaging
 *
 ******************************************************************************/
func (impl *ShipOrderServiceImplement) SelectAndPaging(user *global.User, urlParameters map[string]string) (grmi.PagingResult, error) {

	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "SelectShipOrder", "查询ShipOrder")

	condition := DefaultConditionOfShipOrderAndPaging
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	predicates, err := condition.BuildPredicates(urlParameters)
	if err != nil {
		return grmi.EmptyPagingResult, err
	}
	statusStr, exist := urlParameters["status"]
	if !exist || statusStr == "" {
		statusStr = "0"
	}
	status, err := strconv.Atoi(statusStr)
	if err != nil {
		return grmi.EmptyPagingResult, grmi.NewBusinessError("查询状态参数解析错误， error:" + err.Error())
	}
	formalStatusStr, exist := urlParameters["status1"]
	if !exist || formalStatusStr == "" {
		formalStatusStr = "0"
	}
	formalStatus, err := strconv.Atoi(formalStatusStr)
	if err != nil {
		return grmi.EmptyPagingResult, grmi.NewBusinessError("查询翻车状态解析失败， error:" + err.Error())
	}
	dao := dal.NewShipOrderDAO(session, user.PlantNr, user.UserId)
	condition.Fill(urlParameters)
	result, err := dao.SelectAndPagingWithStatus(condition.Paging, predicates, condition.OrderByFields, status, formalStatus)
	if err != nil {
		return grmi.EmptyPagingResult, err
	}
	return result, nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/jit/ShipOrderService.Update
 *
 ******************************************************************************/
func (impl *ShipOrderServiceImplement) Update(user *global.User, entities *[]model.ShipOrder) error {

	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "UpdateShipOrder", "修改多个ShipOrder")

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

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

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

// CreateAdvanceShipOrder 根据模板创建发运单
func (impl *ShipOrderServiceImplement) CreateAdvanceShipOrder(user *global.User, shipTemplateId string, projectId string, plateNumber string, checkCarSet bool, planQty int) (err error) {
	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "CreateAdvanceShipOrderByTemplate", "通过发运模板创建预发运单")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	projectDao := meDal.NewProjectDAO(session, user.PlantNr, user.UserId)
	snrDao := baseDal.NewSnrDAO(session, user.PlantNr, user.UserId)
	shipOrderDao := dal.NewShipOrderDAO(session, user.PlantNr, user.UserId)
	shipOrderStatusDao := dal.NewShipOrderStatusDAO(session, user.PlantNr, user.UserId)
	shipOrderLstDao := dal.NewShipOrderItemLstDAO(session, user.PlantNr, user.UserId)
	if shipTemplateId != "" {
		// 校验模板数据
		templateDao := dal.NewShipTemplateDAO(session, user.PlantNr, user.UserId)

		template, err := templateDao.SelectOne(shipTemplateId)
		if err != nil {
			return grmi.NewBusinessError("查询发运模板数据失败, error:" + err.Error())
		}
		if template == nil {
			return grmi.NewBusinessError("不存在对应的模板, 模板ID:" + shipTemplateId)
		}
		tempLstDao := dal.NewShipTemplateItemLstDAO(session, user.PlantNr, user.UserId)
		lstLi, err := tempLstDao.Select([]grmi.Predicate{meta.ShipTemplateItemLst_ShipTemplateId.NewPredicate(grmi.Equal, template.ShipTemplateId)}, []grmi.Field{meta.ShipTemplateItemLst_Pos})
		if err != nil {
			return grmi.NewBusinessError("查询发运模板子项失败, error:" + err.Error())
		}
		if len(lstLi) == 0 {
			return grmi.NewBusinessError("该发运模板不存在任何子项, 模板ID:" + shipTemplateId)
		}
		// 获取project 数据
		projectId = template.ProjectId
		project, err := projectDao.SelectOne(projectId)
		if err != nil {
			return grmi.NewBusinessError("查询车型项目数据失败, error:" + err.Error())
		}
		if project == nil {
			return grmi.NewBusinessError("车型项目不存在, 项目ID:" + projectId)
		}
		// 开启事务
		if err = session.Begin(); err != nil {
			return grmi.NewBusinessError("开启事务失败， error:" + err.Error())
		}

		// 获取流水号
		shipOrderId, err := snrDao.GetNextSnr(project.ShipOrderSnr)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("获取发运单流水号失败， error:" + err.Error())
		}
		// 写入发运单 发运单状态 发运单子项数据
		shipOrder := model.ShipOrder{
			ShipOrderId:    shipOrderId,
			ShipTemplateId: shipTemplateId,
			ProjectId:      projectId,
			ShipType:       model.SHIP_TYPE_ADVANCE,
			PlanQty:        template.PlanQty,
			OpenTime:       grmi.DateTime(time.Now()),
			Operator:       user.UserId,
			PlateNumber:    plateNumber,
			CheckCarSet:    checkCarSet,
		}
		shipOrderStatus := model.ShipOrderStatus{
			ShipOrderId: shipOrderId,
			Status:      model.SHIP_STATUS_PLANNED,
			Status1:     model.SHIP_STATUS_PLANNED,
			Status2:     model.SHIP_STATUS_PLANNED,
		}
		err = shipOrderDao.InsertOne(&shipOrder)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("插入发运单失败, error:" + err.Error())
		}
		err = shipOrderStatusDao.InsertOne(&shipOrderStatus)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("插入发运单状态失败, error:" + err.Error())
		}
		pos := 1
		for _, lst := range lstLi {
			for i := 0; i < lst.PlanQty; i++ {
				shipOrderItemLst := model.ShipOrderItemLst{
					ShipOrderId:    shipOrderId,
					Pos:            pos,
					PackTypeId:     lst.PackTypeId,
					PackTemplateId: lst.PackTemplateId,
					Status:         model.SHIP_STATUS_PLANNED,
					PlanQty:        1,
				}
				err = shipOrderLstDao.InsertOne(&shipOrderItemLst)
				if err != nil {
					_ = session.Rollback()
					return grmi.NewBusinessError("插入发运单子项失败, error:" + err.Error())
				}
				pos++
			}
		}
	} else {
		project, err := projectDao.SelectOne(projectId)
		if err != nil {
			return grmi.NewBusinessError("查询车型项目数据失败, error:" + err.Error())
		}
		if project == nil {
			return grmi.NewBusinessError("车型项目不存在, 项目ID:" + projectId)
		}
		// 获取流水号
		shipOrderId, err := snrDao.GetNextSnr(project.ShipOrderSnr)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("获取发运单流水号失败， error:" + err.Error())
		}
		// 写入发运单 发运单状态 发运单子项数据
		shipOrder := model.ShipOrder{
			ShipOrderId:    shipOrderId,
			ShipTemplateId: shipTemplateId,
			ProjectId:      projectId,
			ShipType:       model.SHIP_TYPE_ADVANCE,
			PlanQty:        planQty,
			OpenTime:       grmi.DateTime(time.Now()),
			Operator:       user.UserId,
			PlateNumber:    plateNumber,
			CheckCarSet:    checkCarSet,
		}
		shipOrderStatus := model.ShipOrderStatus{
			ShipOrderId: shipOrderId,
			Status:      model.SHIP_STATUS_PLANNED,
			Status1:     model.SHIP_STATUS_PLANNED,
			Status2:     model.SHIP_STATUS_PLANNED,
		}
		err = shipOrderDao.InsertOne(&shipOrder)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("插入发运单失败, error:" + err.Error())
		}
		err = shipOrderStatusDao.InsertOne(&shipOrderStatus)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("插入发运单状态失败, error:" + err.Error())
		}
	}
	_ = session.Commit()
	return nil
}

// CreateAdvanceShipOrderByEdit 通过页面填写创建发运单
func (impl *ShipOrderServiceImplement) CreateAdvanceShipOrderByEdit(user *global.User, shipOrder *model.ShipOrder) (err error) {
	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "CreateAdvanceShipOrderByInput", "通过页面输入创建预发运单")
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	if err := session.Begin(); err != nil {
		return grmi.NewBusinessError("开启事务失败, error:" + err.Error())
	}
	shipOrderDao := dal.NewShipOrderDAO(session, user.PlantNr, user.UserId)
	shipOrderItemDao := dal.NewShipOrderItemLstDAO(session, user.PlantNr, user.UserId)
	shipOrderStatusDao := dal.NewShipOrderStatusDAO(session, user.PlantNr, user.UserId)
	packTemplateDao := dal.NewPackTemplateDAO(session, user.PlantNr, user.UserId)
	snrDao := baseDal.NewSnrDAO(session, user.PlantNr, user.UserId)
	projectDao := meDal.NewProjectDAO(session, user.PlantNr, user.UserId)
	itemLi := shipOrder.ShipOrderItemLstLi
	project, err := projectDao.SelectOne(shipOrder.ProjectId)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("获取车型项目数据失败, error:" + err.Error())
	}
	if project == nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("车型项目不存在, 车型项目ID:" + shipOrder.ProjectId)
	}
	shipOrderId, err := snrDao.GetNextSnr(project.ShipOrderSnr)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("生成发运单流水号失败, error:" + err.Error())
	}
	shipOrder.ShipOrderId = shipOrderId
	shipOrder.ShipType = model.SHIP_TYPE_ADVANCE
	shipOrder.Operator = user.UserId
	err = shipOrderDao.InsertOne(shipOrder)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("保存发运单数据失败, error:" + err.Error())
	}
	shipOrderStatus := model.ShipOrderStatus{
		ShipOrderId: shipOrderId,
		Status:      model.SHIP_STATUS_PLANNED,
	}
	err = shipOrderStatusDao.InsertOne(&shipOrderStatus)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("保存发运单状态数据失败, error:" + err.Error())
	}
	for index, item := range itemLi {
		packTemplate, err := packTemplateDao.SelectOne(item.PackTemplateId)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("查询发运单子项绑定的包装类型失败, error:" + err.Error())
		}
		if packTemplate == nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("发运单子项绑定的包装类型ID不存在， ID:" + item.PackTypeId)
		}
		if item.PackTypeId != packTemplate.PackTypeId {
			_ = session.Rollback()
			return grmi.NewBusinessError("包装模板ID和包装类型ID不匹配")
		}
		item.ShipOrderId = shipOrderId
		item.Pos = index + 1
		item.Status = model.SHIP_STATUS_PLANNED
		err = shipOrderItemDao.InsertOne(&item)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("保存发运单子项失败, error:" + err.Error())
		}
	}

	_ = session.Commit()
	return nil

}

// ScanBarCode 在发运环境扫描工单条码 通过工单条码获取包装单 自动配置发运单
func (impl *ShipOrderServiceImplement) ScanBarCode(user *global.User, barCode string, shipOrderId string, workPlaceNr int) (result *model.ShipResult, err error) {
	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "ScanBarCode", "在发运环节扫描工单条码")
	result = &model.ShipResult{}
	result.PLCResult = true
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	serialOrderDao := omDal.NewSerialOrderDAO(session, user.PlantNr, user.UserId)
	serialOrderStatusDao := omDal.NewSerialOrderStatusDAO(session, user.PlantNr, user.UserId)
	shipOrderDao := dal.NewShipOrderDAO(session, user.PlantNr, user.UserId)
	shipOrderLstDao := dal.NewShipOrderItemLstDAO(session, user.PlantNr, user.UserId)
	shipOrderDataLstDao := dal.NewShipOrderDataLstDAO(session, user.PlantNr, user.UserId)
	shipOrderStatusDao := dal.NewShipOrderStatusDAO(session, user.PlantNr, user.UserId)
	shipOrderStatusHistoryDao := dal.NewShipOrderStatusHistoryDAO(session, user.PlantNr, user.UserId)
	workPlaceConfigDao := baseDal.NewWorkPlaceConfigDAO(session, user.PlantNr, user.UserId)
	plantDao := baseDal.NewPlantDAO(session, user.UserId)
	plant, err := plantDao.SelectOne(user.PlantNr)
	if err != nil {
		return nil, grmi.NewBusinessError("查询工厂数据失败, 错误:" + err.Error())
	}
	if plant == nil {
		return nil, grmi.NewBusinessError("用户归属工厂不存在, 工厂ID:" + strconv.Itoa(user.PlantNr))
	}
	plantProject := plant.PlantProject
	var workPlaceConfig *baseModel.WorkPlaceConfig
	if plantProject == baseModel.PROJECT_ACURA {
		// 获取工位配置
		workPlaceConfigLi, err := workPlaceConfigDao.Select([]grmi.Predicate{baseMeta.WorkPlaceConfig_WorkPlaceNr.NewPredicate(grmi.Equal, workPlaceNr)}, nil)
		if err != nil {
			return nil, grmi.NewBusinessError("获取工位PLC放行配置失败, error:" + err.Error())
		}
		if len(workPlaceConfigLi) == 0 {
			return nil, grmi.NewBusinessError("未获取到工位PLC放行配置")
		}
		for _, config := range workPlaceConfigLi {
			if config.ParamName == "PLC" {
				workPlaceConfig = &config
			}
		}
		if workPlaceConfig == nil {
			return nil, grmi.NewBusinessError("未获取到工位PLC放行配置")
		}
		if workPlaceConfig.StrValue1 == "" ||
			workPlaceConfig.StrValue2 == "" ||
			workPlaceConfig.StrValue3 == "" ||
			workPlaceConfig.StrValue4 == "" {
			return nil, grmi.NewBusinessError("工位PLC放行配置不足")
		}
	}

	// 1. 通过barcode 工单条码查询包装单数据 并校验
	packLstDao := dal.NewPackOrderItemLstDAO(session, user.PlantNr, user.UserId)
	packOrderDao := dal.NewPackOrderDAO(session, user.PlantNr, user.UserId)
	packTemplateDao := dal.NewPackTemplateDAO(session, user.PlantNr, user.UserId)
	packTemplateLstDao := dal.NewPackTemplateItemLstDAO(session, user.PlantNr, user.UserId)
	packOrderItemLstLi, err := packLstDao.Select([]grmi.Predicate{meta.PackOrderItemLst_SerialOrderId.NewPredicate(grmi.Equal, barCode), meta.PackOrderItemLst_Status.NewPredicate(grmi.Equal, model.PACK_STATUS_CLOSED)}, nil)
	if len(packOrderItemLstLi) == 0 {
		return nil, grmi.NewBusinessError("未查询到该工单的包装单")
	} else if len(packOrderItemLstLi) > 1 {
		return nil, grmi.NewBusinessError("包含该工单的包装单大于一条，请排查, 工单ID:" + barCode)
	}
	packOrderId := packOrderItemLstLi[0].PackOrderId
	packOrder, err := packOrderDao.SelectOneWithStatus(packOrderId)
	if err != nil {
		return nil, grmi.NewBusinessError("查询包装单失败, error:" + err.Error())
	}
	if packOrder == nil {
		return nil, grmi.NewBusinessError("未查询到该工单的包装单头部数据, 包装单ID:" + packOrderId)
	}
	if packOrder.PackOrderStatus.Status != model.PACK_STATUS_CLOSED {
		return nil, grmi.NewBusinessError("该包装单的状态不是已完成, 包装单ID:" + packOrderId)
	}
	if packOrder.PackOrderStatus.LoadStatus == model.SHIP_STATUS_CLOSED || packOrder.PackOrderStatus.ShipStatus == model.SHIP_STATUS_CLOSED {
		return nil, grmi.NewBusinessError("该包装单已存在于发运单中, 包装单ID:" + packOrderId)
	}
	packOrderItemLstLi, err = packLstDao.Select([]grmi.Predicate{meta.PackOrderItemLst_PackOrderId.NewPredicate(grmi.Equal, packOrderId), meta.PackOrderItemLst_Status.NewPredicate(grmi.Equal, model.PACK_STATUS_CLOSED)}, nil)
	if err != nil {
		return nil, grmi.NewBusinessError("查询包装单子项失败, error:" + err.Error())
	}

	// 组装包装单内的物料数量对应关系 用于以后的匹配校验
	packOrderArtQtyMap := make(map[string]int)
	// 校验包装单内所有工单的状态
	for _, packOrderItem := range packOrderItemLstLi {
		// 对包装单内物料数量进行累加
		_, exist := packOrderArtQtyMap[packOrderItem.PartId]
		if !exist {
			packOrderArtQtyMap[packOrderItem.PartId] = 1
		} else {
			packOrderArtQtyMap[packOrderItem.PartId] = packOrderArtQtyMap[packOrderItem.PartId] + 1
		}
		serialOrder, err := serialOrderDao.SelectOne(packOrderItem.SerialOrderId)
		if err != nil {
			return nil, grmi.NewBusinessError("查询工单数据失败, error:" + err.Error())
		}
		if serialOrder == nil {
			return nil, grmi.NewBusinessError("工单不存在, 工单ID:" + packOrderItem.SerialOrderId)
		}
		if serialOrder.RepairFlag {
			return nil, grmi.NewBusinessError("工单是线上返修工单, 工单ID:" + packOrderItem.SerialOrderId)
		}
		if serialOrder.EOLCheck == omModel.EOL_STATUS_NG {
			return nil, grmi.NewBusinessError("工单电检不合格, 工单ID:" + packOrderItem.SerialOrderId)
		}
		if serialOrder.QualityCheck != baseModel.QualityCheck_STATUS_OK {
			return nil, grmi.NewBusinessError("工单目检结果不符合要求")
		}
		if serialOrder.GenerateFlag {
			return nil, grmi.NewBusinessError("该工单条码已作废, 工单ID:" + packOrderItem.SerialOrderId)
		}
		serialOrderStatus, err := serialOrderStatusDao.SelectOne(packOrderItem.SerialOrderId)
		if err != nil {
			return nil, grmi.NewBusinessError("查询工单状态失败, error:" + err.Error())
		}
		if serialOrderStatus == nil {
			return nil, grmi.NewBusinessError("工单状态数据不存在, 工单ID:" + packOrderItem.SerialOrderId)
		}
		if serialOrderStatus.Status != baseModel.WO_STATUS_FINISHED {
			return nil, grmi.NewBusinessError("工单状态不是已完成, 工单ID:" + packOrderItem.SerialOrderId)
		}
	}

	// 2. 校验该包装单是否已经存在发运单中
	shipDataLstDao := dal.NewShipOrderDataLstDAO(session, user.PlantNr, user.UserId)
	shipDataLstLi, err := shipDataLstDao.Select([]grmi.Predicate{meta.ShipOrderDataLst_PackOrderId.NewPredicate(grmi.Equal, packOrderId)}, nil)
	if err != nil {
		return nil, grmi.NewBusinessError("查询发运包装单数据项失败, error:" + err.Error())
	}
	if len(shipDataLstLi) != 0 {
		return nil, grmi.NewBusinessError("该发运单已经存在于发运单中，包装单ID:" + packOrderId)
	}
	// 3. 校验发运单数据
	shipOrder, err := shipOrderDao.SelectOneWithStatus(shipOrderId)
	if err != nil {
		return nil, grmi.NewBusinessError("查询发运单数据失败, error:" + err.Error())
	}
	if shipOrder == nil {
		return nil, grmi.NewBusinessError("该发运单不存在, 发运单ID:" + shipOrderId)
	}
	if shipOrder.ShipOrderStatus.Status >= model.SHIP_STATUS_CLOSED {
		return nil, grmi.NewBusinessError("该发运单状态不支持该操作, 发运单ID:" + shipOrderId)
	}

	//if packOrder.PackOrder.ShortPackToggle {
	//	if shipOrder.ShipOrder.ShipType != model.SHIP_TYPE_ADVANCE || shipOrder.ShipOrder.ShipTemplateId != "" {
	//		return nil, grmi.NewBusinessError("该包装单为短包, 不能进入该发运单,包装单ID:" + packOrderId)
	//	}
	//}
	// 开启事务
	if err = session.Begin(); err != nil {
		return nil, grmi.NewBusinessError("开启事务失败, error:" + err.Error())
	}
	// 记录包状态的状态变化
	packOrderStatusDao := dal.NewPackOrderStatusDAO(session, user.PlantNr, user.UserId)
	packOrderStatusHistoryDao := dal.NewPackOrderStatusHistoryDAO(session, user.PlantNr, user.UserId)
	maxPos, err := packOrderStatusHistoryDao.GetMaxPos(packOrder.PackOrder.PackOrderId)
	if err != nil {
		_ = session.Rollback()
		return nil, grmi.NewBusinessError("获取包装单状态变更位置失败, error:" + err.Error())
	}
	// 预发运单 记录LoadStatus 正式发运单记录 ShipStatus
	if shipOrder.ShipOrder.ShipType == model.SHIP_TYPE_ADVANCE {
		packOrderStatusHistory := model.PackOrderStatusHistory{
			PackOrderId:      packOrder.PackOrder.PackOrderId,
			Pos:              maxPos + 1,
			StatusChangeType: model.PACK_STATUS_CHANGE_TYPE_SHIP,
			FromStatus:       packOrder.PackOrderStatus.LoadStatus,
			ToStatus:         model.PACK_STATUS_CLOSED,
			ChangeTime:       grmi.DateTime(time.Now()),
			TriggerPara1:     model.SHIP_TYPE_ADVANCE,
		}
		err = packOrderStatusHistoryDao.InsertOne(&packOrderStatusHistory)
		if err != nil {
			_ = session.Rollback()
			return nil, grmi.NewBusinessError("保存包装单状态变更记录失败, error:" + err.Error())
		}
		packOrder.PackOrderStatus.LoadStatus = model.PACK_STATUS_CLOSED
		err = packOrderStatusDao.UpdateOne(&packOrder.PackOrderStatus)
		if err != nil {
			_ = session.Rollback()
			return nil, grmi.NewBusinessError("更新包装单状态失败, error:" + err.Error())
		}
	} else {
		packOrderStatusHistory := model.PackOrderStatusHistory{
			PackOrderId:      packOrder.PackOrder.PackOrderId,
			Pos:              maxPos + 1,
			StatusChangeType: model.PACK_STATUS_CHANGE_TYPE_SHIP,
			FromStatus:       packOrder.PackOrderStatus.ShipStatus,
			ToStatus:         model.PACK_STATUS_CLOSED,
			ChangeTime:       grmi.DateTime(time.Now()),
			TriggerPara1:     model.SHIP_TYPE_FORMAL,
		}
		err = packOrderStatusHistoryDao.InsertOne(&packOrderStatusHistory)
		if err != nil {
			_ = session.Rollback()
			return nil, grmi.NewBusinessError("保存包装单状态变更记录失败, error:" + err.Error())
		}
		packOrder.PackOrderStatus.ShipStatus = model.PACK_STATUS_CLOSED
		err = packOrderStatusDao.UpdateOne(&packOrder.PackOrderStatus)
		if err != nil {
			_ = session.Rollback()
			return nil, grmi.NewBusinessError("更新包装单状态失败, error:" + err.Error())
		}
	}
	// 如果是预发运单, 且没有指定发运模板
	if shipOrder.ShipOrder.ShipType == model.SHIP_TYPE_ADVANCE && shipOrder.ShipOrder.ShipTemplateId == "" {
		if shipOrder.ShipOrder.ProjectId != packOrder.ProjectId {
			_ = session.Rollback()
			return nil, grmi.NewBusinessError("包装项目和发运单项目不一致")
		}
		// 如果发运单已经进行扫描且需要校验同一派生
		if shipOrder.CheckCarSet && shipOrder.ShipOrderStatus.Status == model.SHIP_STATUS_RUNNING {
			scanDataLi, err := shipOrderDataLstDao.Select([]grmi.Predicate{
				meta.ShipOrderDataLst_ShipOrderId.NewPredicate(grmi.Equal, shipOrderId),
			}, []grmi.Field{meta.ShipOrderDataLst_ItemPos})
			if err != nil {
				_ = session.Rollback()
				return nil, grmi.NewBusinessError("查询已经扫描的发运数据项失败，错误:" + err.Error())
			}
			if len(scanDataLi) != 0 {
				scanData := scanDataLi[0]
				scanedPackOrderLstLi, err := packLstDao.Select([]grmi.Predicate{
					meta.PackOrderItemLst_PackOrderId.NewPredicate(grmi.Equal, scanData.PackOrderId),
					meta.PackOrderItemLst_Status.NewPredicate(grmi.Equal, model.PACK_STATUS_CLOSED),
				}, nil)
				if err != nil {
					_ = session.Rollback()
					return nil, grmi.NewBusinessError("查询已扫描包装单包装项数据失败, 错误:" + err.Error())
				}
				// 组装包装单内的物料数量对应关系 用于以后的匹配校验
				scanPackOrderArtQtyMap := make(map[string]int)
				for _, packOrderItem := range scanedPackOrderLstLi {
					// 对包装单内物料数量进行累加
					_, exist := scanPackOrderArtQtyMap[packOrderItem.PartId]
					if !exist {
						scanPackOrderArtQtyMap[packOrderItem.PartId] = 1
					} else {
						scanPackOrderArtQtyMap[packOrderItem.PartId] = scanPackOrderArtQtyMap[packOrderItem.PartId] + 1
					}
				}
				// 比对当前包装单的物料数据是否和之前的一样
				for scanArt, scanQty := range scanPackOrderArtQtyMap {
					currentQty, exist := packOrderArtQtyMap[scanArt]
					if exist {
						if scanQty != currentQty {
							_ = session.Rollback()
							return nil, grmi.NewBusinessError("当前包装单和之前扫描的包装单物料信息不匹配")
						}
					} else {
						_ = session.Rollback()
						return nil, grmi.NewBusinessError("当前包装单和之前扫描的包装单物料信息不匹配")
					}
				}
			}
		}
		// 进行扫码处理
		maxPos, err = shipOrderLstDao.GetMaxPos(shipOrderId)
		if err != nil {
			_ = session.Rollback()
			return nil, grmi.NewBusinessError("获取发运单子项位置数据失败, error:" + err.Error())
		}
		shipOrderItem := model.ShipOrderItemLst{
			ShipOrderId:    shipOrderId,
			Pos:            maxPos + 1,
			PackTypeId:     packOrder.PackOrder.PackTypeId,
			PackTemplateId: packOrder.PackOrder.PackTemplateId,
			Status:         model.SHIP_STATUS_CLOSED,
			PlanQty:        1,
			ActQty:         1,
		}
		err = shipOrderLstDao.InsertOne(&shipOrderItem)
		if err != nil {
			_ = session.Rollback()
			return nil, grmi.NewBusinessError("保存发运单子项失败, error:" + err.Error())
		}
		//	写入扫描记录
		shipOrderDataLst := model.ShipOrderDataLst{
			ShipOrderId: shipOrderId,
			PackOrderId: packOrderId,
			ItemPos:     shipOrderItem.Pos,
			PackTypeId:  packOrder.PackOrder.PackTypeId,
			Status:      model.SHIP_STATUS_CLOSED,
			PlanQty:     packOrder.PackOrder.PlanQty,
			ActQty:      packOrder.PackOrder.ActQty,
		}
		err = shipOrderDataLstDao.InsertOne(&shipOrderDataLst)
		if err != nil {
			_ = session.Rollback()
			return nil, grmi.NewBusinessError("写入发运单数据项失败, error:" + err.Error())
		}
		var isClosed = false
		status := model.SHIP_STATUS_RUNNING
		shipOrder.ShipOrder.ActQty += 1
		shipOrder.ShipOrder.Operator = user.UserId
		if shipOrder.ShipOrder.PlanQty == shipOrder.ShipOrder.ActQty {
			isClosed = true
			shipOrder.ShipOrder.CloseTime = grmi.DateTime(time.Now())
			status = model.SHIP_STATUS_CLOSED
		}
		err = shipOrderDao.UpdateOne(&shipOrder.ShipOrder)
		if err != nil {
			_ = session.Rollback()
			return nil, grmi.NewBusinessError("更新发运单数据失败， error:" + err.Error())
		}
		if status != shipOrder.ShipOrderStatus.Status {
			maxPos, err = shipOrderStatusHistoryDao.GetMaxPos(shipOrderId)
			if err != nil {
				_ = session.Rollback()
				return nil, grmi.NewBusinessError("获取发运单状态变更历史位置失败, error:" + err.Error())
			}
			shipOrderStatusHistory := model.ShipOrderStatusHistory{
				ShipOrderId:      shipOrderId,
				Pos:              maxPos + 1,
				StatusChangeType: model.SHIP_STATUS_CHANGE_TYPE_SHIP,
				FromStatus:       shipOrder.ShipOrderStatus.Status,
				ToStatus:         status,
				ChangeTime:       grmi.DateTime(time.Now()),
			}
			err = shipOrderStatusHistoryDao.InsertOne(&shipOrderStatusHistory)
			if err != nil {
				_ = session.Rollback()
				return nil, grmi.NewBusinessError("保存发运单状态变更历史失败, error:" + err.Error())
			}
			shipOrder.ShipOrderStatus.Status = status
			err = shipOrderStatusDao.UpdateOne(&shipOrder.ShipOrderStatus)
			if err != nil {
				_ = session.Rollback()
				return nil, grmi.NewBusinessError("更新发运单状态变更历史失败, error:" + err.Error())
			}
		}
		_ = session.Commit()
		result.Message = "扫描完成，扫描包装单ID:" + packOrder.PackOrder.PackOrderId + ", 当前发运单ID:" + shipOrderId
		result.IsClosed = isClosed
		if plantProject == baseModel.PROJECT_ACURA {
			err = impl.PermitTrough(workPlaceConfig)
			if err != nil {
				result.PLCResult = false
				result.PLCMessage = err.Error()
			} else {
				result.PLCResult = true
			}
		}

		return result, nil
	} else {
		shipOrderLstLi, err := shipOrderLstDao.Select([]grmi.Predicate{meta.ShipOrderItemLst_ShipOrderId.NewPredicate(grmi.Equal, shipOrderId), meta.ShipOrderItemLst_Status.NewPredicate(grmi.LessThen, model.SHIP_STATUS_CLOSED)}, []grmi.Field{meta.ShipOrderItemLst_Pos})
		if err != nil {
			return nil, grmi.NewBusinessError("查询发运单子项失败, error:" + err.Error())
		}

		if len(shipOrderLstLi) == 0 {
			return nil, grmi.NewBusinessError("发运单未获取到需要发运的子项")
		}
		// 按倒叙进行发运 扫描最后一个包装
		shipOrderLst := shipOrderLstLi[len(shipOrderLstLi)-1]
		// 不适用包装单上的派生ID 直接校验包装单里座椅数据

		packTemplate, err := packTemplateDao.SelectOne(shipOrderLst.PackTemplateId)
		if err != nil {
			_ = session.Rollback()
			return nil, grmi.NewBusinessError("查询包装模板数据失败, error:" + err.Error())
		}
		if packTemplate == nil {
			_ = session.Rollback()
			return nil, grmi.NewBusinessError("不存在对应的包装模板, 包装模板ID:" + shipOrderLst.PackTemplateId)
		}
		packTemplateItemLstLi, err := packTemplateLstDao.Select([]grmi.Predicate{meta.PackTemplateItemLst_PackTemplateId.NewPredicate(grmi.Equal, shipOrderLst.PackTemplateId)}, []grmi.Field{meta.PackTemplateItemLst_Pos})
		if err != nil {
			_ = session.Rollback()
			return nil, grmi.NewBusinessError("查询包装模板项数据失败， error:" + err.Error())
		}
		// 组件包装模板MAP
		packTemplateArtMap := make(map[string]int)
		for _, packTemplateItem := range packTemplateItemLstLi {
			_, exist := packTemplateArtMap[packTemplateItem.PartId]
			if !exist {
				packTemplateArtMap[packTemplateItem.PartId] = 1
			} else {
				packTemplateArtMap[packTemplateItem.PartId] += 1
			}
		}
		// 比对模板MAP与包装单MAP
		var mapMatchSign = true
		for artId, qty := range packTemplateArtMap {
			orderQty, exist := packOrderArtQtyMap[artId]
			// 如果模板中的总成 包装单中不存在 则直接跳出当前包装模板比对
			if !exist {
				mapMatchSign = false
				break
			}
			// 如果模板中的总成数量和包装单中数量不一致 直接跳出比对
			if qty != orderQty {
				mapMatchSign = false
				break
			}
		}
		if mapMatchSign {
			// 扫描数量加1
			shipOrderLst.ActQty += 1
			// 判断发运子项是否完成 修改状态 并保存数据
			if shipOrderLst.PlanQty == shipOrderLst.ActQty {
				shipOrderLst.Status = model.SHIP_STATUS_CLOSED
			} else {
				shipOrderLst.Status = model.SHIP_STATUS_RUNNING
			}
			err = shipOrderLstDao.UpdateOne(&shipOrderLst)
			if err != nil {
				_ = session.Rollback()
				return nil, grmi.NewBusinessError("更新发运单子项数据失败, error:" + err.Error())
			}
			// 更新发运单头部数据
			shipOrder.ShipOrder.ActQty += 1
			//	写入扫描记录
			shipOrderDataLst := model.ShipOrderDataLst{
				ShipOrderId: shipOrderId,
				PackOrderId: packOrderId,
				ItemPos:     shipOrderLst.Pos,
				PackTypeId:  shipOrderLst.PackTypeId,
				Status:      model.SHIP_STATUS_CLOSED,
				PlanQty:     packOrder.PackOrder.PlanQty,
				ActQty:      packOrder.PackOrder.ActQty,
			}
			err = shipOrderDataLstDao.InsertOne(&shipOrderDataLst)
			if err != nil {
				_ = session.Rollback()
				return nil, grmi.NewBusinessError("写入发运单数据项失败, error:" + err.Error())
			}
			// 关闭发运单
			if shipOrder.ShipOrder.ActQty == shipOrder.ShipOrder.PlanQty {
				maxPos, err := shipOrderStatusHistoryDao.GetMaxPos(shipOrderId)
				if err != nil {
					_ = session.Rollback()
					return nil, grmi.NewBusinessError("获取发运单状态变更历史位置数据失败, error:" + err.Error())
				}
				shipOrderStatusHistory := model.ShipOrderStatusHistory{
					ShipOrderId: shipOrderId,
					Pos:         maxPos + 1,
					FromStatus:  shipOrder.ShipOrderStatus.Status,
					ToStatus:    model.SHIP_STATUS_CLOSED,
					ChangeTime:  grmi.DateTime(time.Now()),
				}
				err = shipOrderStatusHistoryDao.InsertOne(&shipOrderStatusHistory)
				if err != nil {
					_ = session.Rollback()
					return nil, grmi.NewBusinessError("写入发运单状态变更历史失败, error:" + err.Error())
				}
				shipOrder.ShipOrderStatus.Status = model.SHIP_STATUS_CLOSED
				err = shipOrderStatusDao.UpdateOne(&shipOrder.ShipOrderStatus)
				if err != nil {
					_ = session.Rollback()
					return nil, grmi.NewBusinessError("更新发运单状态失败, error:" + err.Error())
				}
				shipOrder.ShipOrder.CloseTime = grmi.DateTime(time.Now())
				shipOrder.ShipOrder.Operator = user.UserId
				err = shipOrderDao.UpdateOne(&shipOrder.ShipOrder)
				if err != nil {
					_ = session.Rollback()
					return nil, grmi.NewBusinessError("更新发运单数据失败, error:" + err.Error())
				}
				_ = session.Commit()
				if plantProject == baseModel.PROJECT_ACURA {
					err = impl.PermitTrough(workPlaceConfig)
					if err != nil {
						result.PLCResult = false
						result.PLCMessage = err.Error()
					} else {
						result.PLCResult = true
					}
				}
				result.Message = "扫描完成并关闭包装单，扫描包装单ID:" + packOrder.PackOrder.PackOrderId + ", 当前发运单ID:" + shipOrderId
				result.IsClosed = true
				return result, nil
			} else {
				// 将发运单状态置为操作中
				if shipOrder.ShipOrderStatus.Status != model.SHIP_STATUS_RUNNING {
					maxPos, err := shipOrderStatusHistoryDao.GetMaxPos(shipOrderId)
					if err != nil {
						_ = session.Rollback()
						return nil, grmi.NewBusinessError("获取发运单状态变更历史位置数据失败, error:" + err.Error())
					}
					shipOrderStatusHistory := model.ShipOrderStatusHistory{
						ShipOrderId: shipOrderId,
						Pos:         maxPos + 1,
						FromStatus:  shipOrder.ShipOrderStatus.Status,
						ToStatus:    model.SHIP_STATUS_RUNNING,
						ChangeTime:  grmi.DateTime(time.Now()),
					}
					err = shipOrderStatusHistoryDao.InsertOne(&shipOrderStatusHistory)
					if err != nil {
						_ = session.Rollback()
						return nil, grmi.NewBusinessError("写入发运单状态变更历史失败, error:" + err.Error())
					}
					shipOrder.ShipOrderStatus.Status = model.SHIP_STATUS_RUNNING
					err = shipOrderStatusDao.UpdateOne(&shipOrder.ShipOrderStatus)
					if err != nil {
						_ = session.Rollback()
						return nil, grmi.NewBusinessError("更新发运单状态失败, error:" + err.Error())
					}
					shipOrder.ShipOrder.Operator = user.UserId
					err = shipOrderDao.UpdateOne(&shipOrder.ShipOrder)
					if err != nil {
						_ = session.Rollback()
						return nil, grmi.NewBusinessError("更新发运单数据失败, error:" + err.Error())
					}
				} else {
					shipOrder.ShipOrder.Operator = user.UserId
					err = shipOrderDao.UpdateOne(&shipOrder.ShipOrder)
					if err != nil {
						_ = session.Rollback()
						return nil, grmi.NewBusinessError("更新发运单数据失败, error:" + err.Error())
					}
				}
				_ = session.Commit()
				result.Message = "扫描完成，扫描包装单ID:" + packOrder.PackOrder.PackOrderId + ", 当前发运单ID:" + shipOrderId
				result.IsClosed = false
				if plantProject == baseModel.PROJECT_ACURA {
					err = impl.PermitTrough(workPlaceConfig)
					if err != nil {
						result.PLCResult = false
						result.PLCMessage = err.Error()
					} else {
						result.PLCResult = true
					}
				}
				return result, nil
			}

		} else {
			_ = session.Rollback()
			return nil, grmi.NewBusinessError("当前包装未能匹配上对应顺序的正确派生")
		}
	}
}

// ChangeAdvanceToFormal 从预处理发运单翻车成正式发运单
func (impl *ShipOrderServiceImplement) ChangeAdvanceToFormal(user *global.User, advanceShipOrderId string, formalShipOrderId string) error {
	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "ChangeAdvanceToFormal", "预发运单翻车成正式发运单")
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	shipOrderDao := dal.NewShipOrderDAO(session, user.PlantNr, user.UserId)
	shipOrderLstDao := dal.NewShipOrderItemLstDAO(session, user.PlantNr, user.UserId)
	shipOrderDataLstDao := dal.NewShipOrderDataLstDAO(session, user.PlantNr, user.UserId)
	shipOrderStatusDao := dal.NewShipOrderStatusDAO(session, user.PlantNr, user.UserId)
	shipOrderStatusHistoryDao := dal.NewShipOrderStatusHistoryDAO(session, user.PlantNr, user.UserId)
	packOrderStatusDao := dal.NewPackOrderStatusDAO(session, user.PlantNr, user.UserId)
	packOrderStatusHistoryDao := dal.NewPackOrderStatusHistoryDAO(session, user.PlantNr, user.UserId)
	packOrderItemDao := dal.NewPackOrderItemLstDAO(session, user.PlantNr, user.UserId)
	productFamilyRelateDao := meDal.NewProductFamilyRelateDAO(session, user.PlantNr, user.UserId)
	// 1. 校验预发运单
	advanceShipOrder, err := shipOrderDao.SelectOneWithStatus(advanceShipOrderId)
	if err != nil {
		return grmi.NewBusinessError("查询发运单数据失败, error:" + err.Error())
	}
	if advanceShipOrder == nil {
		return grmi.NewBusinessError("预发运单不存在, 发运单ID:" + advanceShipOrderId)
	}
	if advanceShipOrder.ShipOrderStatus.Status != model.SHIP_STATUS_CLOSED {
		return grmi.NewBusinessError("预发运单未关闭,发运单ID:" + advanceShipOrderId)
	}
	if advanceShipOrder.ShipOrder.ShipType != model.SHIP_TYPE_ADVANCE {
		return grmi.NewBusinessError("操作的预发运单类型错误, 发运单ID:" + advanceShipOrderId)
	}
	// 2. 校验正式发运单
	formalShipOrder, err := shipOrderDao.SelectOneWithStatus(formalShipOrderId)
	if err != nil {
		return grmi.NewBusinessError("查询正式发运单失败, error:" + err.Error())
	}
	if formalShipOrder == nil {
		return grmi.NewBusinessError("不存在对应的正式发运单, 发运单ID:" + formalShipOrderId)
	}
	if formalShipOrder.ShipOrder.ShipType != model.SHIP_TYPE_FORMAL {
		return grmi.NewBusinessError("操作的正式发运单类型错误, 发运单ID:" + formalShipOrderId)
	}
	if formalShipOrder.ShipOrderStatus.Status != model.SHIP_STATUS_PLANNED {
		return grmi.NewBusinessError("该正式发运单已在操作中, 发运单ID:" + formalShipOrderId)
	}
	// 3. 比对两个发运单的子项的数据
	advanceShipOrderDataLi, err := shipOrderDataLstDao.Select([]grmi.Predicate{
		meta.ShipOrderDataLst_ShipOrderId.NewPredicate(grmi.Equal, advanceShipOrderId),
	}, []grmi.Field{meta.ShipOrderDataLst_ItemPos})
	if err != nil {
		return grmi.NewBusinessError("查询预发运单数据项失败, 错误：" + err.Error())
	}
	advanceShipOrderDataMap := make(map[string]int)
	for _, shipOrderData := range advanceShipOrderDataLi {
		packOrderItemLi, err := packOrderItemDao.Select([]grmi.Predicate{
			meta.PackOrderItemLst_PackOrderId.NewPredicate(grmi.Equal, shipOrderData.PackOrderId),
			meta.PackOrderItemLst_Status.NewPredicate(grmi.Equal, model.PACK_STATUS_CLOSED),
		}, []grmi.Field{meta.PackOrderItemLst_PartId})
		if err != nil {
			return grmi.NewBusinessError("查询包装单子项失败, 错误：" + err.Error())
		}
		var key string
		for _, packOrderItem := range packOrderItemLi {
			key += packOrderItem.PartId
		}
		_, exist := advanceShipOrderDataMap[key]
		if !exist {
			advanceShipOrderDataMap[key] = 1
		} else {
			advanceShipOrderDataMap[key] += 1
		}
	}
	fmt.Println("advanceShipOrderDataMap:", advanceShipOrderDataMap)
	formalShipOrderItemLi, err := shipOrderLstDao.Select([]grmi.Predicate{meta.ShipOrderItemLst_ShipOrderId.NewPredicate(grmi.Equal, formalShipOrderId)}, []grmi.Field{meta.ShipOrderItemLst_Pos})
	if err != nil {
		return grmi.NewBusinessError("查询正式发运单子项失败, error:" + err.Error())
	}
	formalShipOrderCarSetMap := make(map[string]int)
	for _, shipOrderItem := range formalShipOrderItemLi {
		_, exist := formalShipOrderCarSetMap[shipOrderItem.PackTemplateId]
		if !exist {
			formalShipOrderCarSetMap[shipOrderItem.PackTemplateId] = 1
		} else {
			formalShipOrderCarSetMap[shipOrderItem.PackTemplateId] += 1
		}
	}
	formalShipOrderDataMap := make(map[string]int)
	for productFamilyId, qty := range formalShipOrderCarSetMap {
		productLi, err := productFamilyRelateDao.SelectPackProductByFamilyId(formalShipOrder.ProjectId, productFamilyId)
		if err != nil {
			return grmi.NewBusinessError("查询派生打包总成数据失败, 错误：" + err.Error())
		}
		var key string
		for _, product := range productLi {
			key += product.ProductId
		}
		_, exist := formalShipOrderDataMap[key]
		if !exist {
			formalShipOrderDataMap[key] = qty
		} else {
			formalShipOrderDataMap[key] += qty
		}

	}
	for key, qty := range formalShipOrderDataMap {
		advanceQty, exist := advanceShipOrderDataMap[key]
		if !exist {
			fmt.Println("key:", key)
			return grmi.NewBusinessError("两个发运单发运子项不匹配, 包装模板不匹配")
		}
		if qty != advanceQty {
			return grmi.NewBusinessError("两个发运单发运子项不匹配, 包装模板数量不匹配")
		}
	}
	//advanceShipOrderItemLi, err := shipOrderLstDao.Select([]grmi.Predicate{meta.ShipOrderItemLst_ShipOrderId.NewPredicate(grmi.Equal, advanceShipOrderId), meta.ShipOrderItemLst_Status.NewPredicate(grmi.Equal, model.SHIP_STATUS_CLOSED)}, []grmi.Field{meta.ShipOrderItemLst_Pos})
	//if err != nil {
	//	return grmi.NewBusinessError("查询预发运单子项失败, error:" + err.Error())
	//}
	//formalShipOrderItemLi, err := shipOrderLstDao.Select([]grmi.Predicate{meta.ShipOrderItemLst_ShipOrderId.NewPredicate(grmi.Equal, formalShipOrderId)}, []grmi.Field{meta.ShipOrderItemLst_Pos})
	//if err != nil {
	//	return grmi.NewBusinessError("查询正式发运单子项失败, error:" + err.Error())
	//}
	//advancePackTemplateMap := make(map[string]int)
	//for _, advanceShipOrderItem := range advanceShipOrderItemLi {
	//	_, exist := advancePackTemplateMap[advanceShipOrderItem.PackTemplateId]
	//	if exist {
	//		advancePackTemplateMap[advanceShipOrderItem.PackTemplateId] += advanceShipOrderItem.PlanQty
	//	}
	//	advancePackTemplateMap[advanceShipOrderItem.PackTemplateId] = advanceShipOrderItem.PlanQty
	//}
	//formalPackTemplateMap := make(map[string]int)
	//for _, formalShipOrderItem := range formalShipOrderItemLi {
	//	_, exist := formalPackTemplateMap[formalShipOrderItem.PackTemplateId]
	//	if exist {
	//		formalPackTemplateMap[formalShipOrderItem.PackTemplateId] += formalShipOrderItem.PlanQty
	//	}
	//	formalPackTemplateMap[formalShipOrderItem.PackTemplateId] = formalShipOrderItem.PlanQty
	//}
	//for packTemplateId, qty := range formalPackTemplateMap {
	//	advanceQty, exist := advancePackTemplateMap[packTemplateId]
	//	if !exist {
	//		return grmi.NewBusinessError("两个发运单发运子项不匹配, 包装模板不匹配, 包装模板ID:" + packTemplateId)
	//	}
	//	if qty != advanceQty {
	//		return grmi.NewBusinessError("两个发运单发运子项不匹配, 包装模板数量不匹配, 包装模板ID:" + packTemplateId)
	//	}
	//}
	//	4. 对比通过 进行数据映射
	if err = session.Begin(); err != nil {
		return grmi.NewBusinessError("开启事务失败, error:" + err.Error())
	}
	formalShipOrder.ShipOrder.ActQty = advanceShipOrder.ShipOrder.ActQty
	formalShipOrder.ShipOrder.Operator = advanceShipOrder.ShipOrder.Operator
	formalShipOrder.ShipOrder.CloseTime = advanceShipOrder.ShipOrder.CloseTime
	formalShipOrder.ShipOrder.SourceId = advanceShipOrder.ShipOrder.ShipOrderId
	err = shipOrderDao.UpdateOne(&formalShipOrder.ShipOrder)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("更新正式发运单数据失败, error:" + err.Error())
	}
	maxPos, err := shipOrderStatusHistoryDao.GetMaxPos(formalShipOrderId)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("获取发运单状态变更历史位置失败, error:" + err.Error())
	}
	statusHistory := model.ShipOrderStatusHistory{
		ShipOrderId: formalShipOrderId,
		Pos:         maxPos + 1,
		FromStatus:  formalShipOrder.ShipOrderStatus.Status,
		ToStatus:    model.SHIP_STATUS_CLOSED,
		ChangeTime:  grmi.DateTime(time.Now()),
	}
	err = shipOrderStatusHistoryDao.InsertOne(&statusHistory)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("插入发运单状态变更历史失败, error:" + err.Error())
	}
	formalShipOrder.ShipOrderStatus.Status = model.SHIP_STATUS_CLOSED
	err = shipOrderStatusDao.UpdateOne(&formalShipOrder.ShipOrderStatus)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("更新正式发运单状态失败, error:" + err.Error())
	}
	advanceShipOrder.ShipOrder.FormalShipOrderId = formalShipOrderId
	err = shipOrderDao.UpdateOne(&advanceShipOrder.ShipOrder)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("更新预发运单数据失败, error:" + err.Error())
	}
	for _, formalShipOrderItem := range formalShipOrderItemLi {
		formalShipOrderItem.ActQty = formalShipOrderItem.PlanQty
		formalShipOrderItem.Status = model.SHIP_STATUS_CLOSED
		err = shipOrderLstDao.UpdateOne(&formalShipOrderItem)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("更新正式发运单子项失败, error:" + err.Error())
		}
	}
	advanceDataLstLi, err := shipOrderDataLstDao.Select([]grmi.Predicate{meta.ShipOrderDataLst_ShipOrderId.NewPredicate(grmi.Equal, advanceShipOrderId)}, []grmi.Field{meta.ShipOrderDataLst_CreateTime})
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("查询预发运单数据项失败, error:" + err.Error())
	}
	// 写入正式发运当问题项 同时更新包装单上ShipStatus
	for _, advanceDataLst := range advanceDataLstLi {
		dataLst := model.ShipOrderDataLst{
			ShipOrderId: formalShipOrderId,
			PackOrderId: advanceDataLst.PackOrderId,
			ItemPos:     advanceDataLst.ItemPos,
			PackTypeId:  advanceDataLst.PackTypeId,
			Status:      advanceDataLst.Status,
			PlanQty:     advanceDataLst.PlanQty,
			ActQty:      advanceDataLst.ActQty,
		}
		err = shipOrderDataLstDao.InsertOne(&dataLst)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("写入正式发运单数据项失败, error:" + err.Error())
		}
		packOrderStatus, err := packOrderStatusDao.SelectOne(advanceDataLst.PackOrderId)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("查询发运单状态数据失败, 错误:" + err.Error())
		}
		if packOrderStatus == nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("预发运单中发运子项包装单状态数据不存在, 包装单ID:" + advanceDataLst.PackOrderId)
		}
		maxPos, err = packOrderStatusHistoryDao.GetMaxPos(advanceDataLst.PackOrderId)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("获取包装单状态变更数据失败, 错误:" + err.Error())
		}
		packOrderStatusHistory := model.PackOrderStatusHistory{
			PackOrderId:      packOrderStatus.PackOrderId,
			Pos:              maxPos + 1,
			StatusChangeType: model.PACK_STATUS_CHANGE_TYPE_SHIP,
			FromStatus:       packOrderStatus.ShipStatus,
			ToStatus:         model.PACK_STATUS_CLOSED,
			ChangeTime:       grmi.DateTime(time.Now()),
			TriggerPara1:     model.SHIP_STATUS_CHANGE_TYPE_TRANSFER,
		}
		err = packOrderStatusHistoryDao.InsertOne(&packOrderStatusHistory)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("保存包装单状态变更历史失败, 错误:" + err.Error())
		}
		packOrderStatus.ShipStatus = model.PACK_STATUS_CLOSED
		err = packOrderStatusDao.UpdateOne(packOrderStatus)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("更新包装单状态数据失败, 错误:" + err.Error())
		}
	}
	maxPos, err = shipOrderStatusHistoryDao.GetMaxPos(advanceShipOrderId)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("获取预发运单状态变更历史位置数据失败, error:" + err.Error())
	}
	advanceShipOrderStatusHistory := model.ShipOrderStatusHistory{
		ShipOrderId:      advanceShipOrderId,
		Pos:              maxPos + 1,
		StatusChangeType: model.SHIP_STATUS_CHANGE_TYPE_TRANSFER,
		FromStatus:       advanceShipOrder.ShipOrderStatus.Status1,
		ToStatus:         model.SHIP_STATUS_CLOSED,
		ChangeTime:       grmi.DateTime(time.Now()),
	}
	err = shipOrderStatusHistoryDao.InsertOne(&advanceShipOrderStatusHistory)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("保存预发运单状态变更历史失败, error:" + err.Error())
	}
	advanceShipOrder.ShipOrderStatus.Status1 = model.SHIP_STATUS_CLOSED
	err = shipOrderStatusDao.UpdateOne(&advanceShipOrder.ShipOrderStatus)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("更新预发运单状态失败, error:" + err.Error())
	}
	_ = session.Commit()
	return nil
}

// CloseShipOrder 关闭预发运单
func (impl *ShipOrderServiceImplement) CloseShipOrder(user *global.User, shipOrderId string) error {
	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "CloseShipOrder", "关闭预发运单")
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	shipOrderDao := dal.NewShipOrderDAO(session, user.PlantNr, user.UserId)
	shipOrderStatusDao := dal.NewShipOrderStatusDAO(session, user.PlantNr, user.UserId)
	shipOrderStatusHistoryDao := dal.NewShipOrderStatusHistoryDAO(session, user.PlantNr, user.UserId)
	// 校验发运单数据
	shipOrderData, err := shipOrderDao.SelectOneWithStatus(shipOrderId)
	if err != nil {
		return grmi.NewBusinessError("查询发运单失败, error:" + err.Error())
	}
	if shipOrderData == nil {
		return grmi.NewBusinessError("不存在该发运单, 发运单ID:" + shipOrderId)
	}
	if shipOrderData.ShipOrder.ShipType != model.SHIP_TYPE_ADVANCE {
		return grmi.NewBusinessError("该发运单不是预发运单，不允许关闭")
	}
	//if shipOrderData.ShipOrder.ShipTemplateId != "" {
	//	return grmi.NewBusinessError("该发运单已经绑定包装模板, 不允许关闭")
	//}
	if shipOrderData.ShipOrderStatus.Status == model.SHIP_STATUS_CLOSED {
		return grmi.NewBusinessError("该发运单已经完成关闭, 不能再次操作")
	}
	if err = session.Begin(); err != nil {
		return grmi.NewBusinessError("开启事务失败, error:" + err.Error())
	}
	shipOrderData.ShipOrder.CloseTime = grmi.DateTime(time.Now())
	shipOrderData.Operator = user.UserId
	err = shipOrderDao.UpdateOne(&shipOrderData.ShipOrder)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("更新发运单数据失败, error:" + err.Error())
	}
	maxPos, err := shipOrderStatusHistoryDao.GetMaxPos(shipOrderId)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("获取发运单状态变更历史位置失败, error:" + err.Error())
	}
	statusHistory := model.ShipOrderStatusHistory{
		ShipOrderId:      shipOrderId,
		Pos:              maxPos + 1,
		StatusChangeType: model.SHIP_STATUS_CHANGE_TYPE_SHIP,
		FromStatus:       shipOrderData.ShipOrderStatus.Status,
		ToStatus:         model.SHIP_STATUS_CLOSED,
		ChangeTime:       grmi.DateTime(time.Now()),
	}
	err = shipOrderStatusHistoryDao.InsertOne(&statusHistory)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("保存发运单状态变更记录失败, error:" + err.Error())
	}
	shipOrderData.ShipOrderStatus.Status = model.SHIP_STATUS_CLOSED
	err = shipOrderStatusDao.UpdateOne(&shipOrderData.ShipOrderStatus)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("更新发运单状态失败, error:" + err.Error())
	}
	_ = session.Commit()
	return nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/jit/ShipOrderService.SelectWithStatus
 *
 ******************************************************************************/
func (impl *ShipOrderServiceImplement) SelectWithStatus(user *global.User, urlParameters map[string]string) ([]model.ShipOrderWithStatus, error) {

	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "SelectShipOrder", "查询ShipOrder")

	condition := DefaultConditionOfShipOrderAndPaging
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	predicates, err := condition.BuildPredicates(urlParameters)
	if err != nil {
		return nil, err
	}
	statusStr, exist := urlParameters["status"]
	if !exist || statusStr == "" {
		statusStr = "0"
	}
	status, err := strconv.Atoi(statusStr)
	if err != nil {
		return nil, grmi.NewBusinessError("查询状态参数解析错误， error:" + err.Error())
	}
	formalStatusStr, exist := urlParameters["status1"]
	if !exist || formalStatusStr == "" {
		formalStatusStr = "0"
	}
	formalStatus, err := strconv.Atoi(formalStatusStr)
	if err != nil {
		return nil, grmi.NewBusinessError("查询翻车状态解析失败， error:" + err.Error())
	}
	dao := dal.NewShipOrderDAO(session, user.PlantNr, user.UserId)
	result, err := dao.SelectWithStatus(predicates, condition.OrderByFields, status, formalStatus)
	if err != nil {
		return nil, err
	}
	return result, nil
}

// PermitTrough plc放行
func (impl *ShipOrderServiceImplement) PermitTrough(workPlaceConfig *baseModel.WorkPlaceConfig) error {
	log, _ := logger.NewLogger("plc", "JIT")
	plcType := workPlaceConfig.StrValue1
	plcAddress := workPlaceConfig.StrValue2
	DBAddress := workPlaceConfig.StrValue3
	valueType := workPlaceConfig.StrValue4
	retryCount := workPlaceConfig.IntValue1
	data := baseModel.PLC{
		PLCType:      plcType,
		PLCAddress:   plcAddress,
		ValueAddress: DBAddress,
		ValueType:    valueType,
		RetryCount:   retryCount,
	}
	if valueType == "Boolean" {
		data.ValueText = workPlaceConfig.BoolValue1
	}
	postData, err := json.Marshal(data)
	if err != nil {
		log.Error("发运plc放行调用后台失败, 序列化请求数据失败, error:" + err.Error())
		return grmi.NewBusinessError("准备向plc写入数据失败, error:" + err.Error())
	}
	log.Debug("发运plc放行调用后台, 请求参数:" + string(postData) + ", url:" + conf.DbConfig.PLCWriteBackend)
	boday, err := utils.Post(conf.DbConfig.PLCWriteBackend, postData)
	if err != nil {
		log.Error("发运plc放行调用后台失败, 调用失败, error:" + err.Error())
		return grmi.NewBusinessError("向plc管理后台发送请求失败, error:" + err.Error())
	}
	log.Debug("发运plc放行调用后台, 请求响应:" + string(boday))

	var response baseModel.Response
	err = json.Unmarshal(boday, &response)
	if err != nil {
		log.Error("发运plc放行调用后台失败, 解析后台数据失败, error:" + err.Error() + ", 后台数据:" + string(boday))
		return grmi.NewBusinessError("解析plc管理后台返回值失败, error:" + err.Error())
	}
	if response.Code != iris.StatusOK {
		log.Error("发运plc放行调用后台失败, 后台返回错误, 后台数据:" + string(boday))
		return grmi.NewBusinessError("plc管理后台写入失败, 错误:" + response.Msg)
	}
	type PLCData struct {
		IsSuccess bool        `json:"IsSuccess"`
		Message   string      `json:"Message"`
		ErrorCode int         `json:"ErrorCode"`
		Content   interface{} `json:"Content"`
	}
	plcData, ok := response.Data.(map[string]interface{})
	if !ok {
		log.Error("发运plc放行调用后台失败, 后台返回data格式不正确, 后台数据:" + string(boday))
		return grmi.NewBusinessError("plc管理后台返回数据格式不正确")
	}
	successInterface, exist := plcData["IsSuccess"]
	if !exist {
		log.Error("发运plc放行调用后台失败, 后台返回data格式不正确, 后台数据:" + string(boday))
		return grmi.NewBusinessError("plc管理后台返回数据格式不正确")
	}
	success, ok := successInterface.(bool)
	if !ok {
		log.Error("发运plc放行调用后台失败, 后台返回data格式不正确, 后台数据:" + string(boday))
		return grmi.NewBusinessError("plc管理后台返回数据格式不正确")
	}
	if !success {
		log.Error("发运plc放行调用后台失败, 后台plc执行失败, 后台数据:" + string(boday))
		var message string
		messageInterface, exist := plcData["Message"]
		if !exist {
			message = "未返回错误信息"
		}
		message, ok = messageInterface.(string)
		if !ok {
			message = "未返回错误信息"
		}
		return grmi.NewBusinessError("plc执行失败, error:" + message)
	}
	return nil
}

// SelectShipDataBySerialOrderId 通过工单查询发运单
func (impl *ShipOrderServiceImplement) SelectShipDataBySerialOrderId(user *global.User, serialOrderId string) ([]model.ShipOrderWithStatus, error) {
	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "SelectShipDataBySerialOrderId", "通过工单ID查询发运单")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	packOrderItemLstDao := dal.NewPackOrderItemLstDAO(session, user.PlantNr, user.UserId)
	shipOrderDao := dal.NewShipOrderDAO(session, user.PlantNr, user.UserId)
	shipOrderIdLi, err := packOrderItemLstDao.SelectShipOrderBySerialOrderId(serialOrderId)
	if err != nil {
		return nil, err
	}
	if len(shipOrderIdLi) == 0 {
		return nil, grmi.NewBusinessError("当前工单没有进入到发运单中")
	}
	shipOrderLi, err := shipOrderDao.SelectOrderWithStatus([]grmi.Predicate{
		meta.ShipOrder_ShipOrderId.NewPredicate(grmi.Include, shipOrderIdLi...),
	}, []grmi.Field{meta.ShipOrder_CreateTime})
	if err != nil {
		return nil, grmi.NewBusinessError("查询发运单失败, 错误:" + err.Error())
	}
	return shipOrderLi, nil
}

// WithdrawShipOrderItem 发运单子项撤销
func (impl *ShipOrderServiceImplement) WithdrawShipOrderItem(user *global.User, shipOrderId string, pos int) error {
	grmi.Log(user, "/services/jit/implments/ShipOrder.service.impl.go", "WithdrawShipOrderItem", "发运单子项撤销")

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	shipOrderDao := dal.NewShipOrderDAO(session, user.PlantNr, user.UserId)
	shipOrderItemDao := dal.NewShipOrderItemLstDAO(session, user.PlantNr, user.UserId)
	shipOrderStatusDao := dal.NewShipOrderStatusDAO(session, user.PlantNr, user.UserId)
	shipOrderDataDao := dal.NewShipOrderDataLstDAO(session, user.PlantNr, user.UserId)
	packOrderStatusDao := dal.NewPackOrderStatusDAO(session, user.PlantNr, user.UserId)
	packOrderStatusHistoryDao := dal.NewPackOrderStatusHistoryDAO(session, user.PlantNr, user.UserId)
	shipOrder, err := shipOrderDao.SelectOne(shipOrderId)
	if err != nil {
		return grmi.NewBusinessError("查询发运单失败")
	}
	if shipOrder == nil {
		return grmi.NewBusinessError("发运单不存在")
	}
	shipOrderStatus, err := shipOrderStatusDao.SelectOne(shipOrderId)
	if err != nil {
		return grmi.NewBusinessError("查询发运单数据失败, 错误:" + err.Error())
	}
	if shipOrderStatus == nil {
		return grmi.NewBusinessError("发运单不存在")
	}
	if shipOrderStatus.Status == model.SHIP_STATUS_CLOSED {
		return grmi.NewBusinessError("发运单已关闭")
	}
	shipOrderItem, err := shipOrderItemDao.SelectOne(shipOrderId, pos)
	if err != nil {
		return grmi.NewBusinessError("查询发运单子项数据失败, 错误:" + err.Error())
	}
	if shipOrderItem == nil {
		return grmi.NewBusinessError("不存在选择的发运子项")
	}
	if shipOrderItem.Status != model.SHIP_STATUS_CLOSED {
		return grmi.NewBusinessError("发运子项还没有进行扫码")
	}
	shipOrderDataLi, err := shipOrderDataDao.Select([]grmi.Predicate{
		meta.ShipOrderDataLst_ShipOrderId.NewPredicate(grmi.Equal, shipOrderId),
		meta.ShipOrderDataLst_ItemPos.NewPredicate(grmi.Equal, pos),
	}, nil)
	if len(shipOrderDataLi) == 0 {
		return grmi.NewBusinessError("发运单数据项不存在")
	}
	packOrderId := shipOrderDataLi[0].PackOrderId
	packOrderStatus, err := packOrderStatusDao.SelectOne(packOrderId)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("查询发运单状态数据失败，错误：" + err.Error())
	}
	if packOrderStatus == nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("未查询到发运单状态数据, 发运单ID:" + packOrderId)
	}
	maxPos, err := packOrderStatusHistoryDao.GetMaxPos(packOrderId)
	if err != nil {
		return grmi.NewBusinessError("查询包装单状态变更历史数据失败, 错误:" + err.Error())
	}
	if err = session.Begin(); err != nil {
		return grmi.NewBusinessError("开启事务失败, 错误:" + err.Error())
	}

	err = shipOrderDataDao.DeleteOne(shipOrderId, packOrderId)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("删除发运单数据项失败, 错误:" + err.Error())
	}

	if shipOrder.ShipType == model.SHIP_TYPE_FORMAL {
		packOrderStatusHistory := model.PackOrderStatusHistory{
			PackOrderId:      packOrderId,
			Pos:              maxPos + 1,
			StatusChangeType: model.SHIP_STATUS_CHANGE_TYPE_SHIP,
			FromStatus:       packOrderStatus.ShipStatus,
			ToStatus:         model.PACK_STATUS_PLANNED,
			ChangeTime:       grmi.DateTime(time.Now()),
			TriggerPara1:     model.SHIP_TYPE_FORMAL,
		}
		err = packOrderStatusHistoryDao.InsertOne(&packOrderStatusHistory)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("写入包装单状态变更历史失败, 错误:" + err.Error())
		}
		packOrderStatus.ShipStatus = model.PACK_STATUS_PLANNED
	} else {
		packOrderStatusHistory := model.PackOrderStatusHistory{
			PackOrderId:      packOrderId,
			Pos:              maxPos + 1,
			StatusChangeType: model.SHIP_STATUS_CHANGE_TYPE_SHIP,
			FromStatus:       packOrderStatus.LoadStatus,
			ToStatus:         model.PACK_STATUS_PLANNED,
			ChangeTime:       grmi.DateTime(time.Now()),
			TriggerPara1:     model.SHIP_TYPE_ADVANCE,
		}
		err = packOrderStatusHistoryDao.InsertOne(&packOrderStatusHistory)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("写入包装单状态变更历史失败, 错误:" + err.Error())
		}
		packOrderStatus.LoadStatus = model.PACK_STATUS_PLANNED
	}
	err = packOrderStatusDao.UpdateOne(packOrderStatus)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("更新包装单状态失败, 错误:" + err.Error())
	}
	shipOrderItem.Status = model.SHIP_STATUS_PLANNED
	shipOrderItem.ActQty--
	err = shipOrderItemDao.UpdateOne(shipOrderItem)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("更新发运单子项数据失败, 错误:" + err.Error())
	}
	_ = session.Commit()
	return nil
}
