package contract

import (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/beego/beego/v2/client/orm"
	"github.com/shopspring/decimal"
	"hongze/hz_crm_api/models"
	"hongze/hz_crm_api/models/company"
	"hongze/hz_crm_api/models/contract"
	"hongze/hz_crm_api/models/contract/request"
	"hongze/hz_crm_api/models/system"
	"hongze/hz_crm_api/services"
	"hongze/hz_crm_api/utils"
	"mime/multipart"
	"os"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"time"
)

// AddContract 新增合同
func AddContract(req request.AddContractReq, sellerId, productId int, sellerName string) (newContract *contract.Contract, err error, errMsg string) {
	originalPrice := req.OriginalPrice
	price := req.Price
	if originalPrice < 0 {
		err = errors.New("合同金额不能小于0")
		return
	}
	//如果优惠后金额小于等于0，那么就是等于优惠前的金额
	if price <= 0 {
		price = originalPrice
	}

	//合同日期
	var startDate, endDate time.Time
	if req.ContractBusinessType == "代付合同" {
		businessContractInfo, tmpErr := contract.GetContractById(req.RelationContractId)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		startDate = businessContractInfo.StartDate
		endDate = businessContractInfo.EndDate

		ok, tmpErr := CheckContractPrice(businessContractInfo, price)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		if !ok {
			err = errors.New("合同金额异常，不能高于业务合同金额")
			errMsg = "合同金额异常，不能高于业务合同金额"
			return
		}
	} else {
		tmpStartDate, tmpErr := time.ParseInLocation(utils.FormatDate, req.StartDate, time.Local)
		if tmpErr != nil {
			err = errors.New(fmt.Sprint("合同开始日期转换失败：", tmpErr))
			return
		}
		startDate = tmpStartDate
		tmpEndDate, tmpErr := time.ParseInLocation(utils.FormatDate, req.EndDate, time.Local)
		if tmpErr != nil {
			err = errors.New(fmt.Sprint("合同结束日期转换失败：", tmpErr))
			return
		}
		endDate = tmpEndDate
	}
	companyName := req.CompanyName
	if companyName == "" {
		err = errors.New("客户名称必填")
		return
	}
	creditCode := req.CreditCode
	if companyName == "" {
		err = errors.New("社会统一信用代码必填")
		return
	}
	contractCode, err := contract.GetCompanyContractCode(productId, req.ContractBusinessType)
	if err != nil {
		err = errors.New(fmt.Sprint("合同编号生成异常,Err:", err))
		return
	}
	contractInfo := &contract.Contract{
		ContractCode:         contractCode,
		SellerId:             sellerId,
		SellerName:           sellerName,
		ProductId:            productId,
		ContractType:         req.ContractType,
		ContractBusinessType: req.ContractBusinessType,
		Status:               "待提交",
		StartDate:            startDate,
		EndDate:              endDate,
		OriginalPrice:        originalPrice,
		Price:                price,
		PayRemark:            utils.TrimStr(req.PayRemark),  //付款方式说明,长度255位
		PayChannel:           utils.TrimStr(req.PayChannel), //付款渠道,长度255位
		CompanyName:          utils.TrimStr(companyName),
		CreditCode:           utils.TrimStr(creditCode),
		ProvinceId:           req.ProvinceId,
		Province:             utils.TrimStr(req.Province),
		CityId:               req.CityId,
		City:                 utils.TrimStr(req.City),
		Address:              utils.TrimStr(req.Address),
		Fax:                  utils.TrimStr(req.Fax),
		Phone:                utils.TrimStr(req.Phone),
		Postcode:             utils.TrimStr(req.Postcode),
		Remark:               req.Remark,
		SellerRemark:         req.SellerRemark, //销售备注
		TemplateId:           req.TemplateId,
		SourceId:             req.SourceId, //来源合同id
		ModifyTime:           time.Now(),
		CreateTime:           time.Now(),
	}

	contractServiceSlice, err := getContractServiceAndDetail(contractInfo.ProductId, req.Service, true)
	if err != nil {
		return
	}

	newContract, err = contract.AddContract(contractInfo, contractServiceSlice, req.RelationContractId)
	if err != nil {
		return
	}

	//添加操作日志
	remark := "新增合同模板"
	if newContract.SourceId > 0 {
		remark = "复制模板"
	}
	_ = contract.AddContractOperationRecord(newContract.ContractId, newContract.SellerId, 0, "add", newContract.SellerName, remark)
	return
}

// EditContract 编辑合同
func EditContract(req request.EditContractReq, opUser *system.Admin) (newContract *contract.Contract, err error, errMsg string) {
	//查询当前合同信息
	nowContract, err := contract.GetContractById(req.ContractId)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			err = errors.New(fmt.Sprint("根据合同编号:", req.ContractId, " 找不到初始合同"))
		}
		return
	}
	if nowContract.SellerId != opUser.AdminId {
		err = errors.New("当前账号无操作权限")
		return
	}
	ignoreStatus := []string{"待提交", "已撤回", "已驳回", "已审批"}
	if !strings.Contains(strings.Join(ignoreStatus, ","), nowContract.Status) {
		err = errors.New("合同状态异常，不允许修改，当前合同状态：" + nowContract.Status)
		return
	}

	originalPrice := req.OriginalPrice
	price := req.Price
	if originalPrice < 0 {
		err = errors.New("合同金额不能小于0")
		return
	}
	//如果优惠后金额小于等于0，那么就是等于优惠前的金额
	if price <= 0 {
		price = originalPrice
	}

	checkPrice := price //代付合同，需要检查的需要支付的余额

	// 是否更新业务合同金额
	updateBusinessContractPrice := 0.0
	if nowContract.Status == "已审批" && nowContract.ContractBusinessType == "代付合同" {
		updateBusinessContractPrice = nowContract.Price

		//因为当前代付合同是已审批的，所以修改重审的时候：
		//需要检查的需要支付的余额 = 当前提交的金额 - 之前提交的金额
		checkPrice = price - nowContract.Price
	}

	//合同日期
	var startDate, endDate time.Time
	if nowContract.ContractBusinessType == "代付合同" {
		businessContractInfo, tmpErr := contract.GetContractById(req.RelationContractId)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		startDate = businessContractInfo.StartDate
		endDate = businessContractInfo.EndDate

		ok, tmpErr := CheckContractPrice(businessContractInfo, checkPrice)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		if !ok {
			err = errors.New("合同金额异常，不能高于业务合同金额")
			errMsg = "合同金额异常，不能高于业务合同金额"
			return
		}
	} else {
		tmpStartDate, tmpErr := time.ParseInLocation(utils.FormatDate, req.StartDate, time.Local)
		if tmpErr != nil {
			err = errors.New(fmt.Sprint("合同开始日期转换失败：", tmpErr))
			return
		}
		startDate = tmpStartDate
		tmpEndDate, tmpErr := time.ParseInLocation(utils.FormatDate, req.EndDate, time.Local)
		if tmpErr != nil {
			err = errors.New(fmt.Sprint("合同结束日期转换失败：", tmpErr))
			return
		}
		endDate = tmpEndDate
	}

	companyName := utils.TrimStr(req.CompanyName)
	if companyName == "" {
		err = errors.New("客户名称必填")
		return
	}
	creditCode := utils.TrimStr(req.CreditCode)
	if companyName == "" {
		err = errors.New("社会统一信用代码必填")
		return
	}

	modifyContent := "" //变更记录

	nowContract.ContractType = req.ContractType            //合同类型
	nowContract.StartDate = startDate                      //合同开始日期
	nowContract.EndDate = endDate                          //合同结束日期
	nowContract.OriginalPrice = originalPrice              //原始金额
	nowContract.Price = price                              //优惠后的金额
	nowContract.PayRemark = utils.TrimStr(req.PayRemark)   //付款方式说明,长度255位
	nowContract.PayChannel = utils.TrimStr(req.PayChannel) //付款渠道,长度255位
	nowContract.CompanyName = companyName                  //企业客户名称
	nowContract.CreditCode = creditCode                    //组织社会信用代码
	nowContract.ProvinceId = req.ProvinceId                //省级id
	nowContract.Province = utils.TrimStr(req.Province)     //省
	nowContract.CityId = req.CityId                        //市级id
	nowContract.City = utils.TrimStr(req.City)             //市
	nowContract.Address = utils.TrimStr(req.Address)       //详细地址
	nowContract.Fax = utils.TrimStr(req.Fax)               //传真
	nowContract.Phone = utils.TrimStr(req.Phone)           //电话
	nowContract.FileUrl = ""                               //修改合同后，需要移除原有的合同附件
	nowContract.Postcode = utils.TrimStr(req.Postcode)     //邮编
	nowContract.Remark = req.Remark                        //补充说明
	nowContract.SellerRemark = req.SellerRemark            //销售备注
	nowContract.ModifyTime = time.Now()                    //更新时间
	nowContract.Status = "待提交"                             //合同状态

	//获取服务信息
	contractServiceSlice, err := getContractServiceAndDetail(nowContract.ProductId, req.Service, true)
	if err != nil {
		return
	}

	//最近一次审批通过或者驳回的申请单
	lastContractApproval, err := contract.GetLastContractApprovalByContractIdAndStatus(nowContract.ContractId, "contract")
	if err != nil && err.Error() != utils.ErrNoRow() {
		return
	}
	//如果有申请记录，且申请单的状态是已审批，那么审核内容是：修改重审
	if lastContractApproval != nil {
		//旧的合同信息
		var snapshotContract contract.ContractDetail
		jsonErr := json.Unmarshal([]byte(lastContractApproval.ContractDetail), &snapshotContract)
		if jsonErr != nil {
			err = jsonErr
			return
		}
		//applyContent = "修改重审"

		modifyContentStrList := make([]string, 0)
		//客户信息
		updateCompanyInfoStrList := contrastCompanyInfo(snapshotContract, *nowContract)
		if len(updateCompanyInfoStrList) > 0 {
			updateCompanyInfoStr := ``
			if len(updateCompanyInfoStrList) == 1 {
				updateCompanyInfoStr = fmt.Sprint("客户信息发生了变化:" + updateCompanyInfoStrList[0])
			} else {
				updateCompanyInfoStr = fmt.Sprint("客户信息发生了变化:</n>", strings.Join(updateCompanyInfoStrList, "</n>"))
			}
			modifyContentStrList = append(modifyContentStrList, updateCompanyInfoStr)
		}

		//金额、付款、合同日期方式
		updatePayInfoStrList := contrastPayInfo(snapshotContract, *nowContract)
		modifyContentStrList = append(modifyContentStrList, updatePayInfoStrList...)
		if len(modifyContentStrList) > 0 {
			modifyContent = strings.Join(updatePayInfoStrList, "<br/>")
		}

		//服务内容
		updateServiceStr, tmpErr := contrastServiceInfo(snapshotContract, contractServiceSlice)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		if updateServiceStr != "" {
			modifyContentStrList = append(modifyContentStrList, updateServiceStr)
		}

		//补充内容
		if nowContract.Remark != snapshotContract.Remark {
			snapshotContractRemark := snapshotContract.Remark
			if snapshotContractRemark == "" {
				snapshotContractRemark = "无"
			}
			nowContractRemark := nowContract.Remark
			if nowContractRemark == "" {
				nowContractRemark = "无"
			}
			updateStr := fmt.Sprint("原补充内容：", snapshotContractRemark, "</n>现补充内容：", nowContractRemark)
			modifyContentStrList = append(modifyContentStrList, updateStr)
		}

		if len(modifyContentStrList) > 0 {
			modifyContent = strings.Join(modifyContentStrList, "<br/>")
		}

	}
	nowContract.ModifyContent = modifyContent //修改信息

	updateDetailCol := []string{"ContractType", "StartDate", "EndDate", "OriginalPrice", "Price", "PayRemark", "PayChannel", "CompanyName", "CreditCode", "ProvinceId", "Province", "CityId", "City", "Address", "Fax", "Phone", "FileUrl", "Postcode", "Remark", "SellerRemark", "ModifyContent", "ModifyTime", "Status"}

	//修改合同
	err = contract.EditContract(nowContract, updateDetailCol, contractServiceSlice, req.RelationContractId)

	//添加操作日志
	remark := "编辑合同模板"
	_ = contract.AddContractOperationRecord(nowContract.ContractId, nowContract.SellerId, 0, "edit", nowContract.SellerName, remark)

	//修改业务合同的已支付金额
	if updateBusinessContractPrice > 0 {
		go updateContractPaidPriceByPaymentOnBehalfContractId(nowContract.ContractId, -nowContract.Price)
	}

	//赋值返回
	newContract = nowContract
	return
}

