package service

import (
	"encoding/hex"
	"fmt"
	"mtp20_assisted/global"
	"mtp20_assisted/model"
	"mtp20_assisted/res/pb"
	"mtp20_assisted/utils"
	"os"
	"strconv"
	"strings"
	"time"

	"github.com/gofrs/uuid"
	"github.com/nguyenthenguyen/docx"
	"go.uber.org/zap"
	"google.golang.org/protobuf/proto"
)

// THJNtf 铁合通知处理模型
type THJNtf struct{}

func (t *THJNtf) Process(msg *[]byte) {
	// 分解总线包信息
	funcode := utils.BytesToUint32((*msg)[0:4])
	sessionId := utils.BytesToUint32((*msg)[4:8])
	bytes := (*msg)[8:]
	global.M2A_LOG.Info("[S->C]", zap.Any("funcode", funcode), zap.Any("sessionId", sessionId), zap.Any("count", len(bytes)))

	switch funcode {
	case uint32(global.THJPurchaseTradeNtf):
		// 等待两秒
		<-time.After(2 * time.Second)
		onTHJPurchaseTradeNtf(&bytes)
	case uint32(global.PurchaseTransferNtf):
		<-time.After(2 * time.Second)
		onTHJPurchaseTransferNtf(&bytes)
	case uint32(global.WRTradeDealedNtf):
		<-time.After(2 * time.Second)
		onWRTradeDealedNtf(&bytes)
	}
}

