// 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/pln"
	"LAPP_ACURA_MOM_BACKEND/db"
	"LAPP_ACURA_MOM_BACKEND/global"
	"LAPP_ACURA_MOM_BACKEND/grmi"
	"LAPP_ACURA_MOM_BACKEND/infra/logger"
	meta "LAPP_ACURA_MOM_BACKEND/meta/pln"
	baseModel "LAPP_ACURA_MOM_BACKEND/models/base"
	model "LAPP_ACURA_MOM_BACKEND/models/pln"
	"LAPP_ACURA_MOM_BACKEND/utils"
	"encoding/hex"
	json "github.com/json-iterator/go"
	"github.com/kataras/iris/v12"
	"strconv"
	"time"
)

/******************************************************************************
 *
 * @Description              : ToyotaDeliveryOrder的默认查询条件
 *
 * @Author                   : 代码生成器创建
 *
 * @Date                     : 2022-01-26 09:51:03
 *
 ******************************************************************************/
var DefaultConditionOfToyotaDeliveryOrder = grmi.NewCondition(
	map[string]grmi.ConditionItem{
		meta.ToyotaDeliveryOrder_DemandId.UrlParameterName:        grmi.NewConditionItem(meta.ToyotaDeliveryOrder_DemandId, grmi.Equal, true),
		meta.ToyotaDeliveryOrder_SortNr.UrlParameterName:          grmi.NewConditionItem(meta.ToyotaDeliveryOrder_SortNr, grmi.Equal, false),
		meta.ToyotaDeliveryOrder_ProductFamilyId.UrlParameterName: grmi.NewConditionItem(meta.ToyotaDeliveryOrder_ProductFamilyId, grmi.Equal, false),
		meta.ToyotaDeliveryOrder_ProjectId.UrlParameterName:       grmi.NewConditionItem(meta.ToyotaDeliveryOrder_ProjectId, grmi.Equal, false),
		meta.ToyotaDeliveryOrder_PlcIpAddress.UrlParameterName:    grmi.NewConditionItem(meta.ToyotaDeliveryOrder_PlcIpAddress, grmi.Equal, false),
		meta.ToyotaDeliveryOrder_PlcCode.UrlParameterName:         grmi.NewConditionItem(meta.ToyotaDeliveryOrder_PlcCode, grmi.Equal, false),
		meta.ToyotaDeliveryOrder_Status.UrlParameterName:          grmi.NewConditionItem(meta.ToyotaDeliveryOrder_Status, grmi.Equal, false),
		meta.ToyotaDeliveryOrder_CloseTime.UrlParameterName:       grmi.NewConditionItem(meta.ToyotaDeliveryOrder_CloseTime, grmi.Approximate, false),
		meta.ToyotaDeliveryOrder_CtrlPara1.UrlParameterName:       grmi.NewConditionItem(meta.ToyotaDeliveryOrder_CtrlPara1, grmi.Equal, false),
		meta.ToyotaDeliveryOrder_CtrlPara2.UrlParameterName:       grmi.NewConditionItem(meta.ToyotaDeliveryOrder_CtrlPara2, grmi.Equal, false),
		meta.ToyotaDeliveryOrder_CtrlStr1.UrlParameterName:        grmi.NewConditionItem(meta.ToyotaDeliveryOrder_CtrlStr1, grmi.Equal, false),
		meta.ToyotaDeliveryOrder_CtrlStr2.UrlParameterName:        grmi.NewConditionItem(meta.ToyotaDeliveryOrder_CtrlStr2, grmi.Equal, false),
		meta.ToyotaDeliveryOrder_CtrlTime1.UrlParameterName:       grmi.NewConditionItem(meta.ToyotaDeliveryOrder_CtrlTime1, grmi.Approximate, false),
		meta.ToyotaDeliveryOrder_CtrlTime2.UrlParameterName:       grmi.NewConditionItem(meta.ToyotaDeliveryOrder_CtrlTime2, grmi.Approximate, false),
		meta.ToyotaDeliveryOrder_LastModify.UrlParameterName:      grmi.NewConditionItem(meta.ToyotaDeliveryOrder_LastModify, grmi.Approximate, false),
		meta.ToyotaDeliveryOrder_LastUser.UrlParameterName:        grmi.NewConditionItem(meta.ToyotaDeliveryOrder_LastUser, grmi.Equal, false),
		meta.ToyotaDeliveryOrder_CreateTime.UrlParameterName:      grmi.NewConditionItem(meta.ToyotaDeliveryOrder_CreateTime, grmi.Approximate, false),
	},
	nil,
)