// contrastCompanyInfo 比对客户信息是否变更
func contrastCompanyInfo(snapshotContract contract.ContractDetail, nowContract contract.Contract) (updateStrList []string) {
	//客户信息比对
	if nowContract.CompanyName != snapshotContract.CompanyName {
		updateStrList = append(updateStrList, fmt.Sprint("原客户名称：", snapshotContract.CompanyName, "</n>现客户名称：", nowContract.CompanyName))
	}
	if nowContract.CreditCode != snapshotContract.CreditCode {
		updateStrList = append(updateStrList, fmt.Sprint("原社会信用码：", snapshotContract.CreditCode, "</n>现社会信用码：", nowContract.CreditCode))
	}
	if nowContract.Province != snapshotContract.Province || nowContract.City != snapshotContract.City {
		updateStrList = append(updateStrList, fmt.Sprint("原公司地址：", snapshotContract.Province, snapshotContract.City, "</n>现公司地址：", nowContract.Province, nowContract.City))
	}
	if nowContract.Address != snapshotContract.Address {
		snapshotContractAddress := snapshotContract.Address
		if snapshotContractAddress == "" {
			snapshotContractAddress = `无`
		}
		nowContractAddress := nowContract.Address
		if nowContractAddress == "" {
			nowContractAddress = `无`
		}
		updateStrList = append(updateStrList, fmt.Sprint("原详细地址：", snapshotContractAddress, "</n>现详细地址：", nowContractAddress))
	}
	if nowContract.Fax != snapshotContract.Fax {
		snapshotContractFax := snapshotContract.Fax
		if snapshotContractFax == "" {
			snapshotContractFax = `无`
		}
		nowContractFax := nowContract.Fax
		if nowContractFax == "" {
			nowContractFax = `无`
		}
		updateStrList = append(updateStrList, fmt.Sprint("原传真：", snapshotContractFax, "</n>现传真：", nowContractFax))
	}
	if nowContract.Phone != snapshotContract.Phone {
		snapshotContractPhone := snapshotContract.Phone
		if snapshotContractPhone == "" {
			snapshotContractPhone = `无`
		}
		nowContractPhone := nowContract.Phone
		if nowContractPhone == "" {
			nowContractPhone = `无`
		}
		updateStrList = append(updateStrList, fmt.Sprint("原电话：", snapshotContractPhone, "</n>现电话：", nowContractPhone))
	}
	if nowContract.Postcode != snapshotContract.Postcode {
		snapshotContractPostcode := snapshotContract.Postcode
		if snapshotContractPostcode == "" {
			snapshotContractPostcode = `无`
		}
		nowContractPostcode := nowContract.Postcode
		if nowContractPostcode == "" {
			nowContractPostcode = `无`
		}
		updateStrList = append(updateStrList, fmt.Sprint("原邮编：", snapshotContractPostcode, "</n>现邮编：", nowContractPostcode))
	}
	return
}

// contrastPayInfo 比对合同金额、付款方式是否变更
func contrastPayInfo(snapshotContract contract.ContractDetail, nowContract contract.Contract) (updateStrList []string) {
	//合同信息比对
	if nowContract.StartDate != snapshotContract.StartDate || nowContract.EndDate != snapshotContract.EndDate {
		updateStrList = append(updateStrList, fmt.Sprint("原合同期限：", snapshotContract.StartDate.Format(utils.FormatDate), " ~ ", snapshotContract.EndDate.Format(utils.FormatDate), "</n>现合同期限：", nowContract.StartDate.Format(utils.FormatDate), " ~ ", nowContract.EndDate.Format(utils.FormatDate)))
	}
	if nowContract.ContractBusinessType == "代付合同" {
		if nowContract.Price != snapshotContract.Price {
			updateStrList = append(updateStrList, fmt.Sprint("原代付金额：", decimal.NewFromFloat(snapshotContract.Price).String(), "</n>现代付金额：", decimal.NewFromFloat(nowContract.Price).String()))
		}
	} else {
		if nowContract.OriginalPrice != snapshotContract.OriginalPrice {
			updateStrList = append(updateStrList, fmt.Sprint("原合同金额：", decimal.NewFromFloat(snapshotContract.OriginalPrice).String(), "</n>现合同金额：", decimal.NewFromFloat(nowContract.OriginalPrice).String()))
		}
		if nowContract.Price != snapshotContract.Price {
			updateStrList = append(updateStrList, fmt.Sprint("原优惠后金额：", decimal.NewFromFloat(snapshotContract.Price).String(), "</n>现优惠后金额：", decimal.NewFromFloat(nowContract.Price).String()))
		}
	}
	if nowContract.PayRemark != snapshotContract.PayRemark {
		snapshotContractInfo := snapshotContract.PayRemark
		if snapshotContractInfo == "" {
			snapshotContractInfo = "无"
		}
		nowContractInfo := nowContract.PayRemark
		if nowContractInfo == "" {
			nowContractInfo = "无"
		}
		updateStrList = append(updateStrList, fmt.Sprint("原付款方式：", snapshotContractInfo, "</n>现付款方式：", nowContractInfo))
	}
	if nowContract.PayChannel != snapshotContract.PayChannel {
		snapshotContractInfo := snapshotContract.PayChannel
		if snapshotContractInfo == "" {
			snapshotContractInfo = "无"
		}
		nowContractInfo := nowContract.PayChannel
		if nowContractInfo == "" {
			nowContractInfo = "无"
		}
		updateStrList = append(updateStrList, fmt.Sprint("原付款方：", snapshotContractInfo, "</n>现付款方：", nowContractInfo))
	}
	return
}