// onTHJPurchaseTradeNtf 铁合金成交通知
func onTHJPurchaseTradeNtf(bytes *[]byte) {
	// Read from docx file
	r, err := docx.ReadDocxFile("./static/产能预售合同.docx")
	if err != nil {
		global.M2A_LOG.Error("[铁合金成交通知] 读取合同文件失败", zap.Error(err))
		return
	}

	// 获取网上开户地址（用于客户端下载文件）
	openconfig := model.Wskhopenaccountconfig{CONFIGID: 6}
	if has, err := openconfig.Get(); err != nil || !has {
		global.M2A_LOG.Error("[铁合金成交通知] 获取网上开户地址失败", zap.Error(err))
		return
	}

	var p pb.THJPurchaseTradeNtf
	if err := proto.Unmarshal(*bytes, &p); err != nil {
		global.M2A_LOG.Error("[铁合金成交通知] 总线回复数据反序列化失败", zap.Error(err))
		return
	}

	// 铁合金采购成交扩展信息
	thjpurchasetradedetail := model.Thjpurchasetradedetail{WRTRADEDETAILID: int64(p.GetWRTradeDetailID())}
	if has, err := thjpurchasetradedetail.Get(); err != nil || !has {
		global.M2A_LOG.Error("[铁合金成交通知] 获取铁合金采购成交扩展信息失败", zap.Error(err))
		return
	}
	// 交割方式
	thjdeliverymode := "否"
	if thjpurchasetradedetail.THJDELIVERYMODE == 1 {
		thjdeliverymode = "是"
	}

	// 现货商品信息
	wrstandard := model.Wrstandard{WRSTANDARDID: int64(thjpurchasetradedetail.WRSTANDARDID)}
	if has, err := wrstandard.Get(); err != nil || !has {
		global.M2A_LOG.Error("[铁合金成交通知] 获取现货商品信息失败", zap.Error(err))
		return
	}

	// 仓单预售信息
	wrpresaleinfo := model.Wrpresaleinfo{PRESALEAPPLYID: thjpurchasetradedetail.PRESALEAPPLYID}
	if has, err := wrpresaleinfo.Get(); err != nil || !has {
		global.M2A_LOG.Error("[铁合金成交通知] 获取仓单预售信息失败", zap.Error(err))
		return
	}

	// 甲方信息
	userinfo := model.Userinfo{USERID: thjpurchasetradedetail.BUYUSERID}
	if has, err := userinfo.Get(); err != nil || !has {
		global.M2A_LOG.Error("[铁合金成交通知] 获取甲方信息失败", zap.Error(err))
		return
	}
	division := model.Division{AUTOID: int64(userinfo.DISTRICTID)}
	totalAddress, err := division.GetTotalAddressByDistrictID(userinfo.ADDRESS)
	if err != nil {
		global.M2A_LOG.Error("[铁合金成交通知] 获取甲方地址信息失败", zap.Error(err))
		return
	}
	// 证件号码解密
	key, _ := hex.DecodeString(utils.AESSecretKey)
	if len(userinfo.CARDNUM) > 0 {
		if cardnum, err := hex.DecodeString(userinfo.CARDNUM); err == nil { // hex -> []byte
			if c, err := utils.AESDecrypt(cardnum, key); err == nil {
				userinfo.CARDNUM = string(c)
			}
		}
	}
	// 手机号码解密
	if len(userinfo.MOBILE) > 0 {
		if phonenum, err := hex.DecodeString(userinfo.MOBILE); err == nil { // hex -> []byte
			if mobile, err := utils.AESDecrypt(phonenum, key); err == nil {
				userinfo.MOBILE = string(mobile)
			}
		}
	}

	// 甲方签约信息
	bankaccountsign := model.Bankaccountsign{}
	if has, err := bankaccountsign.GetByUserID(uint64(thjpurchasetradedetail.BUYUSERID)); err != nil || !has {
		global.M2A_LOG.Error("[铁合金成交通知] 获取甲方签约信息失败", zap.Error(err))
		return
	}
	// 账号解密
	if len(bankaccountsign.BANKACCOUNTNO) > 0 {
		if tt, err := hex.DecodeString(bankaccountsign.BANKACCOUNTNO); err == nil { // hex -> []byte
			if dd, err := utils.AESDecrypt(tt, key); err == nil {
				bankaccountsign.BANKACCOUNTNO = string(dd)
			}
		}
	}

	// 银行信息
	bankinfo := model.Bankbankinfo{BANKID: bankaccountsign.BANKID}
	if has, err := bankinfo.Get(); err != nil || !has {
		global.M2A_LOG.Error("[铁合金成交通知] 获取银行信息失败", zap.Error(err))
		return
	}

	// 生产厂家信息
	selluserinfo := model.Userinfo{USERID: thjpurchasetradedetail.SELLUSERID}
	if has, err := selluserinfo.Get(); err != nil || !has {
		global.M2A_LOG.Error("[铁合金成交通知] 获取生产厂家信息失败", zap.Error(err))
		return
	}

	docx1 := r.Editable()
	// global.M2A_LOG.Info(docx1.GetContent())
	docx1.Replace("${WRTRADEDETAILID}", strconv.Itoa(int(thjpurchasetradedetail.WRTRADEDETAILID)), -1)
	docx1.Replace("${TRADETIME}", thjpurchasetradedetail.TRADETIME.Format("2006年01月02日"), -1)
	docx1.Replace("${DESADDRESS}", totalAddress, -1)
	// 判断是公司还是个人
	if userinfo.USERINFOTYPE == 1 {
		// 个人
		docx1.Replace("COMPANY", "", -1)
		docx1.Replace("${LEGALPERSONNAME}", userinfo.CUSTOMERNAME, -1)
	} else {
		// 公司
		docx1.Replace("COMPANY", userinfo.CUSTOMERNAME, -1)
		docx1.Replace("${LEGALPERSONNAME}", userinfo.LEGALPERSONNAME, -1)
	}
	docx1.Replace("CARDNUM", userinfo.CARDNUM, -1)
	docx1.Replace("${MOBILE}", userinfo.MOBILE, -1)
	docx1.Replace("${BANK}", bankinfo.BANKNAME, -1)
	docx1.Replace("${BANKACCOUNTNO}", bankaccountsign.BANKACCOUNTNO, -1)
	docx1.Replace("${WRSTANDARDNAME}", wrstandard.WRSTANDARDNAME, -1)
	docx1.Replace("${SELLUSER}", selluserinfo.CUSTOMERNAME, -1)
	docx1.Replace("${LASTAMOUNT}", strconv.FormatFloat(thjpurchasetradedetail.LASTAMOUNT, 'f', -1, 64), -1)
	docx1.Replace("${DEPOSITRATE}", strconv.FormatFloat(thjpurchasetradedetail.DEPOSITRATE*100, 'f', -1, 64)+"%", -1)
	docx1.Replace("TRADEQTY", strconv.Itoa(int(thjpurchasetradedetail.TRADEQTY)), -1)
	docx1.Replace("${TRADEPRICE}", strconv.FormatFloat(thjpurchasetradedetail.TRADEPRICE, 'f', -1, 64), -1)
	docx1.Replace("${ENDDATEMONTH}", strconv.Itoa(int(wrpresaleinfo.ENDDATE.Local().Month())), -1)
	docx1.Replace("${THJDELIVERYMODE}", thjdeliverymode, -1)
	docx1.Replace("${ENDDATE}", wrpresaleinfo.ENDDATE.Format("200601"), -1)
	docx1.Replace("${STORAGEFEE}", strconv.FormatFloat(wrstandard.STORAGEFEE, 'f', -1, 64), -1)

	// 暂存docx文件
	if exist, _ := utils.PathExists("./.tmp"); !exist {
		os.Mkdir("./.tmp", os.ModePerm)
	}
	uid, _ := uuid.NewV4()
	docxFilename := fmt.Sprintf("%v_%v.docx", strconv.Itoa(int(thjpurchasetradedetail.WRTRADEDETAILID)), uid.String())
	pdfFilename := strings.Replace(docxFilename, "docx", "pdf", -1)
	docx1.WriteToFile("./.tmp/" + docxFilename)
	r.Close()

	// 导出pdf到目标目录
	folderPath := "Purchase_Contract/" + time.Now().Format("20060102")
	savePath := openconfig.CONFIGVALUE + "/uploadFile/" + folderPath
	if exist, _ := utils.PathExists(savePath); !exist {
		os.MkdirAll(savePath, os.ModePerm)
	}
	success := utils.ConvertToPDF("./.tmp/"+docxFilename, savePath)
	if !success {
		// 转换失败
		global.M2A_LOG.Error("[铁合金成交通知] docx转换pdf失败", zap.Error(err))
		return
	}

	// 更新数据库
	// pdfFilename = docxFilename // 临时代码
	thjpurchasetradedetail.CONTRACTADDRBUY = fmt.Sprintf("./uploadFile/%v/%v", folderPath, pdfFilename)
	if err = thjpurchasetradedetail.UpdateContractAddrBuy(); err != nil {
		global.M2A_LOG.Error("[铁合金成交通知] 更新数据库失败", zap.Error(err))
		return
	}
	global.M2A_LOG.Info("[铁合金成交通知] 合同生成成功", zap.Any("file", savePath+pdfFilename))
}