/******************************************************************************
 *
 * @Description              : ToyotaDeliveryOrder的默认分页查询条件
 *
 * @Author                   : 代码生成器创建
 *
 * @Date                     : 2022-01-26 09:51:03
 *
 ******************************************************************************/
var DefaultConditionOfToyotaDeliveryOrderAndPaging = grmi.NewCondition(
	DefaultConditionOfToyotaDeliveryOrder.Items,
	grmi.NewPaging(),
)

/******************************************************************************
 *
 * @Struct Name              : ToyotaDeliveryOrderServiceImplement
 *-----------------------------------------------------------------------------
 *
 * @Description              : ToyotaDeliveryOrder的服务实现
 *
 * @Author                   : 代码生成器创建
 *
 * @Date                     : 2022-01-26 09:51:03
 *
 ******************************************************************************/
type ToyotaDeliveryOrderServiceImplement struct {
}

/******************************************************************************
 *
 * @Function Name            : NewToyotaDeliveryOrderDAOImplement
 *-----------------------------------------------------------------------------
 *
 * @Description              : 创建一个ToyotaDeliveryOrderDAOImplement实例
 *
 * @Return Value             : ToyotaDeliveryOrderDAOImplement实例
 *
 * @Author                   : 代码生成器创建
 *
 * @Date                     : 2022-01-26 09:51:03
 *
 ******************************************************************************/