// contrastServiceInfo 比对合同服务内容是否变更
func contrastServiceInfo(snapshotContract contract.ContractDetail, contractServiceSlice []*contract.ContractServiceAndDetail) (updateStr string, err error) {
	serviceList := snapshotContract.Service
	nowServiceList := contractServiceSlice
	// CRM8.8-权益的合同服务主客观合并
	if snapshotContract.ProductId == 2 {
		updateStr = handleRaiContractModifyContentByServices(serviceList, nowServiceList)
		return
	}
	snapshotPermissionList, err := GetPermissionByContractService(snapshotContract.ProductId, serviceList)
	if err != nil {
		return
	}
	allPermissionMap := make(map[int]string)
	snapshotPermissionIdList := make([]int, 0)
	for _, permissionItem := range snapshotPermissionList {
		for _, permission := range permissionItem.Items {
			allPermissionMap[permission.ChartPermissionId] = permission.PermissionName
			if snapshotContract.ProductId == 2 {
				allPermissionMap[permission.ChartPermissionId] = permission.Remark
			}
		}
		snapshotPermissionIdList = append(snapshotPermissionIdList, permissionItem.CheckList...)
	}
	if len(snapshotPermissionIdList) > 0 {
		sort.Ints(snapshotPermissionIdList)
	}

	nowPermissionList, err := GetPermissionByContractService(snapshotContract.ProductId, nowServiceList)
	if err != nil {
		return
	}
	nowPermissionIdList := make([]int, 0)
	for _, permissionItem := range nowPermissionList {
		nowPermissionIdList = append(nowPermissionIdList, permissionItem.CheckList...)
	}
	if len(nowPermissionIdList) > 0 {
		sort.Ints(nowPermissionIdList)
	}

	//长度不等
	if len(snapshotPermissionIdList) != len(nowPermissionIdList) {
		goto FalseContrast
	}
	for i := 0; i < len(snapshotPermissionIdList); i++ {
		if snapshotPermissionIdList[i] != nowPermissionIdList[i] {
			//权限id不匹配
			goto FalseContrast
		}
	}
	return
FalseContrast:
	snapshotContractServiceStrList := make([]string, 0)
	for _, id := range snapshotPermissionIdList {
		if permissionName, ok := allPermissionMap[id]; ok {
			snapshotContractServiceStrList = append(snapshotContractServiceStrList, permissionName)
		}
	}
	nowContractServiceStrList := make([]string, 0)
	for _, id := range nowPermissionIdList {
		if permissionName, ok := allPermissionMap[id]; ok {
			nowContractServiceStrList = append(nowContractServiceStrList, permissionName)
		}
	}
	snapshotContractServiceStr := `无`
	if len(snapshotContractServiceStrList) > 0 {
		snapshotContractServiceStr = strings.Join(snapshotContractServiceStrList, ",")
	}
	nowContractServiceStr := `无`
	if len(nowContractServiceStrList) > 0 {
		nowContractServiceStr = strings.Join(nowContractServiceStrList, ",")
	}
	updateStr = fmt.Sprint("原服务内容：", snapshotContractServiceStr, "</n>现服务内容：", nowContractServiceStr)
	return
}

// DeleteContract 删除合同
func DeleteContract(contractId int, opUser *system.Admin) (err error) {
	//查询当前合同信息
	nowContract, err := contract.GetContractById(contractId)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			err = errors.New(fmt.Sprint("根据合同编号:", contractId, " 找不到初始合同"))
		}
		return
	}
	if nowContract.SellerId != opUser.AdminId {
		err = errors.New("当前账号无操作权限")
		return
	}
	ignoreStatus := []string{"已审批", "待审批"}
	if strings.Contains(strings.Join(ignoreStatus, ","), nowContract.Status) {
		err = errors.New("合同状态异常，不允许删除，当前合同状态：" + nowContract.Status)
		return
	}
	//如果删除状态 >0，那么代表已经被删除了
	if nowContract.IsDelete > 0 {
		err = errors.New("该合同已删除")
		return
	}

	//假删除
	err = contract.DeleteContract(nowContract)
	if err != nil {
		return
	}
	//添加操作日志
	//remark := "编辑合同模板"
	//_ = contract.AddContractOperationRecord(nowContract.ContractId, nowContract.SellerId, 0, "edit", nowContract.SellerName, remark)
	return
}

// InvalidContract 作废合同
func InvalidContract(contractId int, opUser *system.Admin) (err error) {
	//查询当前合同信息
	nowContract, err := contract.GetContractById(contractId)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			err = errors.New(fmt.Sprint("根据合同编号:", contractId, " 找不到初始合同"))
		}
		return
	}
	if nowContract.SellerId != opUser.AdminId && opUser.RoleTypeCode != utils.ROLE_TYPE_CODE_COMPLIANCE {
		err = errors.New("当前账号无操作权限")
		return
	}
	if nowContract.Status != "已审批" {
		err = errors.New("合同状态异常，不允许作废，当前合同状态：" + nowContract.Status)
		return
	}

	//如果删除状态 >0，那么代表已经被删除了
	if nowContract.IsDelete > 0 {
		err = errors.New("该合同已删除")
		return
	}

	//合同作废
	err = contract.InvalidContract(nowContract)
	if err != nil {
		return
	}
	//添加操作日志
	remark := "作废合同模板"
	_ = contract.AddContractOperationRecord(nowContract.ContractId, opUser.AdminId, 0, "invalid", opUser.AdminName, remark)

	//修改业务合同的已支付金额
	if nowContract.ContractBusinessType == "代付合同" {
		go updateContractPaidPriceByPaymentOnBehalfContractId(nowContract.ContractId, -nowContract.Price)
	}
	return
}

// UploadFile 上传更新合同附件
func UploadFile(contractId int, ext string, fileMulti multipart.File, opUser *system.Admin) (err error) {
	//获取合同信息
	contractInfo, err := contract.GetContractById(contractId)
	if err != nil {
		return
	}

	//合同状态判断
	if contractInfo.Status != "已审批" {
		err = errors.New("合同状态异常，不允许更新合同附件，当前合同状态：" + contractInfo.Status)
		return
	}
	if contractInfo.SellerId != opUser.AdminId {
		err = errors.New("合同异常，只允许本人更新合同附件")
		return
	}

	//保存的文件名
	fileName := contractInfo.CompanyName + "_" + contractInfo.ContractCode
	//非正式环境下，文件名上面还是加上随机数
	if utils.RunMode != "release" {
		fileName += "_" + utils.GetRandStringNoSpecialChar(10)
	}
	fileName += ext
	//上传到阿里云
	resourceUrl, err := services.UploadToOssAndFileName(fileMulti, fileName)
	if err != nil {
		err = errors.New("文件保存失败,Err:" + err.Error())
		return
	}

	contractInfo.FileUrl = resourceUrl
	contractInfo.ModifyTime = time.Now()
	err = contractInfo.Update([]string{"FileUrl", "ModifyTime"})
	if err != nil {
		return
	}

	//添加操作日志
	remark := "更新合同附件"
	_ = contract.AddContractOperationRecord(contractInfo.ContractId, opUser.AdminId, 0, "update_file", opUser.RealName, remark)
	return
}

