// 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"
	meDal "LAPP_ACURA_MOM_BACKEND/dao/me"
	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"
	meMeta "LAPP_ACURA_MOM_BACKEND/meta/me"
	meta "LAPP_ACURA_MOM_BACKEND/meta/pln"
	baseModel "LAPP_ACURA_MOM_BACKEND/models/base"
	meModel "LAPP_ACURA_MOM_BACKEND/models/me"
	model "LAPP_ACURA_MOM_BACKEND/models/pln"
	"LAPP_ACURA_MOM_BACKEND/utils"
	"encoding/csv"
	"io/ioutil"
	"os"
	"path"
	"regexp"
	"strconv"
	"strings"
	"time"
)

/******************************************************************************
 *
 * @Description              : ToyotaCalloff的默认查询条件
 *
 * @Author                   : 代码生成器创建
 *
 * @Date                     : 2022-01-26 09:51:03
 *
 ******************************************************************************/
var DefaultConditionOfToyotaCalloff = grmi.NewCondition(
	map[string]grmi.ConditionItem{
		meta.ToyotaCalloff_DemandId.UrlParameterName:        grmi.NewConditionItem(meta.ToyotaCalloff_DemandId, grmi.Equal, true),
		meta.ToyotaCalloff_SupplierCode.UrlParameterName:    grmi.NewConditionItem(meta.ToyotaCalloff_SupplierCode, grmi.Equal, false),
		meta.ToyotaCalloff_ProjectId.UrlParameterName:       grmi.NewConditionItem(meta.ToyotaCalloff_ProjectId, grmi.Equal, false),
		meta.ToyotaCalloff_ProductFamilyId.UrlParameterName: grmi.NewConditionItem(meta.ToyotaCalloff_ProductFamilyId, grmi.Equal, false),
		meta.ToyotaCalloff_TotalQty.UrlParameterName:        grmi.NewConditionItem(meta.ToyotaCalloff_TotalQty, grmi.Equal, false),
		meta.ToyotaCalloff_CheckSequence.UrlParameterName:   grmi.NewConditionItem(meta.ToyotaCalloff_CheckSequence, grmi.Equal, false),
		meta.ToyotaCalloff_Parsed.UrlParameterName:          grmi.NewConditionItem(meta.ToyotaCalloff_Parsed, grmi.Equal, false),
		meta.ToyotaCalloff_OrderTime.UrlParameterName:       grmi.NewConditionItem(meta.ToyotaCalloff_OrderTime, grmi.Approximate, false),
		meta.ToyotaCalloff_OrderShift.UrlParameterName:      grmi.NewConditionItem(meta.ToyotaCalloff_OrderShift, grmi.Equal, false),
		meta.ToyotaCalloff_FileTime.UrlParameterName:        grmi.NewConditionItem(meta.ToyotaCalloff_FileTime, grmi.Approximate, false),
		meta.ToyotaCalloff_EdiFile.UrlParameterName:         grmi.NewConditionItem(meta.ToyotaCalloff_EdiFile, grmi.Equal, false),
		meta.ToyotaCalloff_EdiFileType.UrlParameterName:     grmi.NewConditionItem(meta.ToyotaCalloff_EdiFileType, grmi.Equal, false),
		meta.ToyotaCalloff_CtrlPara1.UrlParameterName:       grmi.NewConditionItem(meta.ToyotaCalloff_CtrlPara1, grmi.Equal, false),
		meta.ToyotaCalloff_CtrlPara2.UrlParameterName:       grmi.NewConditionItem(meta.ToyotaCalloff_CtrlPara2, grmi.Equal, false),
		meta.ToyotaCalloff_CtrlStr1.UrlParameterName:        grmi.NewConditionItem(meta.ToyotaCalloff_CtrlStr1, grmi.Equal, false),
		meta.ToyotaCalloff_CtrlStr2.UrlParameterName:        grmi.NewConditionItem(meta.ToyotaCalloff_CtrlStr2, grmi.Equal, false),
		meta.ToyotaCalloff_CtrlTime1.UrlParameterName:       grmi.NewConditionItem(meta.ToyotaCalloff_CtrlTime1, grmi.Approximate, false),
		meta.ToyotaCalloff_CtrlTime2.UrlParameterName:       grmi.NewConditionItem(meta.ToyotaCalloff_CtrlTime2, grmi.Approximate, false),
		meta.ToyotaCalloff_LastModify.UrlParameterName:      grmi.NewConditionItem(meta.ToyotaCalloff_LastModify, grmi.Approximate, false),
		meta.ToyotaCalloff_LastUser.UrlParameterName:        grmi.NewConditionItem(meta.ToyotaCalloff_LastUser, grmi.Equal, false),
		meta.ToyotaCalloff_CreateTime.UrlParameterName:      grmi.NewConditionItem(meta.ToyotaCalloff_CreateTime, grmi.Approximate, false),
	},
	nil,
)

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

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

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