// onTHJPurchaseTransferNtf 铁合金协议转让通知
func onTHJPurchaseTransferNtf(bytes *[]byte) {
	// Read from docx file
	r, err := docx.ReadDocxFile("./static/协议转让合同.docx")
	if err != nil {
		global.M2A_LOG.Error("[铁合金协议转让通知] 读取合同文件失败", zap.Error(err))
		return
	}

	// 获取网上开户地址（用于客户端下载文件）
	openconfig := model.Wskhopenaccountconfig{CONFIGID: 6}
	if has, err := openconfig.Get(); err != nil || !has {
		global.M2A_LOG.Error("[铁合金协议转让通知] 获取网上开户地址失败", zap.Error(err))
		return
	}

	var p pb.PurchaseTransferNtf
	if err := proto.Unmarshal(*bytes, &p); err != nil {
		global.M2A_LOG.Error("[铁合金协议转让通知] 总线回复数据反序列化失败", zap.Error(err))
		return
	}

	// 铁合金采购协议表
	thjpurchasetransfer := model.Thjpurchasetransfer{TRANSFERID: int64(p.GetTransferID())}
	if has, err := thjpurchasetransfer.Get(); err != nil || !has {
		global.M2A_LOG.Error("[铁合金协议转让通知] 获取铁合金采购协议表信息失败", zap.Error(err))
		return
	}

	// 铁合金采购成交扩展信息
	thjpurchasetradedetail := model.Thjpurchasetradedetail{WRTRADEDETAILID: thjpurchasetransfer.WRTRADEDETAILID}
	if has, err := thjpurchasetradedetail.Get(); err != nil || !has {
		global.M2A_LOG.Error("[铁合金协议转让通知] 获取铁合金采购成交扩展信息失败", zap.Error(err))
		return
	}

	// 现货商品信息
	wrstandard := model.Wrstandard{WRSTANDARDID: int64(thjpurchasetradedetail.WRSTANDARDID)}
	if has, err := wrstandard.Get(); err != nil || !has {
		global.M2A_LOG.Error("[铁合金协议转让通知] 获取现货商品信息失败", zap.Error(err))
		return
	}

	// ******************* 甲方信息（卖方）*******************
	a_userinfo := model.Userinfo{USERID: thjpurchasetransfer.SELLUSERID}
	if has, err := a_userinfo.Get(); err != nil || !has {
		global.M2A_LOG.Error("[铁合金协议转让通知] 获取甲方信息失败", zap.Error(err))
		return
	}
	a_division := model.Division{AUTOID: int64(a_userinfo.DISTRICTID)}
	a_totalAddress, err := a_division.GetTotalAddressByDistrictID(a_userinfo.ADDRESS)
	if err != nil {
		global.M2A_LOG.Error("[铁合金协议转让通知] 获取甲方地址信息失败", zap.Error(err))
		return
	}
	// 证件号码解密
	key, _ := hex.DecodeString(utils.AESSecretKey)
	if len(a_userinfo.CARDNUM) > 0 {
		if cardnum, err := hex.DecodeString(a_userinfo.CARDNUM); err == nil { // hex -> []byte
			if c, err := utils.AESDecrypt(cardnum, key); err == nil {
				a_userinfo.CARDNUM = string(c)
			}
		}
	}
	// 手机号码解密
	if len(a_userinfo.MOBILE) > 0 {
		if phonenum, err := hex.DecodeString(a_userinfo.MOBILE); err == nil { // hex -> []byte
			if mobile, err := utils.AESDecrypt(phonenum, key); err == nil {
				a_userinfo.MOBILE = string(mobile)
			}
		}
	}
	// 签约信息
	a_bankaccountsign := model.Bankaccountsign{}
	if has, err := a_bankaccountsign.GetByUserID(uint64(thjpurchasetransfer.SELLUSERID)); err != nil || !has {
		global.M2A_LOG.Error("[铁合金协议转让通知] 获取甲方签约信息失败", zap.Error(err))
		return
	}
	// 账号解密
	if len(a_bankaccountsign.BANKACCOUNTNO) > 0 {
		if tt, err := hex.DecodeString(a_bankaccountsign.BANKACCOUNTNO); err == nil { // hex -> []byte
			if dd, err := utils.AESDecrypt(tt, key); err == nil {
				a_bankaccountsign.BANKACCOUNTNO = string(dd)
			}
		}
	}
	// 银行信息
	a_bankinfo := model.Bankbankinfo{BANKID: a_bankaccountsign.BANKID}
	if has, err := a_bankinfo.Get(); err != nil || !has {
		global.M2A_LOG.Error("[铁合金协议转让通知] 获取银行信息失败", zap.Error(err))
		return
	}

	// ******************* 乙方信息（买方）*******************
	b_userinfo := model.Userinfo{USERID: thjpurchasetransfer.BUYUSERID}
	if has, err := b_userinfo.Get(); err != nil || !has {
		global.M2A_LOG.Error("[铁合金协议转让通知] 获取乙方信息失败", zap.Error(err))
		return
	}
	b_division := model.Division{AUTOID: int64(b_userinfo.DISTRICTID)}
	b_totalAddress, err := b_division.GetTotalAddressByDistrictID(b_userinfo.ADDRESS)
	if err != nil {
		global.M2A_LOG.Error("[铁合金协议转让通知] 获取乙方地址信息失败", zap.Error(err))
		return
	}
	// 证件号码解密
	if len(b_userinfo.CARDNUM) > 0 {
		if cardnum, err := hex.DecodeString(b_userinfo.CARDNUM); err == nil { // hex -> []byte
			if c, err := utils.AESDecrypt(cardnum, key); err == nil {
				b_userinfo.CARDNUM = string(c)
			}
		}
	}
	// 手机号码解密
	if len(b_userinfo.MOBILE) > 0 {
		if phonenum, err := hex.DecodeString(b_userinfo.MOBILE); err == nil { // hex -> []byte
			if mobile, err := utils.AESDecrypt(phonenum, key); err == nil {
				b_userinfo.MOBILE = string(mobile)
			}
		}
	}
	// 签约信息
	b_bankaccountsign := model.Bankaccountsign{}
	if has, err := b_bankaccountsign.GetByUserID(uint64(thjpurchasetransfer.BUYUSERID)); err != nil || !has {
		global.M2A_LOG.Error("[铁合金协议转让通知] 获取乙方签约信息失败", zap.Error(err))
		return
	}
	// 账号解密
	if len(b_bankaccountsign.BANKACCOUNTNO) > 0 {
		if tt, err := hex.DecodeString(b_bankaccountsign.BANKACCOUNTNO); err == nil { // hex -> []byte
			if dd, err := utils.AESDecrypt(tt, key); err == nil {
				b_bankaccountsign.BANKACCOUNTNO = string(dd)
			}
		}
	}
	// 银行信息
	b_bankinfo := model.Bankbankinfo{BANKID: b_bankaccountsign.BANKID}
	if has, err := b_bankinfo.Get(); err != nil || !has {
		global.M2A_LOG.Error("[铁合金协议转让通知] 获取乙方银行信息失败", zap.Error(err))
		return
	}

	docx1 := r.Editable()
	docx1.Replace("TRANSFERID", strconv.Itoa(int(thjpurchasetransfer.TRANSFERID)), -1)
	if transfertradedate, e := time.Parse("20060102", thjpurchasetransfer.TRANSFERTRADEDATE); e != nil {
		docx1.Replace("TRANSFERTRADEDATE", transfertradedate.Format("2006年01月02日"), -1)
	}
	docx1.Replace("WRSTANDARDNAME", wrstandard.WRSTANDARDNAME, -1)
	docx1.Replace("WRTRADEDETAILID", strconv.Itoa(int(thjpurchasetradedetail.WRTRADEDETAILID)), -1)
	docx1.Replace("TRANSFERQTY", strconv.Itoa(int(thjpurchasetransfer.TRANSFERQTY)), -1)
	docx1.Replace("TRADEAMOUNT", strconv.FormatFloat(thjpurchasetradedetail.TRADEAMOUNT, 'f', -1, 64), -1)
	docx1.Replace("TRANSFERAMOUNT", strconv.FormatFloat(thjpurchasetransfer.TRANSFERAMOUNT, 'f', -1, 64), -1)
	docx1.Replace("TRANSFERPRICE", strconv.FormatFloat(thjpurchasetransfer.TRANSFERPRICE, 'f', -1, 64), -1)
	// ********************* 甲方 *********************
	// 判断甲方是公司还是个人
	if a_userinfo.USERINFOTYPE == 1 {
		// 个人
		docx1.Replace("PARTYA_COMPANY", "", -1)
		docx1.Replace("PARTYA_LEGALPERSONNAME", a_userinfo.CUSTOMERNAME, -1)
	} else {
		// 公司
		docx1.Replace("PARTYA_COMPANY", a_userinfo.CUSTOMERNAME, -1)
		docx1.Replace("PARTYA_LEGALPERSONNAME", a_userinfo.LEGALPERSONNAME, -1)
	}
	docx1.Replace("PARTYA_DESADDRESS", a_totalAddress, -1)
	docx1.Replace("PARTYA_CARDNUM", a_userinfo.CARDNUM, -1)
	docx1.Replace("PARTYA_MOBILE", a_userinfo.MOBILE, -1)
	docx1.Replace("PARTYA_BANK_BANKACCOUNTNO",
		fmt.Sprintf("%v%v", a_bankinfo.BANKNAME, a_bankaccountsign.BANKACCOUNTNO), -1)
	// ********************* 乙方 *********************
	// 判断乙方是公司还是个人
	if b_userinfo.USERINFOTYPE == 1 {
		// 个人
		docx1.Replace("PARTYB_COMPANY", "", -1)
		docx1.Replace("PARTYB_LEGALPERSONNAME", b_userinfo.CUSTOMERNAME, -1)
	} else {
		// 公司
		docx1.Replace("PARTYB_COMPANY", b_userinfo.CUSTOMERNAME, -1)
		docx1.Replace("PARTYB_LEGALPERSONNAME", b_userinfo.LEGALPERSONNAME, -1)
	}
	docx1.Replace("PARTYB_DESADDRESS", b_totalAddress, -1)
	docx1.Replace("PARTYB_CARDNUM", b_userinfo.CARDNUM, -1)
	docx1.Replace("PARTYB_MOBILE", b_userinfo.MOBILE, -1)
	docx1.Replace("PARTYB_BANK_BANKACCOUNTNO",
		fmt.Sprintf("%v%v", b_bankinfo.BANKNAME, b_bankaccountsign.BANKACCOUNTNO), -1)

	// 暂存docx文件
	if exist, _ := utils.PathExists("./.tmp"); !exist {
		os.Mkdir("./.tmp", os.ModePerm)
	}
	uid, _ := uuid.NewV4()
	docxFilename := fmt.Sprintf("%v_%v.docx", strconv.Itoa(int(thjpurchasetransfer.TRANSFERID)), uid.String())
	pdfFilename := strings.Replace(docxFilename, "docx", "pdf", -1)
	docx1.WriteToFile("./.tmp/" + docxFilename)
	r.Close()

	// 导出pdf到目标目录
	folderPath := "Agreement_Assignment/" + time.Now().Format("20060102")
	savePath := openconfig.CONFIGVALUE + "/uploadFile/" + folderPath
	if exist, _ := utils.PathExists(savePath); !exist {
		os.MkdirAll(savePath, os.ModePerm)
	}
	success := utils.ConvertToPDF("./.tmp/"+docxFilename, savePath)
	if !success {
		// 转换失败
		global.M2A_LOG.Error("[铁合金协议转让通知] docx转换pdf失败", zap.Error(err))
		return
	}

	// 更新数据库
	thjpurchasetransfer.CONTRACTADDR = fmt.Sprintf("./uploadFile/%v/%v", folderPath, pdfFilename)
	if err = thjpurchasetransfer.UpdateContractAddr(); err != nil {
		global.M2A_LOG.Error("[铁合金协议转让通知] 更新数据库失败", zap.Error(err))
		return
	}
	global.M2A_LOG.Info("[铁合金协议转让通知] 合同生成成功", zap.Any("file", savePath+pdfFilename))
}