// UploadCheckBackFile 上传签回合同附件
func UploadCheckBackFile(contractId int, ext string, fileMulti multipart.File, opUser *system.Admin) (resourceUrl string, err error) {
	//获取合同信息
	contractInfo, err := contract.GetContractById(contractId)
	if err != nil {
		return
	}
	//合同状态判断
	if contractInfo.Status != "已审批" && contractInfo.Status != "已签回" {
		err = errors.New("合同状态异常，不允许上传签回合同附件，当前合同状态：" + contractInfo.Status)
		return
	}

	//保存的文件名
	fileName := contractInfo.CompanyName + "_" + contractInfo.ContractCode + "（签回）"
	//非正式环境下，文件名上面还是加上随机数
	if utils.RunMode != "release" {
		fileName += "_" + utils.GetRandStringNoSpecialChar(10)
	}
	fileName += ext
	//上传到阿里云
	resourceUrl, err = services.UploadToOssAndFileName(fileMulti, fileName)
	if err != nil {
		err = errors.New("文件保存失败,Err:" + err.Error())
		return
	}

	contractInfo.CheckBackFileUrl = resourceUrl
	contractInfo.Status = "已签回"
	contractInfo.ModifyTime = time.Now()
	contractInfo.CheckBackFileTime = time.Now()
	err = contractInfo.Update([]string{"CheckBackFileUrl", "Status", "ModifyTime", "CheckBackFileTime"})
	if err != nil {
		return
	}

	//同步更新客户那边提交审批的合同
	o := orm.NewOrm()
	sql := `update company_contract set img_url = ?  where contract_code=? and source="系统合同" `
	_, err = o.Raw(sql, contractInfo.CheckBackFileUrl, contractInfo.ContractCode).Exec()

	//添加操作日志
	remark := "上传签回合同附件"
	_ = contract.AddContractOperationRecord(contractInfo.ContractId, opUser.AdminId, 0, "upload", opUser.RealName, remark)
	return
}

// UploadRescindFile 上传解约合同附件
func UploadRescindFile(contractId int, ext string, fileMulti multipart.File, opUser *system.Admin) (err error) {
	//获取合同信息
	contractInfo, err := contract.GetContractById(contractId)
	if err != nil {
		return
	}
	//合同状态判断
	if contractInfo.Status != "已签回" {
		err = errors.New("合同状态异常，不允许上传解约合同附件，当前合同状态：" + contractInfo.Status)
		return
	}

	//保存的文件名
	fileName := contractInfo.CompanyName + "_" + contractInfo.ContractCode + "（解约）"
	//非正式环境下，文件名上面还是加上随机数
	if utils.RunMode != "release" {
		fileName += "_" + utils.GetRandStringNoSpecialChar(10)
	}
	fileName += ext
	//上传到阿里云
	resourceUrl, err := services.UploadToOssAndFileName(fileMulti, fileName)
	if err != nil {
		err = errors.New("文件保存失败,Err:" + err.Error())
		return
	}

	contractInfo.RescindFileUrl = resourceUrl
	contractInfo.Status = "已解约"
	contractInfo.ModifyTime = time.Now()
	contractInfo.RescindTime = time.Now()
	err = contractInfo.Update([]string{"RescindFileUrl", "Status", "ModifyTime", "RescindTime"})
	if err != nil {
		return
	}

	//添加操作日志
	remark := "上传解约合同附件"
	_ = contract.AddContractOperationRecord(contractInfo.ContractId, opUser.AdminId, 0, "rescind", opUser.RealName, remark)

	//修改业务合同的已支付金额
	if contractInfo.ContractBusinessType == "代付合同" {
		go updateContractPaidPriceByPaymentOnBehalfContractId(contractInfo.ContractId, -contractInfo.Price)
	}
	return
}

// 根据id获取合同详情（包含服务）
func GetContractDetail(contractId int) (contractDetail *contract.ContractDetail, err error) {
	contractDetail, err = getContractDetail(contractId)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			err = errors.New("找不到该合同")
		}
		return
	}
	relationContractDetailList := make([]*contract.ContractDetail, 0)

	switch contractDetail.ContractBusinessType {
	case "业务合同":
		tmpList, tmpErr := contract.GetContractRelationListByRelationContractId(contractDetail.ContractId)
		if tmpErr != nil {
			err = errors.New("查询业务关联合同异常：" + tmpErr.Error())
			return
		}

		//获取所有关联合同详情
		for _, relationContract := range tmpList {
			tmpContractDetail, tmpErr := getContractDetail(relationContract.PaymentOnBehalfContractId)
			if tmpErr != nil {
				err = errors.New("查询业务关联合同详情异常：" + tmpErr.Error())
				return
			}
			relationContractDetailList = append(relationContractDetailList, tmpContractDetail)
		}
	case "代付合同":
		tmpList, tmpErr := contract.GetContractRelationListByPaymentOnBehalfContractId(contractDetail.ContractId)
		if tmpErr != nil {
			err = errors.New("查询代付关联合同异常：" + tmpErr.Error())
			return
		}

		//获取所有关联合同详情
		for _, relationContract := range tmpList {
			tmpContractDetail, tmpErr := getContractDetail(relationContract.ContractId)
			if tmpErr != nil {
				err = errors.New("查询业务关联合同详情异常：" + tmpErr.Error())
				return
			}
			relationContractDetailList = append(relationContractDetailList, tmpContractDetail)
		}
	}
	contractDetail.RelationContractDetailList = relationContractDetailList
	return
}

// getContractDetail 根据id获取合同详情（包含服务）
func getContractDetail(contractId int) (contractDetail *contract.ContractDetail, err error) {
	//获取合同基础信息详情
	contractDetail, err = contract.GetContractDetailById(contractId)
	if err != nil {
		if err.Error() == utils.ErrNoRow() {
			err = errors.New("找不到该合同")
		}
		return
	}
	//获取合同服务内容详情
	serviceList, err := getContractServiceAndDetailList(contractId)
	if err != nil {
		err = errors.New(fmt.Sprint("查找合同服务异常", err))
		return
	}
	contractDetail.Service = serviceList
	return
}

// getContractServiceAndDetailList 根据合同Id获取服务详情列表
func getContractServiceAndDetailList(contractId int) (serviceList []*contract.ContractServiceAndDetail, err error) {
	serviceList, err = contract.GetContractServiceAndDetailList(contractId)
	if err != nil {
		err = errors.New(fmt.Sprint("查找合同服务异常", err))
		return
	}
	// 权益合同主客观合并
	//if mergeEquity && len(serviceList) > 0 && serviceList[0].ProductId == 2 {
	//	mergeList, e := EquityMergeSubjectAndObject(serviceList)
	//	if e != nil {
	//		err = errors.New(fmt.Sprint("合并权益合同服务异常", err))
	//		return
	//	}
	//	serviceList = mergeList
	//}
	newLen := len(serviceList)
	for i := 0; newLen > i; i++ {
		if serviceList[i].HasDetail == "是" {
			list, detailErr := contract.GetContractServiceDetailListByServiceId(serviceList[i].ContractServiceId)
			if detailErr != nil {
				err = errors.New(fmt.Sprint("查找合同服务详情异常", detailErr))
				return
			}
			serviceList[i].DetailList = list
		}
	}
	return
}