/******************************************************************************
 *
 * @Reference LAPP_ACURA_MOM_BACKEND/services/pln/ToyotaCalloffService.InsertOne
 *
 ******************************************************************************/
func (impl *ToyotaCalloffServiceImplement) InsertOne(user *global.User, entity *model.ToyotaCalloff) error {

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

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewToyotaCalloffDAO(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/ToyotaCalloffService.DeleteOne
 *
 ******************************************************************************/
func (impl *ToyotaCalloffServiceImplement) DeleteOne(user *global.User, demandId string) error {

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

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewToyotaCalloffDAO(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/ToyotaCalloffService.SelectOne
 *
 ******************************************************************************/
func (impl *ToyotaCalloffServiceImplement) SelectOne(user *global.User, demandId string) (*model.ToyotaCalloff, error) {

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

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewToyotaCalloffDAO(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/ToyotaCalloffService.UpdateOne
 *
 ******************************************************************************/
func (impl *ToyotaCalloffServiceImplement) UpdateOne(user *global.User, entity *model.ToyotaCalloff) error {

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

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewToyotaCalloffDAO(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/ToyotaCalloffService.Insert
 *
 ******************************************************************************/
func (impl *ToyotaCalloffServiceImplement) Insert(user *global.User, entities *[]model.ToyotaCalloff) error {

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

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewToyotaCalloffDAO(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/ToyotaCalloffService.Delete
 *
 ******************************************************************************/
func (impl *ToyotaCalloffServiceImplement) Delete(user *global.User, entities *[]model.ToyotaCalloff) error {

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

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewToyotaCalloffDAO(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/ToyotaCalloffService.Select
 *
 ******************************************************************************/
func (impl *ToyotaCalloffServiceImplement) Select(user *global.User, urlParameters map[string]string) ([]model.ToyotaCalloff, error) {

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

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

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

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

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

	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	dao := dal.NewToyotaCalloffDAO(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
}

// ParseToyotaCallOffFile 解析南沙顺引
func (impl *ToyotaCalloffServiceImplement) ParseToyotaCallOffFile() {
	log, _ := logger.NewLogger("CallOff", "PLN")

	userId := "Scheduler"
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	plantDao := baseDal.NewPlantDAO(session, userId)
	plantLi, err := plantDao.Select(nil, nil)
	if err != nil {
		log.Error("解析广丰CallOff, 查询工厂数据失败, 错误：" + err.Error())
		return
	}
	for _, plant := range plantLi {
		if plant.PlantProject != baseModel.PROJECT_NANSHA {
			continue
		}
		go func(plant baseModel.Plant) {
			user := &global.User{
				UserId:  userId,
				PlantNr: plant.PlantNr,
			}
			projectDao := meDal.NewProjectDAO(session, user.PlantNr, user.UserId)
			projectLi, err := projectDao.Select(nil, []grmi.Field{meMeta.Project_ProjectId})
			if err != nil {
				log.Error("解析广丰CallOff, 查询项目数据失败, 错误：" + err.Error())
				return
			}
			for _, project := range projectLi {
				inboxPath := path.Join(conf.DbConfig.CallOffFolder, project.CalloffFolder)
				outBoxPath := path.Join(conf.DbConfig.OutCallOffFolder, project.CalloffFolder)
				errorBoxPath := path.Join(conf.DbConfig.ErrorCallOffFolder, project.CalloffFolder)
				go impl.LoadFile(user, inboxPath, outBoxPath, errorBoxPath)
			}
		}(plant)
	}

}

// LoadFile 读取目录下的文件
func (impl *ToyotaCalloffServiceImplement) LoadFile(user *global.User, inBoxPath string, outBoxPath string, errBoxPath string) {
	log, _ := logger.NewLogger("CallOff", "PLN")
	fileInfoList, err := ioutil.ReadDir(inBoxPath)
	if err != nil {
		log.Error("解析广丰CallOff, 读取项目文件路径失败, error:" + err.Error())
		return
	}
	if len(fileInfoList) == 0 {
		log.Info("解析广丰CallOff, 待解析文件为0")
		return
	}
	for _, file := range fileInfoList {
		if file.IsDir() {
			continue
		}
		filepath := path.Join(inBoxPath, file.Name())
		repeat, err := impl.ParseCsvFile(user, filepath, file.Name())
		if err != nil {
			log.Error("解析广丰CallOff， 解析失败， 文件:" + file.Name() + ", 错误:" + err.Error())
			if !repeat {
				errorPath := path.Join(errBoxPath, file.Name())
				//c := exec.Command("move", filepath, errorPath)
				//if err := c.Run(); err != nil {
				//	log.Error("解析广丰CallOff, 移动文件到错误文件夹失败，文件名:" + file.Name() + ", 错误:" + err.Error()+ ", errorPath:" + errorPath)
				//}
				err = os.Rename(filepath, errorPath)
				if err != nil {
					log.Error("解析广丰CallOff, 移动文件到错误文件夹失败，文件名:" + file.Name() + ", 错误:" + err.Error())
				}
			} else {
				log.Error("解析广丰CallOff, 解析错误且可重试，文件名:" + file.Name() + ", 错误:" + err.Error())
			}
		} else {
			movePath := path.Join(outBoxPath, file.Name())
			//c := exec.Command("move", filepath, movePath)
			//if err := c.Run(); err != nil {
			//	log.Error("解析广丰CallOff, 移动文件到已解析文件夹失败，文件名:" + file.Name() + ", 错误:" + err.Error() + ", movePath:" + movePath)
			//}
			err = os.Rename(filepath, movePath)
			if err != nil {
				log.Error("解析广丰CallOff, 移动文件到已解析文件夹失败，文件名:" + file.Name() + ", 错误:" + err.Error())
			}
		}

	}
}

// ParseCsvFile 解析csv文件
func (impl *ToyotaCalloffServiceImplement) ParseCsvFile(user *global.User, filepath string, filename string) (bool, error) {
	// 第一个返回值表示是否可以重试
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	demandId := strings.Split(filename, ".")[0]
	calloffDao := dal.NewToyotaCalloffDAO(session, user.PlantNr, user.UserId)
	existCallOff, err := calloffDao.SelectOne(demandId)
	if err != nil {
		return true, grmi.NewBusinessError("查询calloff数据失败, 错误：" + err.Error())
	}
	if existCallOff != nil {
		return true, nil
	}
	f, err := os.Open(filepath)
	if err != nil {
		return true, grmi.NewBusinessError("打开文件失败, error:" + err.Error())
	}
	defer f.Close()

	readCsv := csv.NewReader(f)
	read, err := readCsv.Read()
	if err != nil {
		return true, grmi.NewBusinessError("读取csv文件失败, error:" + err.Error())
	}
	if len(read) == 0 {
		return false, grmi.NewBusinessError("未获取到csv文件内容")
	}
	lineReg := regexp.MustCompile(`(?P<supply>.*?)\s+.*?\s+.*?\s+(?P<code>.*?)\s+(?P<seq>\d+?)\s+(?P<date>\d{13})\s+(?P<carset>[a-zA-Z0-9]+)`)
	if lineReg == nil {
		return true, grmi.NewBusinessError("初始化正则表达式失败")
	}
	matchLi := lineReg.FindStringSubmatch(read[0])
	if len(matchLi) != 6 {
		return false, grmi.NewBusinessError("未能从csv文件获取到足够的数据")
	}
	if len(matchLi[1]) < 9 {
		return false, grmi.NewBusinessError("获取到的供应商数据不足")
	}
	fileId := matchLi[1]
	supplyCode := matchLi[1][:9]
	code := matchLi[2]
	seqStr := matchLi[3]
	shift, err := strconv.Atoi(matchLi[4][8:9])
	if err != nil {
		return false, grmi.NewBusinessError("班组格式不正确")
	}
	datetimeStr := matchLi[4][:8] + matchLi[4][9:]
	productFamilyId := matchLi[5]
	seq, err := strconv.Atoi(seqStr)
	if err != nil {
		return false, grmi.NewBusinessError("获取的连番号格式错误")
	}
	datetime, err := time.ParseInLocation("200601021504", datetimeStr, utils.TimezoneLocation)
	if err != nil {
		return false, grmi.NewBusinessError("获取到的订单时间格式错误")
	}
	productFamilyDao := meDal.NewProductFamilyDAO(session, user.PlantNr, user.UserId)
	productFamily, err := productFamilyDao.SelectOne(productFamilyId)
	if err != nil {
		return true, grmi.NewBusinessError("查询车型派生失败, error:" + err.Error())
	}
	if productFamily == nil {
		return false, grmi.NewBusinessError("车型派生不存在, 派生id:" + productFamilyId)
	}
	callOff := model.ToyotaCalloff{
		DemandId:        demandId,
		SupplierCode:    supplyCode,
		ProjectId:       productFamily.ProjectId,
		ProductFamilyId: productFamilyId,
		TotalQty:        1,
		CheckSequence:   seq,
		Parsed:          model.CALLOFF_STATUS_UNPARSED,
		OrderTime:       grmi.DateTime(datetime),
		OrderShift:      shift,
		FileTime:        grmi.DateTime(time.Now()),
		EdiFile:         filename,
		EdiFileType:     "csv",
		CtrlStr1:        code,
		CtrlStr2:        fileId,
	}
	err = calloffDao.InsertOne(&callOff)
	if err != nil {
		return true, grmi.NewBusinessError("写入callOff数据失败, error:" + err.Error())
	}
	return true, nil
}

// ParseToyotaCallOffCache 解析南沙顺引换成数据
func (impl *ToyotaCalloffServiceImplement) ParseToyotaCallOffCache() {
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	defer session.Close()
	userId := "Scheduler"
	log, _ := logger.NewLogger("CallOff", "PLN")
	plantDao := baseDal.NewPlantDAO(session, userId)
	plantLi, err := plantDao.Select(nil, nil)
	if err != nil {
		log.Error("解析CallOff数据, 查询工厂数据失败， error:" + err.Error())
		return
	}
	for _, plant := range plantLi {
		if plant.PlantProject != baseModel.PROJECT_NANSHA {
			continue
		}
		go func(plant baseModel.Plant) {
			user := &global.User{
				UserId:  userId,
				PlantNr: plant.PlantNr,
			}
			projectDao := meDal.NewProjectDAO(session, user.PlantNr, user.UserId)
			projectLi, err := projectDao.Select(nil, []grmi.Field{meMeta.Project_ProjectId})
			if err != nil {
				log.Error("解析CallOff数据, 查询项目数据失败， error:" + err.Error())
				return
			}
			for _, project := range projectLi {
				go impl.ParseCallOffData(user, &project)
			}
		}(plant)
	}
}

func (impl *ToyotaCalloffServiceImplement) ParseCallOffData(user *global.User, project *meModel.Project) {
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	errSession := engine.NewSession()
	defer session.Close()
	log, _ := logger.NewLogger("CallOff", "PLN")
	callOffDao := dal.NewToyotaCalloffDAO(session, user.PlantNr, user.UserId)
	callOffErrDao := dal.NewToyotaCallOffErrorLstDAO(errSession, user.PlantNr, user.UserId)
	deliveryOrderDao := dal.NewToyotaDeliveryOrderDAO(session, user.PlantNr, user.UserId)
	productFamilyRelateDao := meDal.NewProductFamilyRelateDAO(session, user.PlantNr, user.UserId)
	productFamilyDao := meDal.NewProductFamilyDAO(session, user.PlantNr, user.UserId)

	waitParseLi, err := callOffDao.Select([]grmi.Predicate{meta.ToyotaCalloff_ProjectId.NewPredicate(grmi.Equal, project.ProjectId),
		meta.ToyotaCalloff_Parsed.NewPredicate(grmi.Equal, model.CALLOFF_STATUS_UNPARSED)}, []grmi.Field{meta.ToyotaCalloff_CheckSequence})
	if err != nil {
		log.Error("解析CallOff数据,获取带解析的CallOff数据失败, error:" + err.Error())
		return
	}
	if len(waitParseLi) == 0 {
		log.Info("解析CallOff数据, 没有待解析的CallOff数据")
	}
	maxSeqCallOff, err := callOffDao.SelectMaxSeqCallOff()
	if err != nil {
		log.Error("解析CallOff数据,获取已解析的最大连番号CallOff数据失败, error:" + err.Error())
		return
	}
	//maxSortNr, err := deliveryOrderDao.GetMaxSortNr(project.ProjectId)
	//if err != nil {
	//	log.Error("解析CallOff数据, 获取最大sortNr失败, error:" + err.Error())
	//	return
	//}
	var needParseSeq int
	if maxSeqCallOff != nil {
		if maxSeqCallOff.CheckSequence == 999 {
			needParseSeq = 0
		} else {
			needParseSeq = maxSeqCallOff.CheckSequence + 1
		}
	} else {
		needParseSeq = -1
	}
	if err = session.Begin(); err != nil {
		log.Error("解析CallOff数据, 开启事务失败, error:" + err.Error())
		return
	}
	if err = errSession.Begin(); err != nil {
		log.Error("解析CallOff数据, 开启事务失败, error:" + err.Error())
		return
	}
	defer func() {
		_ = errSession.Commit()
	}()
	productFamilyMap := make(map[string]*meModel.ProductFamily)
	productFamilyRelateMap := make(map[string][]meModel.Product)
	for _, callOffData := range waitParseLi {
		err = callOffErrDao.DeleteWhere([]grmi.Predicate{meta.ToyotaCallOffErrorLst_DemandId.NewPredicate(grmi.Equal, callOffData.DemandId)})
		if err != nil {
			_ = session.Rollback()
			log.Error("解析CallOff数据,删除已存在的错误数据失败, error:" + err.Error())
			return
		}
		if callOffData.CheckSequence != needParseSeq {
			if callOffData.CheckSequence != needParseSeq+1 || (needParseSeq == 999 && callOffData.CheckSequence != 0) {
				callOffError := model.ToyotaCallOffErrorLst{
					DemandId:    callOffData.DemandId,
					Pos:         1,
					ErrorType:   model.ERROR_TYPE_HINT,
					ErrorInfo:   "连番号不连续，当前需要解析连番号为:" + strconv.Itoa(needParseSeq) + ", 该连番号为:" + strconv.Itoa(callOffData.CheckSequence),
					ErrorStatus: model.ERROR_STATUS_ON,
				}
				err = callOffErrDao.InsertOne(&callOffError)
				if err != nil {
					_ = session.Rollback()
					log.Error("解析CallOff数据, 写入错误信息失败, error:" + err.Error())
					return
				}
				break
			}
		}

		needParseSeq = callOffData.CheckSequence + 1
		productFamily, exist := productFamilyMap[callOffData.ProductFamilyId]
		if !exist {
			productFamily, err = productFamilyDao.SelectOne(callOffData.ProductFamilyId)
			if err != nil {
				callOffError := model.ToyotaCallOffErrorLst{
					DemandId:    callOffData.DemandId,
					Pos:         1,
					ErrorType:   model.ERROR_TYPE_SYSTEM,
					ErrorInfo:   "查询派生数据失败, error:" + err.Error(),
					ErrorStatus: model.ERROR_STATUS_ON,
				}
				err = callOffErrDao.InsertOne(&callOffError)
				if err != nil {
					_ = session.Rollback()
					log.Error("解析CallOff数据, 写入错误信息失败, error:" + err.Error())
					return
				}
				break
			}
			if productFamily == nil {
				callOffError := model.ToyotaCallOffErrorLst{
					DemandId:    callOffData.DemandId,
					Pos:         1,
					ErrorType:   model.ERROR_TYPE_DATA,
					ErrorInfo:   "派生不存在",
					ErrorStatus: model.ERROR_STATUS_ON,
				}
				err = callOffErrDao.InsertOne(&callOffError)
				if err != nil {
					_ = session.Rollback()
					log.Error("解析CallOff数据, 写入错误信息失败, error:" + err.Error())
					return
				}
				break
			}
			productFamilyMap[callOffData.ProductFamilyId] = productFamily
		}

		var seatData string
		if productFamily.CtrlPara1 == 1 { // 如果座椅是安道拓的
			productLi, exist := productFamilyRelateMap[callOffData.ProductFamilyId]
			if !exist {
				productLi, err = productFamilyRelateDao.SelectProductByFamilyId(project.ProjectId, callOffData.ProductFamilyId)
				if err != nil {
					callOffError := model.ToyotaCallOffErrorLst{
						DemandId:    callOffData.DemandId,
						Pos:         1,
						ErrorType:   model.ERROR_TYPE_SYSTEM,
						ErrorInfo:   "查询派生下座椅总成失败",
						ErrorStatus: model.ERROR_STATUS_ON,
					}
					err = callOffErrDao.InsertOne(&callOffError)
					if err != nil {
						_ = session.Rollback()
						log.Error("解析CallOff数据, 写入错误信息失败, error:" + err.Error())
						return
					}
					break
				}
				if len(productLi) == 0 {
					callOffError := model.ToyotaCallOffErrorLst{
						DemandId:    callOffData.DemandId,
						Pos:         1,
						ErrorType:   model.ERROR_TYPE_DATA,
						ErrorInfo:   "该派生下没有关联座椅",
						ErrorStatus: model.ERROR_STATUS_ON,
					}
					err = callOffErrDao.InsertOne(&callOffError)
					if err != nil {
						_ = session.Rollback()
						log.Error("解析CallOff数据, 写入错误信息失败, error:" + err.Error())
						return
					}
					break
				}
				productFamilyRelateMap[callOffData.ProductFamilyId] = productLi
			}
			seatData, err = impl.MakeUpSeatData(productLi)
			if err != nil {
				callOffError := model.ToyotaCallOffErrorLst{
					DemandId:    callOffData.DemandId,
					Pos:         1,
					ErrorType:   model.ERROR_TYPE_DATA,
					ErrorInfo:   err.Error(),
					ErrorStatus: model.ERROR_STATUS_ON,
				}
				err = callOffErrDao.InsertOne(&callOffError)
				if err != nil {
					_ = session.Rollback()
					log.Error("解析CallOff数据, 写入错误信息失败, error:" + err.Error())
					return
				}
				break
			}
		} else { // 如果座椅是樱泰的
			seatData = productFamily.ProductFamilyId
			for i := len(seatData); i < 25; i++ {
				seatData += "0"
			}
		}

		plcCode := `1` + strconv.Itoa(productFamily.CtrlPara1) + seatData
		deliveryOrder := model.ToyotaDeliveryOrder{
			DemandId:        callOffData.DemandId,
			SortNr:          callOffData.CheckSequence,
			ProductFamilyId: callOffData.ProductFamilyId,
			ProjectId:       project.ProjectId,
			PlcIpAddress:    conf.DbConfig.CallOffPlcAddress,
			PlcCode:         plcCode,
			Status:          model.DELIVERY_STATUS_PLAN,
		}
		err = deliveryOrderDao.InsertOne(&deliveryOrder)
		if err != nil {
			callOffError := model.ToyotaCallOffErrorLst{
				DemandId:    callOffData.DemandId,
				Pos:         1,
				ErrorType:   model.ERROR_TYPE_SYSTEM,
				ErrorInfo:   "写入发运数据失败, error:" + err.Error(),
				ErrorStatus: model.ERROR_STATUS_ON,
			}
			err = callOffErrDao.InsertOne(&callOffError)
			if err != nil {
				_ = session.Rollback()
				log.Error("解析CallOff数据, 写入错误信息失败, error:" + err.Error())
				return
			}
			break
		}
		callOffData.Parsed = model.CALLOFF_STATUS_PARSED
		err = callOffDao.UpdateOne(&callOffData)
		if err != nil {
			_ = session.Rollback()
			log.Error("解析CallOff数据, 更新CallOff状态失败, error:" + err.Error())
			return
		}
	}
	_ = session.Commit()
	log.Info("解析CallOff数据任务执行完成，当前项目:"+project.ProjectId+", 最大MaxSeq:", strconv.Itoa(needParseSeq-1))
	return
}

func (impl *ToyotaCalloffServiceImplement) MakeUpSeatData(productLi []meModel.Product) (string, error) {
	seatMap := make(map[string]meModel.Product)
	var seatData string
	for _, product := range productLi {
		seatMap[product.CtrlStr1] = product
	}
	product, exist := seatMap[meModel.PRODUCT_TYPE_MS]
	if !exist {
		errInfo := "包装单子项中不存在主驾"
		return "", grmi.NewBusinessError(errInfo)
	}
	seatData += product.MachineCode
	seatData += product.ColorValue
	product, exist = seatMap[meModel.PRODUCT_TYPE_PS]
	if !exist {
		errInfo := "包装单子项中不存在副驾"
		return "", grmi.NewBusinessError(errInfo)
	}
	seatData += product.MachineCode
	seatData += product.ColorValue
	product, exist = seatMap[meModel.PRODUCT_TYPE_40]
	if !exist {
		errInfo := "包装单子项中不存在40%"
		return "", grmi.NewBusinessError(errInfo)
	}
	seatData += product.MachineCode
	seatData += product.ColorValue
	product, exist = seatMap[meModel.PRODUCT_TYPE_60]
	if !exist {
		errInfo := "包装单子项中不存在60%"
		return "", grmi.NewBusinessError(errInfo)
	}
	seatData += product.MachineCode
	seatData += product.ColorValue
	product, exist = seatMap[meModel.PRODUCT_TYPE_CUSHION]
	if !exist {
		errInfo := "包装单子项中不存在坐垫"
		return "", grmi.NewBusinessError(errInfo)
	}
	seatData += product.MachineCode
	seatData += product.ColorValue
	return seatData, nil
}

// AnalysisAgain 重新解析CallOff
func (impl *ToyotaCalloffServiceImplement) AnalysisAgain(user *global.User, demandId string) error {
	engine := db.Eloquent.Master()
	session := engine.NewSession()
	errSession := engine.NewSession()
	defer session.Close()
	defer errSession.Close()
	callOffDao := dal.NewToyotaCalloffDAO(session, user.PlantNr, user.UserId)
	callOffErrDao := dal.NewToyotaCallOffErrorLstDAO(errSession, user.PlantNr, user.UserId)
	deliveryOrderDao := dal.NewToyotaDeliveryOrderDAO(session, user.PlantNr, user.UserId)
	productFamilyRelateDao := meDal.NewProductFamilyRelateDAO(session, user.PlantNr, user.UserId)
	productFamilyDao := meDal.NewProductFamilyDAO(session, user.PlantNr, user.UserId)
	callOff, err := callOffDao.SelectOne(demandId)
	if err != nil {
		return grmi.NewBusinessError("查询CallOff数据失败, 错误:" + err.Error())
	}
	if callOff == nil {
		return grmi.NewBusinessError("CallOff不存在")
	}
	errorLi, err := callOffErrDao.Select([]grmi.Predicate{meta.ToyotaCallOffErrorLst_DemandId.NewPredicate(grmi.Equal, demandId),
		meta.ToyotaCallOffErrorLst_ErrorStatus.NewPredicate(grmi.Equal, model.ERROR_STATUS_ON),
		meta.ToyotaCallOffErrorLst_ErrorType.NewPredicate(grmi.Equal, model.ERROR_TYPE_DATA)}, nil)
	if len(errorLi) != 0 {
		return grmi.NewBusinessError("存在未修复的数据项错误")
	}
	doneCallOff, err := callOffDao.SelectMaxSeqCallOff()
	if err != nil {
		return grmi.NewBusinessError("查询已解析最大连番号CallOff数据失败, 错误:" + err.Error())
	}
	if doneCallOff != nil {
		var needParseSequence int
		if doneCallOff.CheckSequence != 999 {
			needParseSequence = doneCallOff.CheckSequence + 1
		}
		if callOff.CheckSequence != needParseSequence {
			return grmi.NewBusinessError("当前连番号大于需要解析的连番号,需要解析连番号为:" + strconv.Itoa(needParseSequence))
		}
	}
	err = callOffErrDao.DeleteWhere([]grmi.Predicate{meta.ToyotaCallOffErrorLst_DemandId.NewPredicate(grmi.Equal, demandId)})
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("解析CallOff数据,删除已存在的错误数据失败, error:" + err.Error())
	}
	productFamilyMap := make(map[string]*meModel.ProductFamily)
	productFamilyRelateMap := make(map[string][]meModel.Product)
	productFamily, exist := productFamilyMap[callOff.ProductFamilyId]
	var innerErr error
	if !exist {
		productFamily, err = productFamilyDao.SelectOne(callOff.ProductFamilyId)
		if err != nil {
			_ = session.Rollback()
			callOffError := model.ToyotaCallOffErrorLst{
				DemandId:    callOff.DemandId,
				Pos:         1,
				ErrorType:   model.ERROR_TYPE_SYSTEM,
				ErrorInfo:   "查询派生数据失败, error:" + err.Error(),
				ErrorStatus: model.ERROR_STATUS_ON,
			}
			innerErr = callOffErrDao.InsertOne(&callOffError)
			if innerErr != nil {
				return grmi.NewBusinessError("解析CallOff数据, 写入错误信息失败, 解析错误:" + err.Error())
			}
			return grmi.NewBusinessError("查询派生数据失败, error:" + err.Error())
		}
		if productFamily == nil {
			_ = session.Rollback()
			callOffError := model.ToyotaCallOffErrorLst{
				DemandId:    callOff.DemandId,
				Pos:         1,
				ErrorType:   model.ERROR_TYPE_DATA,
				ErrorInfo:   "派生不存在",
				ErrorStatus: model.ERROR_STATUS_ON,
			}
			innerErr = callOffErrDao.InsertOne(&callOffError)
			if innerErr != nil {
				return grmi.NewBusinessError("解析CallOff数据, 写入错误信息失败, 解析错误:" + err.Error())
			}
			return grmi.NewBusinessError("派生不存在")
		}
		productFamilyMap[callOff.ProductFamilyId] = productFamily
	}
	productLi, exist := productFamilyRelateMap[callOff.ProductFamilyId]
	if !exist {
		productLi, err = productFamilyRelateDao.SelectProductByFamilyId(callOff.ProjectId, callOff.ProductFamilyId)
		if err != nil {
			_ = session.Rollback()
			callOffError := model.ToyotaCallOffErrorLst{
				DemandId:    callOff.DemandId,
				Pos:         1,
				ErrorType:   model.ERROR_TYPE_SYSTEM,
				ErrorInfo:   "查询派生下座椅总成失败",
				ErrorStatus: model.ERROR_STATUS_ON,
			}
			innerErr = callOffErrDao.InsertOne(&callOffError)
			if innerErr != nil {
				return grmi.NewBusinessError("解析CallOff数据, 写入错误信息失败, 解析错误:" + err.Error())
			}
			return grmi.NewBusinessError("查询派生下座椅总成失败")
		}
		if len(productLi) == 0 {
			_ = session.Rollback()
			callOffError := model.ToyotaCallOffErrorLst{
				DemandId:    callOff.DemandId,
				Pos:         1,
				ErrorType:   model.ERROR_TYPE_DATA,
				ErrorInfo:   "该派生下没有关联座椅",
				ErrorStatus: model.ERROR_STATUS_ON,
			}
			innerErr = callOffErrDao.InsertOne(&callOffError)
			if innerErr != nil {
				return grmi.NewBusinessError("解析CallOff数据, 写入错误信息失败, 解析错误:" + err.Error())
			}
			return grmi.NewBusinessError("该派生下没有关联座椅")
		}
		productFamilyRelateMap[callOff.ProductFamilyId] = productLi
	}
	var seatData string
	seatMap := make(map[string]meModel.Product)
	for _, product := range productLi {
		seatMap[product.CtrlStr1] = product
	}
	product, exist := seatMap[meModel.PRODUCT_TYPE_MS]
	if !exist {
		_ = session.Rollback()
		errInfo := "包装单子项中不存在主驾"
		callOffError := model.ToyotaCallOffErrorLst{
			DemandId:    callOff.DemandId,
			Pos:         1,
			ErrorType:   model.ERROR_TYPE_DATA,
			ErrorInfo:   errInfo,
			ErrorStatus: model.ERROR_STATUS_ON,
		}
		innerErr = callOffErrDao.InsertOne(&callOffError)
		if innerErr != nil {
			return grmi.NewBusinessError("解析CallOff数据, 写入错误信息失败, 解析错误:" + errInfo)
		}
		return grmi.NewBusinessError(errInfo)
	}
	seatData += product.MachineCode
	seatData += product.ColorValue
	product, exist = seatMap[meModel.PRODUCT_TYPE_PS]
	if !exist {
		_ = session.Rollback()
		errInfo := "包装单子项中不存在副驾"
		callOffError := model.ToyotaCallOffErrorLst{
			DemandId:    callOff.DemandId,
			Pos:         1,
			ErrorType:   model.ERROR_TYPE_DATA,
			ErrorInfo:   errInfo,
			ErrorStatus: model.ERROR_STATUS_ON,
		}
		innerErr = callOffErrDao.InsertOne(&callOffError)
		if innerErr != nil {
			return grmi.NewBusinessError("解析CallOff数据, 写入错误信息失败, 解析错误:" + errInfo)
		}
		return grmi.NewBusinessError(errInfo)
	}
	seatData += product.MachineCode
	seatData += product.ColorValue
	product, exist = seatMap[meModel.PRODUCT_TYPE_40]
	if !exist {
		_ = session.Rollback()
		errInfo := "包装单子项中不存在40%"
		callOffError := model.ToyotaCallOffErrorLst{
			DemandId:    callOff.DemandId,
			Pos:         1,
			ErrorType:   model.ERROR_TYPE_DATA,
			ErrorInfo:   errInfo,
			ErrorStatus: model.ERROR_STATUS_ON,
		}
		innerErr = callOffErrDao.InsertOne(&callOffError)
		if innerErr != nil {
			return grmi.NewBusinessError("解析CallOff数据, 写入错误信息失败, 解析错误:" + errInfo)
		}
		return grmi.NewBusinessError(errInfo)
	}
	seatData += product.MachineCode
	seatData += product.ColorValue
	product, exist = seatMap[meModel.PRODUCT_TYPE_60]
	if !exist {
		_ = session.Rollback()
		errInfo := "包装单子项中不存在60%"
		callOffError := model.ToyotaCallOffErrorLst{
			DemandId:    callOff.DemandId,
			Pos:         1,
			ErrorType:   model.ERROR_TYPE_DATA,
			ErrorInfo:   errInfo,
			ErrorStatus: model.ERROR_STATUS_ON,
		}
		innerErr = callOffErrDao.InsertOne(&callOffError)
		if innerErr != nil {
			return grmi.NewBusinessError("解析CallOff数据, 写入错误信息失败, 解析错误:" + errInfo)
		}
		return grmi.NewBusinessError(errInfo)
	}
	seatData += product.MachineCode
	seatData += product.ColorValue
	product, exist = seatMap[meModel.PRODUCT_TYPE_CUSHION]
	if !exist {
		_ = session.Rollback()
		errInfo := "包装单子项中不存在坐垫"
		callOffError := model.ToyotaCallOffErrorLst{
			DemandId:    callOff.DemandId,
			Pos:         1,
			ErrorType:   model.ERROR_TYPE_DATA,
			ErrorInfo:   errInfo,
			ErrorStatus: model.ERROR_STATUS_ON,
		}
		innerErr = callOffErrDao.InsertOne(&callOffError)
		if innerErr != nil {
			return grmi.NewBusinessError("解析CallOff数据, 写入错误信息失败, 解析错误:" + errInfo)
		}
		return grmi.NewBusinessError(errInfo)
	}
	seatData += product.MachineCode
	seatData += product.ColorValue
	plcCode := `1` + strconv.Itoa(productFamily.CtrlPara1) + seatData
	deliveryOrder := model.ToyotaDeliveryOrder{
		DemandId:        callOff.DemandId,
		SortNr:          callOff.CheckSequence,
		ProductFamilyId: callOff.ProductFamilyId,
		ProjectId:       callOff.ProjectId,
		PlcIpAddress:    conf.DbConfig.CallOffPlcAddress,
		PlcCode:         plcCode,
		Status:          model.DELIVERY_STATUS_PLAN,
	}
	err = deliveryOrderDao.InsertOne(&deliveryOrder)
	if err != nil {
		_ = session.Rollback()
		errorInfo := "写入发运数据失败:" + err.Error()
		callOffError := model.ToyotaCallOffErrorLst{
			DemandId:    callOff.DemandId,
			Pos:         1,
			ErrorType:   model.ERROR_TYPE_SYSTEM,
			ErrorInfo:   "写入发运数据失败, error:" + err.Error(),
			ErrorStatus: model.ERROR_STATUS_ON,
		}
		innerErr = callOffErrDao.InsertOne(&callOffError)
		if innerErr != nil {
			return grmi.NewBusinessError("解析CallOff数据, 写入错误信息失败, 解析错误:" + errorInfo)
		}
		return grmi.NewBusinessError(errorInfo)
	}
	callOff.Parsed = model.CALLOFF_STATUS_PARSED
	err = callOffDao.UpdateOne(callOff)
	if err != nil {
		_ = session.Rollback()
		return grmi.NewBusinessError("解析CallOff数据, 更新CallOff状态失败, error:" + err.Error())
	}
	_ = session.Commit()
	return nil
}