// onWRTradeDealedNtf 仓单贸易成交通知
func onWRTradeDealedNtf(bytes *[]byte) {
	var p pb.WRTradeDealedNtf
	if err := proto.Unmarshal(*bytes, &p); err != nil {
		global.M2A_LOG.Error("[仓单贸易成交通知] 总线回复数据反序列化失败", zap.Error(err))
		return
	}
	if p.GetHeader().GetMarketID() != 65201 {
		return
	}

	// 铁合金采购协议表
	wrtradetradequote := model.Wrtradetradequote{WRTRADEDETAILID: int64(p.GetTradeID())}
	if has, err := wrtradetradequote.Get(); err != nil || !has {
		global.M2A_LOG.Error("[仓单贸易成交通知] 获取仓单贸易成交行情表信息失败", zap.Error(err))
		return
	}

	buildWRTradeDealedContract(wrtradetradequote, 0)
	buildWRTradeDealedContract(wrtradetradequote, 1)
}

/*
buildWRTradeDealedContract 生成现货采购合同

buyOrSell 0-买方合同 1-卖方合同
*/
func buildWRTradeDealedContract(wrtradetradequote model.Wrtradetradequote, buyOrSell int) {
	tempDocx := "./static/现货贸易合同（买家模板）.docx"
	if buyOrSell == 1 {
		tempDocx = "./static/现货贸易合同（卖家模板）.docx"
	}
	r, err := docx.ReadDocxFile(tempDocx)
	if err != nil {
		global.M2A_LOG.Error("[仓单贸易成交通知] 读取合同文件失败", zap.Error(err))
		return
	}

	// 获取网上开户地址（用于客户端下载文件）
	openconfig := model.Wskhopenaccountconfig{CONFIGID: 6}
	if has, err := openconfig.Get(); err != nil || !has {
		global.M2A_LOG.Error("[仓单贸易成交通知] 获取网上开户地址失败", zap.Error(err))
		return
	}

	// 现货商品信息
	wrstandard := model.Wrstandard{WRSTANDARDID: int64(wrtradetradequote.WRSTANDARDID)}
	if has, err := wrstandard.Get(); err != nil || !has {
		global.M2A_LOG.Error("[仓单贸易成交通知] 获取现货商品信息失败", zap.Error(err))
		return
	}

	// 甲方或乙方信息
	userId := wrtradetradequote.BUYUSERID
	if buyOrSell == 1 {
		userId = wrtradetradequote.SELLUSERID
	}
	userinfo := model.Userinfo{USERID: userId}
	if has, err := userinfo.Get(); err != nil || !has {
		global.M2A_LOG.Error("[仓单贸易成交通知] 获取用户信息失败", zap.Error(err))
		return
	}
	division := model.Division{AUTOID: int64(userinfo.DISTRICTID)}
	totalAddress, err := division.GetTotalAddressByDistrictID(userinfo.ADDRESS)
	if err != nil {
		global.M2A_LOG.Error("[仓单贸易成交通知] 获取用户地址信息失败", zap.Error(err))
		return
	}
	// 证件号码解密
	key, _ := hex.DecodeString(utils.AESSecretKey)
	if len(userinfo.CARDNUM) > 0 {
		if cardnum, err := hex.DecodeString(userinfo.CARDNUM); err == nil { // hex -> []byte
			if c, err := utils.AESDecrypt(cardnum, key); err == nil {
				userinfo.CARDNUM = string(c)
			}
		}
	}
	// 手机号码解密
	if len(userinfo.MOBILE) > 0 {
		if phonenum, err := hex.DecodeString(userinfo.MOBILE); err == nil { // hex -> []byte
			if mobile, err := utils.AESDecrypt(phonenum, key); err == nil {
				userinfo.MOBILE = string(mobile)
			}
		}
	}

	// 签约信息
	bankaccountsign := model.Bankaccountsign{}
	if has, err := bankaccountsign.GetByUserID(uint64(userId)); err != nil || !has {
		global.M2A_LOG.Error("[仓单贸易成交通知] 获取用户签约信息失败", zap.Error(err))
		return
	}
	// 账号解密
	if len(bankaccountsign.BANKACCOUNTNO) > 0 {
		if tt, err := hex.DecodeString(bankaccountsign.BANKACCOUNTNO); err == nil { // hex -> []byte
			if dd, err := utils.AESDecrypt(tt, key); err == nil {
				bankaccountsign.BANKACCOUNTNO = string(dd)
			}
		}
	}

	// 银行信息
	bankinfo := model.Bankbankinfo{BANKID: bankaccountsign.BANKID}
	if has, err := bankinfo.Get(); err != nil || !has {
		global.M2A_LOG.Error("[仓单贸易成交通知] 获取银行信息失败", zap.Error(err))
		return
	}

	// 电子仓单号
	type temp struct {
		LADINGBILLID string `xorm:"LADINGBILLID"`
	}
	_temp := temp{}
	sql := fmt.Sprintf(`
	select 
		to_char(wrd.LADINGBILLID) LADINGBILLID
	from wrtrade_tradedetail td
	left join WRChangeDetail wrd on td.wrid = wrd.wrid and wrd.changetype = 1
	where td.WRTRADEDETAILID = %v and td.wrtradetype = 2
  	`, wrtradetradequote.WRTRADEDETAILID)
	global.M2A_DB.SQL(sql).Get(&_temp)

	docx1 := r.Editable()
	docx1.Replace("${WRTRADEDETAILID}", strconv.Itoa(int(wrtradetradequote.WRTRADEDETAILID)), -1)
	if transfertradedate, e := time.Parse("20060102", wrtradetradequote.TRADEDATE); e != nil {
		docx1.Replace("TRADEDATE", transfertradedate.Format("2006年01月02日"), -1)
	}
	// 判断是公司还是个人
	if userinfo.USERINFOTYPE == 1 {
		// 个人
		docx1.Replace("COMPANY", "", -1)
		docx1.Replace("LEGALPERSONNAME", userinfo.CUSTOMERNAME, -1)
	} else {
		// 公司
		docx1.Replace("COMPANY", userinfo.CUSTOMERNAME, -1)
		docx1.Replace("LEGALPERSONNAME", userinfo.LEGALPERSONNAME, -1)
	}
	docx1.Replace("DESADDRESS", totalAddress, -1)
	docx1.Replace("CARDNUM", userinfo.CARDNUM, -1)
	docx1.Replace("MOBILE", userinfo.MOBILE, -1)
	docx1.Replace("BANK", bankinfo.BANKNAME, -1)
	docx1.Replace("BANKACCOUNTNO", bankaccountsign.BANKACCOUNTNO, -1)
	docx1.Replace("WRSTANDARDNAME", wrstandard.WRSTANDARDNAME, -1)
	docx1.Replace("TRADEQTY", strconv.Itoa(int(wrtradetradequote.TRADEQTY)), -1)
	docx1.Replace("TRADEPRICE", strconv.FormatFloat(wrtradetradequote.TRADEPRICE, 'f', -1, 64), -1)
	docx1.Replace("TRADEAMOUNT", strconv.FormatFloat(wrtradetradequote.TRADEAMOUNT, 'f', -1, 64), -1)
	docx1.Replace("STORAGEFEE", strconv.FormatFloat(wrstandard.STORAGEFEE, 'f', -1, 64), -1)
	docx1.Replace("LADINGBILLID", _temp.LADINGBILLID, -1)

	// 暂存docx文件
	if exist, _ := utils.PathExists("./.tmp"); !exist {
		os.Mkdir("./.tmp", os.ModePerm)
	}
	uid, _ := uuid.NewV4()
	docxFilename := fmt.Sprintf("%v_%v_%v.docx", buyOrSell, strconv.Itoa(int(wrtradetradequote.WRTRADEDETAILID)), uid.String())
	pdfFilename := strings.Replace(docxFilename, "docx", "pdf", -1)
	docx1.WriteToFile("./.tmp/" + docxFilename)
	r.Close()

	// 导出pdf到目标目录
	folderPath := "Spot_Contract/" + time.Now().Format("20060102")
	savePath := openconfig.CONFIGVALUE + "/uploadFile/" + folderPath
	if exist, _ := utils.PathExists(savePath); !exist {
		os.MkdirAll(savePath, os.ModePerm)
	}
	success := utils.ConvertToPDF("./.tmp/"+docxFilename, savePath)
	if !success {
		// 转换失败
		global.M2A_LOG.Error("[仓单贸易成交通知] docx转换pdf失败", zap.Error(err))
		return
	}

	// 更新数据库
	if buyOrSell == 0 {
		wrtradetradequote.CONTRACTADDRBUY = fmt.Sprintf("./uploadFile/%v/%v", folderPath, pdfFilename)
	} else {
		wrtradetradequote.CONTRACTADDRSELL = fmt.Sprintf("./uploadFile/%v/%v", folderPath, pdfFilename)
	}
	if err = wrtradetradequote.UpdateContractAddr(buyOrSell); err != nil {
		global.M2A_LOG.Error("[仓单贸易成交通知] 更新数据库失败", zap.Error(err))
		return
	}
	global.M2A_LOG.Info("[仓单贸易成交通知] 合同生成成功", zap.Any("file", savePath+pdfFilename))
}