// GetContractDetailByAddContractReq 根据请求参数获取合同详情结构体数据
func GetContractDetailByAddContractReq(req request.AddContractReq, sellerId, productId int, sellerName string) (contractDetail *contract.ContractDetail, err error) {
	originalPrice := req.OriginalPrice
	price := req.Price
	if originalPrice < 0 {
		err = errors.New("合同金额不能小于0")
		return
	}
	//如果优惠后金额小于等于0，那么就是等于优惠前的金额
	if price <= 0 {
		price = originalPrice
	}

	companyName := req.CompanyName
	if companyName == "" {
		err = errors.New("客户名称必填")
		return
	}
	creditCode := req.CreditCode
	if companyName == "" {
		err = errors.New("社会统一信用代码必填")
		return
	}
	contractCode, err := contract.GetCompanyContractCode(productId, req.ContractBusinessType)
	if err != nil {
		err = errors.New(fmt.Sprint("合同编号生成异常,Err:", err))
		return
	}

	//校验合同模板类型
	contractTemplate, err := contract.GetContractTemplateByTemplateId(req.TemplateId)
	if err != nil {
		return
	}
	if contractTemplate.ProductId != productId {
		err = errors.New("模板类型与当前账户类型不符")
		return
	}

	contractDetail = &contract.ContractDetail{
		ContractId:           int(time.Now().Unix()),
		ContractCode:         contractCode,
		SellerId:             sellerId,
		SellerName:           sellerName,
		ProductId:            productId,
		ContractBusinessType: req.ContractBusinessType,
		ContractType:         req.ContractType,
		Status:               "待提交",
		OriginalPrice:        originalPrice,
		Price:                price,
		PayRemark:            req.PayRemark,  //付款方式说明,长度255位
		PayChannel:           req.PayChannel, //付款渠道,长度255位
		CompanyName:          companyName,
		CreditCode:           creditCode,
		ProvinceId:           req.ProvinceId,
		Province:             req.Province,
		CityId:               req.CityId,
		City:                 req.City,
		Address:              req.Address,
		Fax:                  req.Fax,
		Phone:                req.Phone,
		Postcode:             req.Postcode,
		Remark:               req.Remark,
		TemplateId:           req.TemplateId,
		SourceId:             req.SourceId, //来源合同id
		ModifyTime:           time.Now(),
		CreateTime:           time.Now(),
	}

	//合同日期
	if req.ContractBusinessType == "代付合同" {
		//关联合同
		relationContractDetailList := make([]*contract.ContractDetail, 0)
		tmpContractDetail, tmpErr := getContractDetail(req.RelationContractId)
		if tmpErr != nil {
			err = errors.New("查询业务关联合同详情异常：" + tmpErr.Error())
			return
		}
		relationContractDetailList = append(relationContractDetailList, tmpContractDetail)
		contractDetail.RelationContractDetailList = relationContractDetailList
	} else {
		tmpStartDate, tmpErr := time.Parse(utils.FormatDate, req.StartDate)
		if tmpErr != nil {
			err = errors.New(fmt.Sprint("合同开始日期转换失败：", tmpErr))
			return
		}
		contractDetail.StartDate = tmpStartDate
		tmpEndDate, tmpErr := time.Parse(utils.FormatDate, req.EndDate)
		if tmpErr != nil {
			err = errors.New(fmt.Sprint("合同结束日期转换失败：", tmpErr))
			return
		}
		contractDetail.EndDate = tmpEndDate
		contractServiceSlice, tmpErr := getContractServiceAndDetail(productId, req.Service, false)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		contractDetail.Service = contractServiceSlice
	}
	return
}

// 根据请求数据获取套餐服务详情信息
func getContractServiceAndDetail(productId int, reqService []request.AddContractServiceReq, base642Image bool) (contractServiceSlice []*contract.ContractServiceAndDetail, err error) {
	contractServiceSlice = make([]*contract.ContractServiceAndDetail, 0)
	if len(reqService) < 0 {
		err = errors.New("请至少选择一种套餐")
		return
	}
	for i := 0; i < len(reqService); i++ {
		item := reqService[i]
		detail := item.Detail

		contractServiceDetailSlice := make([]*contract.ContractServiceDetail, 0)
		if len(detail) > 0 {
			for j := 0; j < len(detail); j++ {
				detailItem := detail[j]
				cellMap := make(map[string]string)
				for k := 0; k < len(detailItem); k++ {
					key := fmt.Sprint("cell_", k+1)
					tmpVal, jsonErr := json.Marshal(detailItem[k])
					if jsonErr != nil {
						err = errors.New(fmt.Sprint("json转换失败：", jsonErr))
						return
					}
					cellMap[key] = string(tmpVal)
				}
				contractServiceDetail := &contract.ContractServiceDetail{
					Col1: func(cellMap map[string]string) string {
						tmpVal, ok := cellMap["cell_1"]
						if ok {
							return tmpVal
						} else {
							return ""
						}
					}(cellMap),
					Col2: func(cellMap map[string]string) string {
						tmpVal, ok := cellMap["cell_2"]
						if ok {
							return tmpVal
						} else {
							return ""
						}
					}(cellMap),
					Col3: func(cellMap map[string]string) string {
						tmpVal, ok := cellMap["cell_3"]
						if ok {
							return tmpVal
						} else {
							return ""
						}
					}(cellMap),
					Col4: func(cellMap map[string]string) string {
						tmpVal, ok := cellMap["cell_4"]
						if ok {
							return tmpVal
						} else {
							return ""
						}
					}(cellMap),
					Col5: func(cellMap map[string]string) string {
						tmpVal, ok := cellMap["cell_5"]
						if ok {
							return tmpVal
						} else {
							return ""
						}
					}(cellMap),
					Col6: func(cellMap map[string]string) string {
						tmpVal, ok := cellMap["cell_6"]
						if ok {
							return tmpVal
						} else {
							return ""
						}
					}(cellMap),
					Col7: func(cellMap map[string]string) string {
						tmpVal, ok := cellMap["cell_7"]
						if ok {
							return tmpVal
						} else {
							return ""
						}
					}(cellMap),
					ServiceTemplateId: item.ServiceTemplateId,
					CreateTime:        time.Now(),
				}
				contractServiceDetailSlice = append(contractServiceDetailSlice, contractServiceDetail)
			}
		}
		hasDetail := "否"
		if len(contractServiceDetailSlice) > 0 {
			hasDetail = "是"
		}
		//报价单图片地址
		valueStr := item.Value
		if base642Image {
			b, _ := regexp.MatchString(`^data:\s*image\/(\w+);base64,`, valueStr)
			if b {
				imageUrl, uploadErr := UploadImageBase64(valueStr)
				if uploadErr != nil {
					err = errors.New(fmt.Sprint("base64图片上传失败：", uploadErr))
					return
				}
				valueStr = imageUrl
			}
		}

		//寻找该系统模板
		systemContractServiceTem, tmpErr := contract.GetContractServiceTemplateById(item.ServiceTemplateId)
		if tmpErr != nil {
			err = errors.New("找不到该模板")
			return
		}
		tmpContractService := &contract.ContractServiceAndDetail{
			ServiceTemplateId: item.ServiceTemplateId,
			Title:             item.Title,
			Value:             valueStr,
			ProductId:         productId,
			//CreateTime:        time.Now(),
			HasDetail:         hasDetail,
			TableValue:        systemContractServiceTem.TableValue,
			DetailList:        contractServiceDetailSlice,
			ChartPermissionId: systemContractServiceTem.ChartPermissionId,
		}
		contractServiceSlice = append(contractServiceSlice, tmpContractService)
	}
	return
}

// 获取品种列数据（因为前端可以随意插入列数据，所以需要根据列名来搜索对应的品种列）
func GetProductCelData(detail contract.ContractServiceDetail, tableCel *request.AddContractServiceDetailReq) (err error) {
	t := reflect.TypeOf(detail)
	v := reflect.ValueOf(detail)
	for k := 0; k < t.NumField(); k++ {
		//获取结构体的参数名
		tmpName := t.Field(k).Name
		if strings.Contains(tmpName, "Col") {
			//获取结构体该参数名的值
			tmpValue := v.Field(k).String()
			//如果值不为空的话，那么做下json转换
			if tmpValue != "" {
				tmpErr := json.Unmarshal([]byte(tmpValue), tableCel)
				if tmpErr != nil {
					err = tmpErr
					continue
				}
				if tableCel.HeadName == "品种" {
					err = nil
					return
				}
			}
		}
	}

	return
}

// 将base64的图片上传至oss
func UploadImageBase64(base64Str string) (resourceUrl string, err error) {
	ext := ".png"
	uploadDir := "./static"
	randStr := utils.GetRandStringNoSpecialChar(28)
	fileName := randStr + ext
	fpath := uploadDir + "/" + fileName

	b, _ := regexp.MatchString(`^data:\s*image\/(\w+);base64,`, base64Str)
	if !b {
		err = errors.New("图片格式不正确")
		return
	}
	re, _ := regexp.Compile(`^data:\s*image\/(\w+);base64,`)
	base64Str = re.ReplaceAllString(base64Str, "")
	base64Str = strings.Replace(base64Str, " ", "", -1)

	base64Str = strings.Replace(base64Str, " ", "", -1)
	//imgByte, err := base64.StdEncoding.DecodeString(base64Str)
	//err=ioutil.WriteFile(fpath,imgByte,os.ModeAppend)
	//if err!=nil {
	//	br.Msg = "图片保存失败"
	//	br.ErrMsg = "图片保存失败,Err:"+err.Error()
	//	return
	//}
	err = utils.SaveBase64ToFile(base64Str, fpath)
	if err != nil {

		return
	}
	fmt.Println("end")

	defer os.Remove(fpath)

	savePath := utils.Upload_Audio_Dir + time.Now().Format("200601/20060102/")
	savePath += fileName
	//上传到阿里云
	err = services.UploadVideoAliyun(fileName, fpath, savePath)
	if err != nil {
		return
	}
	utils.FileLog.Info("%s:", time.Now().Format(utils.FormatDateTime))
	utils.FileLog.Info("end update oss ")
	resourceUrl = utils.Imghost + savePath

	item := new(models.Resource)
	item.ResourceUrl = resourceUrl
	item.ResourceType = 1
	item.CreateTime = time.Now()
	_, err = models.AddResource(item)
	if err != nil {
		return
	}
	return
}