func NewToyotaDeliveryOrderServiceImplement() *ToyotaDeliveryOrderServiceImplement {
	return &ToyotaDeliveryOrderServiceImplement{}
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/ToyotaDeliveryOrderService.InsertOne
 *
 ******************************************************************************/
func (impl *ToyotaDeliveryOrderServiceImplement) InsertOne(user *global.User, entity *model.ToyotaDeliveryOrder) error {

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

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewToyotaDeliveryOrderDAO(session, user.PlantNr, user.UserId)
	record, err := dao.SelectOne(entity.DemandId)
	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/pln/ToyotaDeliveryOrderService.DeleteOne
 *
 ******************************************************************************/
func (impl *ToyotaDeliveryOrderServiceImplement) DeleteOne(user *global.User, demandId string) error {

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

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

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/ToyotaDeliveryOrderService.SelectOne
 *
 ******************************************************************************/
func (impl *ToyotaDeliveryOrderServiceImplement) SelectOne(user *global.User, demandId string) (*model.ToyotaDeliveryOrder, error) {

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

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewToyotaDeliveryOrderDAO(session, user.PlantNr, user.UserId)
	result, err := dao.SelectOne(demandId)
	if err != nil {
		return nil, err
	}
	return result, nil
}

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/ToyotaDeliveryOrderService.UpdateOne
 *
 ******************************************************************************/
func (impl *ToyotaDeliveryOrderServiceImplement) UpdateOne(user *global.User, entity *model.ToyotaDeliveryOrder) error {

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

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

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/ToyotaDeliveryOrderService.Insert
 *
 ******************************************************************************/
func (impl *ToyotaDeliveryOrderServiceImplement) Insert(user *global.User, entities *[]model.ToyotaDeliveryOrder) error {

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

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

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

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

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

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

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

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

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

	condition := DefaultConditionOfToyotaDeliveryOrderAndPaging
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	predicates, err := condition.BuildPredicates(urlParameters)
	if err != nil {
		return grmi.EmptyPagingResult, err
	}
	dao := dal.NewToyotaDeliveryOrderDAO(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/ToyotaDeliveryOrderService.Update
 *
 ******************************************************************************/
func (impl *ToyotaDeliveryOrderServiceImplement) Update(user *global.User, entities *[]model.ToyotaDeliveryOrder) error {

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

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

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

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

//func (impl *ToyotaDeliveryOrderServiceImplement) WritePlcCode(user *global.User) {
//	engine := db.Eloquent.Master()
//	session := engine.NewSession()
//	defer session.Close()
//	log, _ := logger.NewLogger("DeliveryOrder", "PLN")
//	deliveryOrderDao := dal.NewToyotaDeliveryOrderDAO(session, user.PlantNr, user.UserId)
//	deliveryOrder, err := deliveryOrderDao.SelectTopOne([]grmi.Predicate{meta.ToyotaDeliveryOrder_Status.NewPredicate(grmi.Equal, model.DELIVERY_STATUS_PLAN)}, []grmi.Field{meta.ToyotaDeliveryOrder_SortNr})
//	if err != nil {
//		log.Error("写入发运PLC数据， 查询待写入plc的发运单数据失败, error:" + err.Error())
//	}
//	if deliveryOrder == nil {
//		log.Debug("写入发运PLC数据， 暂无待写入plc的发运单数据")
//		return
//	}
//
//}

// WriteDeliveryDataToPLCTask 把发运数据写入到plc的任务
func (impl *ToyotaDeliveryOrderServiceImplement) WriteDeliveryDataToPLCTask() {
	log, _ := logger.NewLogger("CallOff", "JIT")
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	userId := "Scheduler"
	plantDao := baseDal.NewPlantDAO(session, userId)
	plantLi, err := plantDao.Select(nil, nil)
	if err != nil {
		log.Error("广丰写入座椅出库数据, 查询工厂数据失败, error:" + err.Error())
		return
	}
	for _, plant := range plantLi {
		if plant.PlantProject != baseModel.PROJECT_NANSHA {
			continue
		}
		go impl.WriteDeliveryDataToPLC(&global.User{
			UserId:  userId,
			PlantNr: plant.PlantNr,
		})
	}
}

// WriteDeliveryDataToPLC 把发运数据写入到plc的具体实现
func (impl *ToyotaDeliveryOrderServiceImplement) WriteDeliveryDataToPLC(user *global.User) {
	log, _ := logger.NewLogger("CallOff", "JIT")
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	errSession := engine.NewSession()
	defer errSession.Close()
	dao := dal.NewToyotaDeliveryOrderDAO(session, user.PlantNr, user.UserId)
	errDao := dal.NewToyotaDeliveryOrderErrorLstDAO(session, user.PlantNr, user.UserId)
	callOffDao := dal.NewToyotaCalloffDAO(session, user.PlantNr, user.UserId)
	deliveryOrder, err := dao.SelectTopOne([]grmi.Predicate{meta.ToyotaDeliveryOrder_Status.NewPredicate(grmi.Equal, model.DELIVERY_STATUS_PLAN)}, []grmi.Field{meta.ToyotaDeliveryOrder_SortNr})
	if err != nil {
		log.Error("广丰写入座椅出库数据, 查询发运数据失败, error:" + err.Error())
		return
	}
	if deliveryOrder == nil {
		log.Info("广丰写入座椅出库数据, 当前没有待写入的座椅出库数据")
		return
	}
	doneOrder, err := dao.SelectTopOneDesc([]grmi.Predicate{meta.ToyotaDeliveryOrder_Status.NewPredicate(grmi.Equal, model.DELIVERY_STATUS_DONE)}, []grmi.Field{meta.ToyotaDeliveryOrder_SortNr})
	if err != nil {
		log.Error("广丰写入座椅出库数据, 查询写入完成的发运单数据失败, error:" + err.Error())
		return
	}
	callOff, err := callOffDao.SelectOne(deliveryOrder.DemandId)
	if err != nil {
		log.Error("查询callOff数据失败, 错误：" + err.Error())
		return
	}
	if callOff == nil {
		errorContent := "CallOff数据不存在"
		log.Error("广丰写入座椅出库数据，" + errorContent + ", demandId:" + deliveryOrder.DemandId)
		errData := model.ToyotaDeliveryOrderErrorLst{
			DemandId: deliveryOrder.DemandId,
			Pos: 1,
			ErrorType: model.ERROR_TYPE_HINT,
			ErrorInfo: errorContent,
			ErrorStatus: model.ERROR_STATUS_ON,
		}
		err = errDao.InsertOne(&errData)
		if err != nil {
			log.Error("广丰写入座椅出库数据, 写入错误数据失败, error:" + err.Error() + ", 错误数据:" + errorContent + "， demandId：" + deliveryOrder.DemandId)
		}
		return
	}
	//if doneOrder == nil {
	//	if deliveryOrder.SortNr != 1 {
	//		log.Error("广丰写入座椅出库数据, 起始SortNr不为1")
	//		return
	//	}
	//}
	err = errDao.DeleteWhere([]grmi.Predicate{meta.ToyotaDeliveryOrderErrorLst_DemandId.NewPredicate(grmi.Equal, deliveryOrder.DemandId)})
	if err != nil {
		log.Error("广丰写入座椅出库数据, 删除已存在的错误数据失败， error:" + err.Error())
		return
	}
	if doneOrder != nil {
		if deliveryOrder.SortNr != doneOrder.SortNr+1 {
			errorContent := "发运数据连番号不连续，当前已写到:" + strconv.Itoa(doneOrder.SortNr)
			log.Error("广丰写入座椅出库数据，" + errorContent + ", demandId:" + deliveryOrder.DemandId)
			errData := model.ToyotaDeliveryOrderErrorLst{
				DemandId: deliveryOrder.DemandId,
				Pos: 1,
				ErrorType: model.ERROR_TYPE_HINT,
				ErrorInfo: errorContent,
				ErrorStatus: model.ERROR_STATUS_ON,
			}
			err = errDao.InsertOne(&errData)
			if err != nil {
				log.Error("广丰写入座椅出库数据, 写入错误数据失败, error:" + err.Error() + ", 错误数据:" + errorContent + "， demandId：" + deliveryOrder.DemandId)
			}
			return
		}
	}
	if err = session.Begin(); err != nil {
		log.Error("广丰写入座椅出库数据, 开启事务失败, error:" + err.Error())
		errorContent := "开启事务失败, error:" + err.Error()
		errData := model.ToyotaDeliveryOrderErrorLst{
			DemandId: deliveryOrder.DemandId,
			Pos: 1,
			ErrorType: model.ERROR_TYPE_SYSTEM,
			ErrorInfo: errorContent,
			ErrorStatus: model.ERROR_STATUS_ON,
		}
		err = errDao.InsertOne(&errData)
		if err != nil {
			log.Error("广丰写入座椅出库数据, 写入错误数据失败, error:" + err.Error() + ", 错误数据:" + errorContent + "， demandId：" + deliveryOrder.DemandId)
		}
		return
	}
	deliveryOrder.Status = model.DELIVERY_STATUS_DONE
	deliveryOrder.CloseTime = grmi.DateTime(time.Now())
	err = dao.UpdateOne(deliveryOrder)
	if err != nil {
		_ = session.Rollback()
		log.Error("广丰写入座椅出库数据, 更新发运数据失败, error:" + err.Error())
		return
	}
	callOff.Parsed = model.CALLOFF_STATUS_SHIPED
	err = callOffDao.UpdateOne(callOff)
	if err != nil {
		_ = session.Rollback()
		log.Error("广丰写入座椅出库数据, 更新CallOff状态失败, 错误:" + err.Error())
		return
	}
	err = impl.WriteToPLC(user, deliveryOrder)
	if err != nil {
		_ = session.Rollback()
		log.Error("广丰写入座椅出库数据, 写PLC数据失败, error:" + err.Error())
		errorContent := "写PLC数据失败"
		errData := model.ToyotaDeliveryOrderErrorLst{
			DemandId: deliveryOrder.DemandId,
			Pos: 1,
			ErrorType: model.ERROR_TYTPE_PLC,
			ErrorInfo: errorContent,
			ErrorStatus: model.ERROR_STATUS_ON,
		}
		err = errDao.InsertOne(&errData)
		if err != nil {
			log.Error("广丰写入座椅出库数据, 写入错误数据失败, error:" + err.Error() + ", 错误数据:" + errorContent + "， demandId：" + deliveryOrder.DemandId)
		}
		return
	}
	_ = session.Commit()
	log.Info("广丰写入座椅出库数据, 写PLC数据成功, demandId:" + deliveryOrder.DemandId)
}

// WriteToPLC plc放行
func (impl *ToyotaDeliveryOrderServiceImplement) WriteToPLC(user *global.User, deliveryOrder *model.ToyotaDeliveryOrder) error {
	productFamilyId := deliveryOrder.ProductFamilyId
	projectId := deliveryOrder.ProjectId

	err := impl.ReadSign()
	if err != nil {
		innerErr := impl.SaveCallOffPLCError(user, deliveryOrder.DemandId, 1, err.Error(), deliveryOrder.PlcCode, productFamilyId, projectId)
		if innerErr != nil {
			return grmi.NewBusinessError(err.Error() + ", 保存错误失败, error:" + err.Error())
		}
		return err
	}
	err = impl.WriteSign()
	if err != nil {
		innerErr := impl.SaveCallOffPLCError(user, deliveryOrder.DemandId, 2, err.Error(), deliveryOrder.PlcCode, productFamilyId, projectId)
		if innerErr != nil {
			return grmi.NewBusinessError(err.Error() + ", 保存错误失败, error:" + err.Error())
		}
		return err
	}
	err = impl.WriteSeatData(deliveryOrder.PlcCode)
	if err != nil {
		innerErr := impl.SaveCallOffPLCError(user, deliveryOrder.DemandId, 3, err.Error(), deliveryOrder.PlcCode, productFamilyId, projectId)
		if innerErr != nil {
			return grmi.NewBusinessError(err.Error() + ", 保存错误失败, error:" + err.Error())
		}
		return err
	}
	err = impl.WriteDoneSign()
	if err != nil {
		innerErr := impl.SaveCallOffPLCError(user, deliveryOrder.DemandId, 4, err.Error(), deliveryOrder.PlcCode, productFamilyId, projectId)
		if innerErr != nil {
			return grmi.NewBusinessError(err.Error() + ", 保存错误失败, error:" + err.Error())
		}
		return err
	}
	return nil
}



func (impl *ToyotaDeliveryOrderServiceImplement) ReadSign() error {
	log, _ := logger.NewLogger("plc", "JIT")
	data := baseModel.PLC{
		PLCType:      conf.DbConfig.CallOffPlcType,
		PLCAddress:   conf.DbConfig.CallOffPlcAddress,
		ValueAddress: conf.DbConfig.CallOffPlcReadSign,
		ValueType:    "Boolean",
		RetryCount:   conf.DbConfig.OfflinePLCRetry,
	}
	var retryNum int
	for {
		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.PLCReadBackend)
		boday, err := utils.Post(conf.DbConfig.PLCReadBackend, 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)
		}
		plcData, ok := response.Data.(map[string]interface{})
		if !ok {
			log.Error("座椅出库plc写入, 写入座椅数据后台返回data格式不正确, 后台数据:" + string(boday))
			return grmi.NewBusinessError("座椅出库plc写入, 写入座椅数据后台返回data格式不正确, 后台数据:" + string(boday))
		}
		successInterface, exist := plcData["IsSuccess"]
		if !exist {
			log.Error("座椅出库plc写入, 读取写入标识后台返回data格式不正确, 后台数据:" + string(boday))
			return grmi.NewBusinessError("座椅出库plc写入, 读取写入标识后台返回data格式不正确, 后台数据:" + string(boday))
		}
		success, ok := successInterface.(bool)
		if !ok {
			log.Error("座椅出库plc写入, 读取写入标识后台返回data格式不正确, 后台数据:" + string(boday))
			return grmi.NewBusinessError("座椅出库plc写入, 读取写入标识后台返回data格式不正确, 后台数据:" + string(boday))
		}
		if !success {
			log.Error("座椅出库plc写入, 读取写入标识后台plc执行失败, 后台数据:" + string(boday))
			return grmi.NewBusinessError("座椅出库plc写入, 读取写入标识后台plc执行失败, 后台数据:" + string(boday))
		}
		content, exist := plcData["Content"]
		if !exist {
			log.Error("座椅出库plc写入, 读取写入标识后台返回data格式不正确, 后台数据:" + string(boday))
			return grmi.NewBusinessError("座椅出库plc写入, 读取写入标识后台返回data格式不正确, 后台数据:" + string(boday))
		}
		sign, ok := content.(bool)
		if !ok {
			log.Error("座椅出库plc写入, 读取标识位后台返回data格式不正确, 后台数据:" + string(boday))
			return grmi.NewBusinessError("座椅出库plc写入, 读取标识位后台返回data格式不正确, 后台数据:" + string(boday))
		}
		if !sign {
			if retryNum >= 3 {
				log.Error("座椅出库plc写入, 读取标识位不允许写入且达到最大次数, 后台数据:" + string(boday))
				return grmi.NewBusinessError("座椅出库plc写入, 读取标识位不允许写入且达到最大次数, 后台数据:" + string(boday))
			}
			log.Error("座椅出库plc写入, 读取标识位不允许写入, 后台数据:" + string(boday))
			retryNum++
			time.Sleep(time.Millisecond * 500)
			continue
		} else {
			break
		}
	}
	return nil
}

func (impl *ToyotaDeliveryOrderServiceImplement) WriteSign() error {
	log, _ := logger.NewLogger("plc", "JIT")
	data := baseModel.PLC{
		PLCType:      conf.DbConfig.CallOffPlcType,
		PLCAddress:   conf.DbConfig.CallOffPlcAddress,
		ValueAddress: conf.DbConfig.CallOffPlcReadSign,
		ValueType:    "Boolean",
		RetryCount:   conf.DbConfig.OfflinePLCRetry,
		ValueText:    false,
	}
	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)
	}
	plcData, ok := response.Data.(map[string]interface{})
	if !ok {
		log.Error("座椅出库plc写入, 写入第一步标识位后台返回data格式不正确, 后台数据:" + string(boday))
		return grmi.NewBusinessError("座椅出库plc写入, 写入第一步标识位后台返回data格式不正确, 后台数据:" + string(boday))
	}
	successInterface, exist := plcData["IsSuccess"]
	if !exist {
		log.Error("座椅出库plc写入, 写入第一步标识位后台返回data格式不正确, 后台数据:" + string(boday))
		return grmi.NewBusinessError("座椅出库plc写入, 写入第一步标识位后台返回data格式不正确, 后台数据:" + string(boday))
	}
	success, ok := successInterface.(bool)
	if !ok {
		log.Error("座椅出库plc写入, 写入第一步标识位后台返回data格式不正确, 后台数据:" + string(boday))
		return grmi.NewBusinessError("座椅出库plc写入, 写入第一步标识位后台返回data格式不正确, 后台数据:" + string(boday))
	}
	if !success {
		log.Error("座椅出库plc写入, 写入第一步标识位后台plc执行失败, 后台数据:" + string(boday))
		return grmi.NewBusinessError("座椅出库plc写入, 写入第一步标识位后台plc执行失败, 后台数据:" + string(boday))
	}
	return nil
}

func (impl *ToyotaDeliveryOrderServiceImplement) WriteSeatData(seatData string) error {
	log, _ := logger.NewLogger("plc", "JIT")
	seatData = hex.EncodeToString([]byte(seatData))
	data := baseModel.PLC{
		PLCType:      conf.DbConfig.CallOffPlcType,
		PLCAddress:   conf.DbConfig.CallOffPlcAddress,
		ValueAddress: conf.DbConfig.CallOffPlcWrite,
		ValueType:    "Bytes",
		RetryCount:   conf.DbConfig.OfflinePLCRetry,
		ValueText:    seatData,
		ByteCount:    conf.DbConfig.CallOffPlcWriteLen,
	}
	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)
	}
	plcData, ok := response.Data.(map[string]interface{})
	if !ok {
		log.Error("座椅出库plc写入, 写入座椅数据后台返回data格式不正确, 后台数据:" + string(boday))
		return grmi.NewBusinessError("座椅出库plc写入, 写入座椅数据后台返回data格式不正确, 后台数据:" + string(boday))
	}
	successInterface, exist := plcData["IsSuccess"]
	if !exist {
		log.Error("座椅出库plc写入, 写入座椅数据后台返回data格式不正确, 后台数据:" + string(boday))
		return grmi.NewBusinessError("座椅出库plc写入, 写入座椅数据后台返回data格式不正确, 后台数据:" + string(boday))
	}
	success, ok := successInterface.(bool)
	if !ok {
		log.Error("座椅出库plc写入, 写入座椅数据后台返回data格式不正确, 后台数据:" + string(boday))
		return grmi.NewBusinessError("座椅出库plc写入, 写入座椅数据后台返回data格式不正确, 后台数据:" + string(boday))
	}
	if !success {
		log.Error("座椅出库plc写入, 写入座椅数据后台plc执行失败, 后台数据:" + string(boday))
		return grmi.NewBusinessError("座椅出库plc写入, 写入座椅数据后台plc执行失败, 后台数据:" + string(boday))
	}
	return nil
}

func (impl *ToyotaDeliveryOrderServiceImplement) WriteDoneSign() error {
	log, _ := logger.NewLogger("plc", "JIT")
	data := baseModel.PLC{
		PLCType:      conf.DbConfig.CallOffPlcType,
		PLCAddress:   conf.DbConfig.CallOffPlcAddress,
		ValueAddress: conf.DbConfig.CallOffPlcWriteSign,
		ValueType:    "Boolean",
		RetryCount:   conf.DbConfig.OfflinePLCRetry,
		ValueText:    true,
	}
	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)
	}
	plcData, ok := response.Data.(map[string]interface{})
	if !ok {
		log.Error("座椅出库plc写入, 写入保存完成后台返回data格式不正确, 后台数据:" + string(boday))
		return grmi.NewBusinessError("座椅出库plc写入, 写入保存完成后台返回data格式不正确, 后台数据:" + string(boday))
	}
	successInterface, exist := plcData["IsSuccess"]
	if !exist {
		log.Error("座椅出库plc写入, 写入保存完成后台返回data格式不正确, 后台数据:" + string(boday))
		return grmi.NewBusinessError("座椅出库plc写入, 写入保存完成后台返回data格式不正确, 后台数据:" + string(boday))
	}
	success, ok := successInterface.(bool)
	if !ok {
		log.Error("座椅出库plc写入, 写入保存完成后台返回data格式不正确, 后台数据:" + string(boday))
		return grmi.NewBusinessError("座椅出库plc写入, 写入保存完成后台返回data格式不正确, 后台数据:" + string(boday))
	}
	if !success {
		log.Error("座椅出库plc写入, 写入保存完成后台plc执行失败, 后台数据:" + string(boday))
		return grmi.NewBusinessError("座椅出库plc写入, 写入保存完成后台plc执行失败, 后台数据:" + string(boday))
	}
	return nil
}