// GetPermissionByContractService 通过合同服务，获取权限id列表
func GetPermissionByContractService(productId int, serviceList []*contract.ContractServiceAndDetail) (permissionList []*company.PermissionLookList, err error) {
	//获取已经勾选的的权限
	checkPermissionIdMap, err := GetServicePermissionMap(serviceList)
	if err != nil {
		return
	}

	permissionList, err = GetPermissionByPermissionIdMap(productId, checkPermissionIdMap)
	return
}

// GetPermissionByPermissionIdMap 通过权限id的map，获取权限列表
func GetPermissionByPermissionIdMap(productId int, checkPermissionIdMap map[int]int) (permissionList []*company.PermissionLookList, err error) {
	//子权限切片集合
	allPermissions, err := company.GetPermissionLookItemsByProductId(productId)
	if err != nil {
		err = fmt.Errorf("获取权限失败，Err:%s", err.Error())
		return
	}
	permissionMap := make(map[int][]*company.PermissionLookItem, 0)
	for _, v := range allPermissions {
		if v.ParentId > 0 {
			permissionMap[v.ParentId] = append(permissionMap[v.ParentId], v)
		}
	}
	//遍历获取
	for _, v := range allPermissions {
		if v.ParentId == 0 {
			checkList := make([]int, 0)
			plist := new(company.PermissionLookList)
			plist.Items = make([]*company.PermissionLookItem, 0)
			items, ok1 := permissionMap[v.ChartPermissionId]
			if ok1 {
				for _, n := range items {
					if _, ok := checkPermissionIdMap[n.ChartPermissionId]; ok {
						checkList = append(checkList, n.ChartPermissionId)
					} else if _, ok2 := checkPermissionIdMap[n.ChartPermissionId+utils.PERMISSION_ID_UPGRADE]; ok2 {
						checkList = append(checkList, n.ChartPermissionId)
						n.IsUpgrade = 1
					}
				}
				plist.Items = items
			}
			plist.ClassifyName = v.PermissionName
			plist.CheckList = checkList

			permissionList = append(permissionList, plist)
		}

	}
	return
}

// GetServicePermissionMap 获取合同服务中的权限id  map
func GetServicePermissionMap(serviceList []*contract.ContractServiceAndDetail) (checkPermissionIdMap map[int]int, err error) {
	checkPermissionIdMap = make(map[int]int)
	//获取已经勾选的的权限
	for _, contractService := range serviceList {
		//如果是权益，那么研选必要（2022-07-06 10:29:11移除）
		//if contractService.ProductId == 2 {
		//	chartPermissionId := 31 //研选服务
		//	checkPermissionIdMap[chartPermissionId] = chartPermissionId
		//}

		//看看系统中有没有映射对应的权限，如果有的话，那么直接返回，没有那么可能是特殊服务，需要去遍历
		if contractService.ChartPermissionId > 0 {
			checkPermissionIdMap[contractService.ChartPermissionId] = contractService.ChartPermissionId
			continue
		}
		switch contractService.ServiceTemplateId {
		case 1: //ficc 大套餐
			allFiccPermissions, e := company.GetPermissionLookItemsByProductId(utils.COMPANY_PRODUCT_FICC_ID)
			if e != nil {
				err = fmt.Errorf("获取权限失败 Err：%v", e)
				return
			}
			permissionMap := make(map[int][]*company.PermissionLookItem, 0)
			for _, v := range allFiccPermissions {
				if v.ParentId > 0 {
					permissionMap[v.ParentId] = append(permissionMap[v.ParentId], v)
				}
			}
			for _, v := range allFiccPermissions {
				if v.ParentId == 0 {
					//合同这边市场策略不需要体现出来，所以调整返回
					if v.PermissionName == "市场策略" {
						continue
					}
					items, ok := permissionMap[v.ChartPermissionId]
					if ok {
						for _, n := range items {
							checkPermissionIdMap[n.ChartPermissionId] = n.ChartPermissionId
						}
					}
				}
			}
		case 2: //ficc小套餐
			permissionValues := []string{
				"FICC周报", "商品双周报+线上电话会讨论会<br/>（由弘则的研究员主持线上讨论）", "数据点评",
			}
			for _, detail := range contractService.DetailList {
				var tableCel request.AddContractServiceDetailReq
				tmpErr := json.Unmarshal([]byte(detail.Col1), &tableCel)
				if tmpErr != nil {
					err = tmpErr
					return
				}
				if strings.Contains(strings.Join(permissionValues, ","), tableCel.Value) {
					//获取品种列数据
					var tableCel2 request.AddContractServiceDetailReq
					tmpErr := GetProductCelData(*detail, &tableCel2)
					if tmpErr != nil {
						err = tmpErr
						return
					}
					for _, serviceId := range tableCel2.ValueId {
						checkPermissionIdMap[serviceId] = serviceId
					}
				}
			}
		case 4, 5, 6: //权益大套餐
			permissionFiccClassifyArr := []string{"权益"}
			for _, v := range permissionFiccClassifyArr {
				items, tmpErr := company.GetPermissionLookItems(2, v)
				if tmpErr != nil {
					err = tmpErr
					return
				}
				for _, n := range items {
					//如果是专家行业，那么 结束当前循环，进入下一循环（产品需求：专家行业不在里面）
					if n.ChartPermissionId == 29 || n.ChartPermissionId == 31 {
						continue
					}
					checkPermissionIdMap[n.ChartPermissionId] = n.ChartPermissionId
				}
			}
		}

	}
	return
}

// GetServicePackageType 获取合同服务中的 大小套餐类型
func GetServicePackageType(serviceList []*contract.ContractServiceAndDetail) (packageType int, err error) {
	//获取已经勾选的的权限
	for _, contractService := range serviceList {
		switch contractService.ServiceTemplateId {
		case 1: //ficc 大套餐
			packageType = 1
		case 2: //ficc小套餐
			packageType = 2
		case 4, 5, 6: //权益大套餐
			//packageType = 1
		}
	}
	return
}

// GetRaiServicePackageType 获取合同服务中的 权益的大小套餐类型
func GetRaiServicePackageType(serviceList []*contract.ContractServiceAndDetail) (raiPackageType int) {
	for _, contractService := range serviceList {
		switch contractService.ServiceTemplateId {
		case 5: // 45w大套餐
			raiPackageType = 2
		case 6: // 70w大套餐
			raiPackageType = 1
		}
		if raiPackageType > 0 {
			break
		}
	}
	return
}

// CheckContractPrice 校验代付合同金额是否 大于 业务合同金额（可能存在多份合同，需要遍历，如果大于的话，校验不通过，需要驳回）
func CheckContractPrice(contractInfo *contract.Contract, price float64) (ok bool, err error) {
	list, err := contract.GetContractRelationListByContractId(contractInfo.ContractId)
	if err != nil {
		return
	}
	payedPrice := 0.0
	for _, v := range list {
		payedPrice += v.Price
	}
	if (contractInfo.Price - payedPrice) < price {
		return
	}
	ok = true
	return
}

// UploadCheckBackFileFromSeal 更新用印上传签回合同附件
func UploadCheckBackFileFromSeal(contractId int, fileUrl string, opUser *system.Admin) (err error) {
	// 获取合同信息
	contractInfo, err := contract.GetContractById(contractId)
	if err != nil {
		return
	}

	// 合同状态判断
	if contractInfo.Status != "已审批" && contractInfo.Status != "已签回" {
		err = errors.New("合同状态异常，不允许上传签回合同附件，当前合同状态：" + contractInfo.Status)
		return
	}
	contractInfo.CheckBackFileUrl = fileUrl
	contractInfo.Status = "已签回"
	contractInfo.ModifyTime = time.Now()
	contractInfo.CheckBackFileTime = time.Now()
	err = contractInfo.Update([]string{"CheckBackFileUrl", "Status", "ModifyTime", "CheckBackFileTime"})
	if err != nil {
		return
	}

	// 同步更新客户那边提交审批的合同
	o := orm.NewOrm()
	sql := `update company_contract set img_url = ? where contract_code=? and source = "系统合同" `
	_, err = o.Raw(sql, contractInfo.CheckBackFileUrl, contractInfo.ContractCode).Exec()

	// 添加操作日志
	remark := "上传签回合同附件"
	_ = contract.AddContractOperationRecord(contractInfo.ContractId, opUser.AdminId, 0, "upload", opUser.RealName, remark)

	return
}

//func init()  {
//	fmt.Println("contract init start")
//	go FixEquityContractService()
//	fmt.Println("contract init end")
//}

// FixEquityContractService 修复权益合同服务内容-CRM8.8
func FixEquityContractService() (err error) {
	defer func() {
		if err != nil {
			fmt.Println("FixEquityContractService Err: " + err.Error())
		}
	}()
	// 获取所有权益的合同(不考虑状态)
	productId := 2
	contractList, e := contract.GetContractListByProductId(productId)
	if e != nil {
		err = errors.New("获取权益合同列表失败")
		return
	}
	contractLen := len(contractList)
	if contractLen == 0 {
		fmt.Println("无合同需要修复")
		return
	}
	fmt.Println("待修复权益合同数", contractLen)
	//return
	// 合同IDs
	contractIdArr := make([]string, 0)
	contractIdServices := make(map[int][]*contract.ContractService, 0)
	for i := 0; i < contractLen; i++ {
		contractIdArr = append(contractIdArr, strconv.Itoa(contractList[i].ContractId))
		newServices := make([]*contract.ContractService, 0)
		contractIdServices[contractList[i].ContractId] = newServices
	}
	contractIds := strings.Join(contractIdArr, ",")
	// 合同服务内容
	serviceList, e := contract.GetContractServiceListByIds(contractIds)
	if e != nil {
		err = errors.New("获取权益合同服务内容列表失败")
		return
	}
	servicesLen := len(serviceList)
	if servicesLen == 0 {
		fmt.Println("无合同服务需要修复")
		return
	}
	for i := 0; i < servicesLen; i++ {
		contractIdServices[serviceList[i].ContractId] = append(contractIdServices[serviceList[i].ContractId], serviceList[i])
	}
	// 服务套餐模板
	templateList, e := contract.GetAllContractServiceTemplateList()
	if e != nil {
		err = errors.New("获取服务套餐模板列表失败")
		return
	}
	// 主客观服务套餐
	titleArr := []string{"医药", "消费", "科技", "智造"}
	subTempMap := make(map[string]*contract.ContractServiceTemplate, 0)
	objTempMap := make(map[string]*contract.ContractServiceTemplate, 0)
	templateIdMap := make(map[int]*contract.ContractServiceTemplate, 0)
	templateLen := len(templateList)
	for i := 0; i < templateLen; i++ {
		templateIdMap[templateList[i].ServiceTemplateId] = templateList[i]
	}
	for i := 0; i < templateLen; i++ {
		if templateList[i].Title == "主观" {
			parentTemp := templateIdMap[templateList[i].Pid]
			subTempMap[parentTemp.Title] = templateList[i]
			continue
		}
		if templateList[i].Title == "客观" {
			parentTemp := templateIdMap[templateList[i].Pid]
			objTempMap[parentTemp.Title] = templateList[i]
			continue
		}
	}
	// 遍历合同
	for i := 0; i < contractLen; i++ {
		contractId := contractList[i].ContractId
		fmt.Printf("正在修复第%d个, 合同ID: %d\n", i+1, contractId)
		// 合同服务内容
		contractServices := contractIdServices[contractId]
		insertArr := make([]*contract.ContractService, 0)
		serviceLen := len(contractServices)
		// 是否含有医药、消费、科技、智造
		for _, v := range titleArr {
			for ii := 0; ii < serviceLen; ii++ {
				createTime := contractServices[ii].CreateTime
				// 含有四种套餐之一
				if contractServices[ii].Title == v {
					template := templateIdMap[contractServices[ii].ServiceTemplateId]
					pid := template.ServiceTemplateId
					insertSubject := true
					insertObject := true
					// 去重, 校验是否已存在主客观
					for iii := 0; iii < serviceLen; iii++ {
						t := templateIdMap[contractServices[iii].ServiceTemplateId]
						if t.Pid == pid && t.Title == "主观" {
							insertSubject = false
							continue
						}
						if t.Pid == pid && t.Title == "客观" {
							insertObject = false
							continue
						}
					}
					if insertSubject {
						subTemp := subTempMap[v]
						title := v + "（" + subTemp.Title + "）"
						insertArr = append(insertArr, &contract.ContractService{
							ContractId:        contractId,
							ProductId:         productId,
							ServiceTemplateId: subTemp.ServiceTemplateId,
							Title:             title,
							Value:             subTemp.Value,
							TableValue:        subTemp.TableValue,
							HasDetail:         "否",
							ChartPermissionId: subTemp.ChartPermissionId,
							CreateTime:        createTime,
						})
					}
					if insertObject {
						objTemp := objTempMap[v]
						title := v + "（" + objTemp.Title + "）"
						insertArr = append(insertArr, &contract.ContractService{
							ContractId:        contractId,
							ProductId:         productId,
							ServiceTemplateId: objTemp.ServiceTemplateId,
							Title:             title,
							Value:             objTemp.Value,
							TableValue:        objTemp.TableValue,
							HasDetail:         "否",
							ChartPermissionId: objTemp.ChartPermissionId,
							CreateTime:        createTime,
						})
					}
					break
				}
			}
		}
		// 新增主客观
		if len(insertArr) > 0 {
			if e := contract.MultiCreateContractService(insertArr); e != nil {
				fmt.Printf("第%d个修复失败, 合同ID: %d, Err: %s\n", i+1, contractId, e.Error())
				return
			}
			fmt.Printf("第%d个修复成功, 合同ID: %d\n", i+1, contractId)
		} else {
			fmt.Printf("第%d个已修复过, 忽略合同ID: %d\n", i+1, contractId)
		}
	}
	return
}

// CRM8.8-权益合同主客观套餐合并
func EquityMergeSubjectAndObject(serviceList []*contract.ContractServiceAndDetail) (mergeList []*contract.ContractServiceAndDetail) {
	serviceLen := len(serviceList)
	if serviceLen == 0 {
		return serviceList
	}
	mergeArr := []string{"医药", "消费", "科技", "智造"}
	// 获取模板列表
	templateList, e := contract.GetAllContractServiceTemplateList()
	if e != nil {
		return serviceList
	}
	parentTempMap := make(map[string]int, 0)
	templateMap := make(map[int]*contract.ContractServiceTemplate, 0)
	for _, v := range templateList {
		if utils.InArrayByStr(mergeArr, v.Title) {
			parentTempMap[v.Title] = v.ServiceTemplateId
		}
		templateMap[v.ServiceTemplateId] = v
	}
	// 计算每个行业的子套餐数, 并判断所有套餐所属行业
	countIndustryMap := make(map[string]int, 0)
	serviceIndustryMap := make(map[int]string, 0)
	industryServiceMap := make(map[string]*contract.ContractServiceAndDetail, 0)
	childrenServiceMap := make(map[string]*contract.ContractServiceAndDetail, 0)
	for i := 0; i < serviceLen; i++ {
		temp := templateMap[serviceList[i].ServiceTemplateId]
		if temp == nil {
			continue
		}
		// 行业套餐
		if utils.InArrayByStr(mergeArr, temp.Title) {
			serviceIndustryMap[i] = temp.Title
			industryServiceMap[temp.Title] = serviceList[i]
			continue
		}
		// 主/客观
		parentTemp := templateMap[temp.Pid]
		if parentTemp != nil && utils.InArrayByStr(mergeArr, parentTemp.Title) {
			countIndustryMap[parentTemp.Title] += 1
			serviceIndustryMap[i] = parentTemp.Title
			childrenServiceMap[parentTemp.Title] = serviceList[i]
		}
	}
	mergeList = make([]*contract.ContractServiceAndDetail, 0)
	// 遍历每一个套餐, 取出所属的行业, 不属于合并的行业则直接加入数组
	// 属于合并的行业, 则校验行业子套餐数, 若子套餐数为1, 则取取主/客观套餐, 否则取行业套餐
	mergeIndustryMap := make(map[string]int, 0)
	for i := 0; i < serviceLen; i++ {
		industryName := serviceIndustryMap[i]
		// 不需要合并的行业
		if industryName == "" {
			mergeList = append(mergeList, serviceList[i])
			continue
		}
		// 未合并则进行合并
		if mergeIndustryMap[industryName] > 0 {
			continue
		}
		count := countIndustryMap[industryName]
		if count == 1 {
			// 取主/客观套餐
			mergeList = append(mergeList, childrenServiceMap[industryName])
		} else {
			// 0或者2都取行业套餐
			mergeList = append(mergeList, industryServiceMap[industryName])
		}
		mergeIndustryMap[industryName] += 1
	}
	return
}