// SaveCallOffPLCError 将座椅出库写入plc阶段的错误保存到数据表
func (impl *ToyotaDeliveryOrderServiceImplement) SaveCallOffPLCError(user *global.User, demandId string, step int, errInfo string, seatData string, productFamilyId string, projectId string) error {
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	errDao := baseDal.NewPLCErrorInfoDAO(session, user.PlantNr, user.UserId)
	errData := baseModel.PLCErrorInfo{
		ErrorId:   demandId,
		Status:    baseModel.WO_STATUS_PLANNED,
		Step:      step,
		ErrorInfo: errInfo,
		SeatData:  seatData,
		Source:    baseModel.PLC_ERROR_SOURCE_CALLOFF,
		SaveStr1:  productFamilyId,
		SaveStr2:  projectId,
	}
	return errDao.InsertOne(&errData)
}

func (impl *ToyotaDeliveryOrderServiceImplement) RepairDeliveryOrderError(user *global.User, errorInfoId string) (err error) {
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	deliveryOrderDao := dal.NewToyotaDeliveryOrderDAO(session, user.PlantNr, user.UserId)
	deliveryOrderErrorDao := dal.NewToyotaDeliveryOrderErrorLstDAO(session, user.PlantNr, user.UserId)
	dao := baseDal.NewPLCErrorInfoDAO(session, user.PlantNr, user.UserId)
	deliveryOrder, err := deliveryOrderDao.SelectOne(errorInfoId)
	if err != nil {
		return grmi.NewBusinessError("查询发运单数据失败, 错误:" + err.Error())
	}
	if deliveryOrder == nil {
		return grmi.NewBusinessError("不存在错误对应的发运单数据")
	}
	if deliveryOrder.Status == model.DELIVERY_STATUS_DONE {
		return grmi.NewBusinessError("错误项关联发运数据已写入成功")
	}
	errorLi, err := deliveryOrderErrorDao.Select([]grmi.Predicate{meta.ToyotaDeliveryOrderErrorLst_DemandId.NewPredicate(grmi.Equal, errorInfoId)}, []grmi.Field{meta.ToyotaDeliveryOrderErrorLst_Pos})
	if err != nil {
		return grmi.NewBusinessError("查询错误项数据失败, 错误:" + err.Error())
	}
	if len(errorLi) == 0 {
		return grmi.NewBusinessError("发运数据不存在错误项")
	}
	orderError := errorLi[0]
	doneOrder, err := deliveryOrderDao.SelectTopOneDesc([]grmi.Predicate{meta.ToyotaDeliveryOrder_Status.NewPredicate(grmi.Equal, model.DELIVERY_STATUS_DONE)}, []grmi.Field{meta.ToyotaDeliveryOrder_SortNr})
	if err != nil {
		return grmi.NewBusinessError("查询写入完成的发运单数据失败, error:" + err.Error())
	}
	if doneOrder != nil {
		if deliveryOrder.SortNr != doneOrder.SortNr+1 {
			errorContent := "发运数据连番号不连续，当前已写到:" + strconv.Itoa(doneOrder.SortNr)
			return grmi.NewBusinessError(errorContent)
		}
	}
	if err = session.Begin(); err != nil {
		return grmi.NewBusinessError("开启事务失败， 错误:" + err.Error())
	}
	deliveryOrder.Status = model.DELIVERY_STATUS_DONE
	deliveryOrder.CloseTime = grmi.DateTime(time.Now())
	err = deliveryOrderDao.UpdateOne(deliveryOrder)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("更新发运数据状态失败, 错误:"+ err.Error())
	}
	err = deliveryOrderErrorDao.DeleteWhere([]grmi.Predicate{meta.ToyotaDeliveryOrderErrorLst_DemandId.NewPredicate(grmi.Equal, errorInfoId)})
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("删除发运数据错误项失败, 错误:" + err.Error())
	}
	if orderError.ErrorType == model.ERROR_TYTPE_PLC {
		errorInfo, err := dao.SelectOne(errorInfoId, baseModel.PLC_ERROR_SOURCE_CALLOFF)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("查询PLC错误项失败, 错误:" + err.Error())
		}
		if errorInfo == nil {
			return grmi.NewBusinessError("不存在该PLC错误项")
		}
		errorInfo.Status = baseModel.WO_STATUS_FINISHED
		err = dao.UpdateOne(errorInfo)
		if err != nil {
			_ = session.Rollback()
			return grmi.NewBusinessError("更新PLC错误项状态失败, 错误:"+ err.Error())
		}
		switch errorInfo.Step {
		case 1, 2:
			err = impl.ReadSign()
			if err != nil {
				_ = session.Rollback()
				innerErr := impl.SaveCallOffPLCError(user, errorInfo.ErrorId, 1, err.Error(), errorInfo.SeatData, errorInfo.SaveStr1, errorInfo.SaveStr2)
				if innerErr != nil {
					return grmi.NewBusinessError(err.Error() + ", 保存错误失败, error:" + err.Error())
				}
				return err
			}
			err = impl.WriteSign()
			if err != nil {
				_ = session.Rollback()
				innerErr := impl.SaveCallOffPLCError(user, errorInfo.ErrorId, 2, err.Error(), errorInfo.SeatData, errorInfo.SaveStr1, errorInfo.SaveStr2)
				if innerErr != nil {
					return grmi.NewBusinessError(err.Error() + ", 保存错误失败, error:" + err.Error())
				}
				return err
			}
			fallthrough
		case 3:
			err = impl.WriteSeatData(errorInfo.SeatData)
			if err != nil {
				_ = session.Rollback()
				innerErr := impl.SaveCallOffPLCError(user, errorInfo.ErrorId, 3, err.Error(), errorInfo.SeatData, errorInfo.SaveStr1, errorInfo.SaveStr2)
				if innerErr != nil {
					return grmi.NewBusinessError(err.Error() + ", 保存错误失败, error:" + err.Error())
				}
				return err
			}
			fallthrough
		case 4:
			err = impl.WriteDoneSign()
			if err != nil {
				_ = session.Rollback()
				innerErr := impl.SaveCallOffPLCError(user, errorInfo.ErrorId, 4, err.Error(), errorInfo.SeatData, errorInfo.SaveStr1, errorInfo.SaveStr2)
				if innerErr != nil {
					return grmi.NewBusinessError(err.Error() + ", 保存错误失败, error:" + err.Error())
				}
				return err
			}
		}
	} else {
		err = impl.WriteToPLC(user, deliveryOrder)
		return err
	}

	_ = session.Commit()
	return nil
}

func (impl *ToyotaDeliveryOrderServiceImplement) SelectError(user *global.User, demandId string) (errorInfo *baseModel.PLCErrorInfo, err error) {
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := baseDal.NewPLCErrorInfoDAO(session, user.PlantNr, user.UserId)
	errorInfo, err = dao.SelectOne(demandId, baseModel.PLC_ERROR_SOURCE_CALLOFF)
	return
}