// CRM8.8-权益合同主客观权限的合并
func EquityMergeSubjectAndObjectPermission(list []*company.CompanyContractPermissionName) (newList []*company.CompanyContractPermissionName) {
	if len(list) == 0 {
		return list
	}
	// contractPermissionMap示例:
	// map[
	//	665:map[
	//		专家:[0xc0002e24d0]
	//		买方研选:[0xc0002e2630]
	//		医药:[0xc0002e2370 0xc0002e28f0]
	//		智造:[0xc0002e2160 0xc0002e26e0]
	//		消费:[0xc0002e22c0 0xc0002e2840]
	//		科技:[0xc0002e2210 0xc0002e2790]
	//		策略:[0xc0002e2420]
	//		路演服务:[0xc0002e2580]
	//	]
	//	666:map[
	//		智造:[0xc0002e29a0 0xc0002e2b00]
	//		科技:[0xc0002e2a50 0xc0002e2bb0]
	//	]
	// ]
	contractPermissionMap := make(map[int]map[string][]*company.CompanyContractPermissionName)
	for _, v := range list {
		permissionMap, ok := contractPermissionMap[v.CompanyContractId]
		if ok {
			permissionItemMap, ok2 := permissionMap[v.ChartPermissionName]
			if !ok2 {
				permissionItemMap = make([]*company.CompanyContractPermissionName, 0)
			}
			permissionItemMap = append(permissionItemMap, v)
			permissionMap[v.ChartPermissionName] = permissionItemMap
		} else {
			permissionMap = make(map[string][]*company.CompanyContractPermissionName)
			permissionMap[v.ChartPermissionName] = append(permissionMap[v.ChartPermissionName], v)
		}
		contractPermissionMap[v.CompanyContractId] = permissionMap
	}
	newList = make([]*company.CompanyContractPermissionName, 0)
	for _, v := range contractPermissionMap {
		for _, p := range v {
			if len(p) == 1 {
				p[0].ChartPermissionName = p[0].PermissionRemark
			}
			newList = append(newList, p[0])
		}
	}
	return
}

// HandleEquityPermissionLookList 权益-PermissionLookList主客观合并
func HandleEquityPermissionLookList(permissionLookList []*company.PermissionLookList) []*company.PermissionLookList {
	if len(permissionLookList) == 0 {
		return permissionLookList
	}
	checkList := permissionLookList[0].CheckList
	permissionList := permissionLookList[0].Items
	newPermissionList := HandleEquityPermissionLookItem(checkList, permissionList)
	permissionLookList[0].Items = newPermissionList
	return permissionLookList
}

// HandleEquityContractPermissionList 权益-ContractPermissionList主客观合并
func HandleEquityContractPermissionList(contractPermissionList []*company.ContractPermissionList) []*company.ContractPermissionList {
	if len(contractPermissionList) == 0 {
		return contractPermissionList
	}
	checkList := contractPermissionList[0].CheckList
	permissionList := contractPermissionList[0].Items
	newPermissionList := HandleEquityPermissionLookItem(checkList, permissionList)
	contractPermissionList[0].Items = newPermissionList
	return contractPermissionList
}

// HandleEquityPermissionLookItem 权益-权限展示的主客观合并处理
func HandleEquityPermissionLookItem(checkList []int, permissionList []*company.PermissionLookItem) (newPermissionList []*company.PermissionLookItem) {
	permissionLen := len(permissionList)
	if len(checkList) <= 0 || permissionLen <= 0 {
		return permissionList
	}
	// 若某个行业的主客观权限均被满足，则只留其中一个权限
	// 1.取出每个行业对应的其中一个权限
	industryName := []string{"医药", "消费", "科技", "智造"}
	namePermissionMap := make(map[string]*company.PermissionLookItem)
	for i := 0; i < permissionLen; i++ {
		pName := permissionList[i].PermissionName
		if utils.InArrayByStr(industryName, pName) && namePermissionMap[pName] != nil {
			namePermissionMap[pName] = permissionList[i]
		}
	}
	// 2.计算哪些行业主客观权限都有
	countIndustryMap := make(map[string]int, 0)
	for i := 0; i < permissionLen; i++ {
		p := permissionList[i]
		if utils.InArrayByStr(industryName, p.PermissionName) && utils.InArrayByInt(checkList, p.ChartPermissionId) {
			countIndustryMap[p.PermissionName] += 1
		}
	}
	// 3.重新组成一个权限列表
	mergeIndustryMap := make(map[string]int, 0)
	newPermissionList = make([]*company.PermissionLookItem, 0)
	for i := 0; i < permissionLen; i++ {
		item := permissionList[i]
		if utils.InArrayByStr(industryName, item.PermissionName) {
			// 只有主客观之一, permissionName取remark
			if countIndustryMap[item.PermissionName] == 1 {
				// CRM13.2 标准合同新增升级套餐
				if item.IsUpgrade == 1 {
					item.PermissionName += "（升级）"
					newPermissionList = append(newPermissionList, item)
				} else {
					item.PermissionName = item.Remark
					newPermissionList = append(newPermissionList, item)
				}
				continue
			}
			// 主客观都有
			if countIndustryMap[item.PermissionName] > 1 && mergeIndustryMap[item.PermissionName] == 0 {
				mergeIndustryMap[item.PermissionName] += 1
				// CRM13.2 标准合同新增升级套餐
				if item.IsUpgrade == 1 {
					item.PermissionName += "（升级）"
				}
				newPermissionList = append(newPermissionList, item)
			}
		} else {
			newPermissionList = append(newPermissionList, item)
		}
	}
	return
}

// handleRaiContractModifyContentByServices 权益合同-服务内容变更内容
func handleRaiContractModifyContentByServices(originService []*contract.ContractServiceAndDetail, newService []*contract.ContractServiceAndDetail) (tips string) {
	if originService == nil || newService == nil {
		return
	}
	oldArr := make([]string, 0)
	newArr := make([]string, 0)
	oldStr := "无"
	newStr := "无"
	o := EquityMergeSubjectAndObject(originService)
	n := EquityMergeSubjectAndObject(newService)
	for i := range o {
		oldArr = append(oldArr, o[i].Title)
	}
	if len(oldArr) > 0 {
		oldStr = strings.Join(oldArr, ",")
	}
	for i := range n {
		newArr = append(newArr, n[i].Title)
	}
	if len(newArr) > 0 {
		newStr = strings.Join(newArr, ",")
	}
	tips = fmt.Sprint("原服务内容：", oldStr, "</n>现服务内容：", newStr)
	return
}

// 获取权益近一年是否有新签合同
func GetCompanyContractCountRaiByLastYear(companyId int, startDate string) (total int, err error) {
	firstContractRai, err := company.GetFirstContractRai(companyId)
	if err != nil && err.Error() != utils.ErrNoRow() {
		return
	}
	//没有合同这第一份合同就属于新签合同
	if firstContractRai == nil {
		err = nil
		total = 1
		return
	}
	//判断是否是在一年以内
	startDateTime, _ := time.Parse(utils.FormatDate, startDate)
	startDateTime = startDateTime.AddDate(-1, 0, 0)
	startDateTimeFirst, _ := time.Parse(utils.FormatDate, firstContractRai.StartDate)
	if startDateTime.Before(startDateTimeFirst) {
		total = 1
	}
	return
}

func initCRM15_5() {
	var condition string
	var pars []interface{}

	condition = " AND  rai_contract_type  = '新签合同'  AND  product_id = 2 "
	companyContractList, e := company.GetCompanyContractList(condition, pars)
	if e != nil && e.Error() != utils.ErrNoRow() {
		fmt.Println(e)
		return
	}
	var CompanyContractIdS []int
	for k, v := range companyContractList {
		fmt.Println(k)
		firstContractRai, err := company.GetFirstContractRai(v.CompanyId)
		if err != nil {
			fmt.Println(err)
			continue
		}

		if firstContractRai.CompanyContractId == v.CompanyContractId {
			continue
		}
		//判断是否是在一年以内
		startDateTime, _ := time.Parse(utils.FormatDate, v.StartDate)
		startDateTime = startDateTime.AddDate(-1, 0, 0)
		startDateTimeFirst, _ := time.Parse(utils.FormatDate, firstContractRai.StartDate)
		if !startDateTime.Before(startDateTimeFirst) {
			CompanyContractIdS = append(CompanyContractIdS, v.CompanyContractId)
		}
	}
	fmt.Println("companyContractIds", len(CompanyContractIdS))
	fmt.Println("companyContractIds", (CompanyContractIdS))
	//
	//fmt.Println(strings.Join(companyContractIds, ","))
	//err := company.UpdateCompanyContractRaiContractTypeInit(strings.Join(companyContractIds, ","))
	//fmt.Println(err)
	return
}
