package pay

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/x509"
	"database/sql"
	"encoding/base64"
	"encoding/json"
	"encoding/pem"
	"errors"
	"fmt"
	"github.com/astaxie/beego/httplib"
	uID "github.com/satori/go.uuid"
	"io/ioutil"
	rand2 "math/rand"
	"strconv"
	"strings"
	"system_pay/models"
	"system_pay/mysql"
	"system_pay/setting"
	"time"
)

// 拉卡拉支付
func UnifiedOrder(input *models.PlaceAnOrderParamInput, ip string) (interface{}, error) {
	//输入项check
	if input.SourceCode==0 {
		return nil, errors.New("输入项「source_code」为空错误")
	}
	if input.PlatformType==0 {
		return nil, errors.New("输入项「platform_type」为空错误")
	}

	fmt.Println("谛宝多多输入参数")
	fmt.Println(input)

	orderID := GetUID()

	attachMap := make(map[string]interface{}, 0)
	attachMap["store_sn"] = input.StoreSn
	attachMap["old_attach"] = input.AttachInfo

	attach, _ := json.Marshal(attachMap)
	input.AttachInfo = string(attach)

	// 插入数据库
	db, err := mysql.NewPayConn()
	if err != nil {
		return 0, err
	}

	tx, err := db.Begin()
	if err != nil {
		return nil, err
	}

	defer mysql.CloseTx(tx, err)

	billID, err := InsertPayBill(tx, input, orderID)
	if err != nil {
		return nil, err
	}

	//数据重组 - start
	now := time.Now()
	now.Add(time.Minute * 60)
	date_time1 := now.Format("20060102150405")
	date_time2 := now.Add(time.Minute * 60).Format("20060102150405")

	var version, out_org_code, merchant_no1, merchant_no2, merchant_no3, term_no3, merchant_no4, term_no4 string
	//平台类型 1:saas 2:shop 3:shop mobile 4:收银台 6:bk_shop 7:bk_shop_mobile
	if input.PlatformType==2 || input.PlatformType==3 {
		// 谛宝多多自营
		version = setting.Conf.Lakala.DbcVersion
		out_org_code = setting.Conf.Lakala.DbcAppid
		merchant_no1 = setting.Conf.Lakala.DbcMerchantNo1
		merchant_no2 = setting.Conf.Lakala.DbcMerchantNo2
		merchant_no3 = setting.Conf.Lakala.DbcMerchantNo3
		term_no3 = setting.Conf.Lakala.DbcTermNo3
		merchant_no4 = setting.Conf.Lakala.DbcMerchantNo4
		term_no4 = setting.Conf.Lakala.DbcTermNo4
	} else if input.PlatformType==6 || input.PlatformType==7 {
		// 必康自营
		version = setting.Conf.Lakala.BkVersion
		out_org_code = setting.Conf.Lakala.BkAppid
		merchant_no1 = setting.Conf.Lakala.BkMerchantNo1
		merchant_no2 = setting.Conf.Lakala.BkMerchantNo2
		merchant_no3 = setting.Conf.Lakala.BkMerchantNo3
		term_no3 = setting.Conf.Lakala.BkTermNo3
		merchant_no4 = setting.Conf.Lakala.BkMerchantNo4
		term_no4 = setting.Conf.Lakala.BkTermNo4
	} else {
		// 必康医生
		version = setting.Conf.Lakala.SaasVersion
		out_org_code = setting.Conf.Lakala.SaasAppid
		merchant_no1 = setting.Conf.Lakala.SaasMerchantNo1
		merchant_no2 = setting.Conf.Lakala.SaasMerchantNo2
		merchant_no3 = setting.Conf.Lakala.SaasMerchantNo3
		term_no3 = setting.Conf.Lakala.SaasTermNo3
		merchant_no4 = setting.Conf.Lakala.SaasMerchantNo4
		term_no4 = setting.Conf.Lakala.SaasTermNo4
	}

	var url string
	data := make(map[string]interface{}) //数据结构
	data["req_time"] = date_time1
	data["version"] = version
	data["out_org_code"] = out_org_code

	//source_code 1: 微信 Native 2:微信小程序 3:微信内支付 4:h5 跳微信
	//5:支付宝(web)-扫码或登录支付宝账户 6:alipay(mobile) 7:alipay(app)
	//9: B2C 10:bk支付宝web 11:bk 支付宝手机 15:快捷支付(银行卡) 16:微信小程序-必康自营
	if input.SourceCode==4 || input.SourceCode==6 ||input.SourceCode==1 ||
		input.SourceCode==5 || input.SourceCode==15 || input.SourceCode==16 {
		//聚合收银台(微信H5、支付宝H5、微信扫码、支付宝扫码)
		//聚合收银台(微信小程序-必康自营)
		//url = "https://test.wsmsd.cn/sit/api/v3/ccss/counter/order/create" //聚合收银台
		url = setting.Conf.Lakala.UrlCreate //聚合收银台

		//input.ReturnURL = "https://test.pet-dbc.cn"

		// 构造回调url
		input.NoticeURL = GetNoticeURL(input.SourceCode)

		data2 := make(map[string]interface{})
		if input.SourceCode==4 || input.SourceCode==6 {
			data2["merchant_no"] = merchant_no1 //微信H5、支付宝H5
		} else {
			data2["merchant_no"] = merchant_no2 //微信扫码、支付宝扫码
		}
		data2["total_amount"] = input.GoodsPrice*100
		data2["out_order_no"] = orderID //随机生成的订单号 //商户订单号

		if input.SourceCode==15 {
			//快捷支付
			data2["counter_param"] = "{\"pay_mode\":\"QUICK_PAY\"}"
		} else if input.SourceCode < 5 || input.SourceCode==16 {
			//微信
			data2["counter_param"] = "{\"pay_mode\":\"WECHAT\"}"
		} else {
			//支付宝
			data2["counter_param"] = "{\"pay_mode\":\"ALIPAY\"}"
		}

		data2["order_efficient_time"] = date_time2 //订单有效期 格式yyyyMMddHHmmss,最大支持下单时间+2天
		data2["notify_url"] = input.NoticeURL      //订单支付成功后商户接收订单通知的地址 http://xxx.xxx.com
		data2["callback_url"] = input.ReturnURL    //客户端下单完成支付后返回的商户网页跳转地址
		data2["order_info"] = input.PlatformInfo   //订单标题,在使用收银台扫码支付时必输入,交易时送往账户端
		//data2["goods_mark"] = input.AttachInfo   //商品信息标识 (1:含商品信息,不填默认不含商品信息)
		data2["support_refund"] = 1                //是否支持退款 默认0 不支持

		data["req_data"] = make(map[string]interface{})
		data["req_data"] = data2

	} else if input.SourceCode==2 || input.SourceCode==3 {
		//聚合主扫(微信JSAPI、微信小程序)
		//url = "https://test.wsmsd.cn/sit/api/v3/labs/trans/preorder" //聚合主扫
		url = setting.Conf.Lakala.UrlPreorder //聚合主扫

		//input.ReturnURL = "https://test.pet-dbc.cn"

		// 构造回调url
		input.NoticeURL = GetNoticeURL(input.SourceCode)

		data2 := make(map[string]interface{})
		data2["merchant_no"] = merchant_no3
		data2["term_no"] = term_no3
		data2["total_amount"] = input.GoodsPrice*100
		data2["out_trade_no"] = orderID //随机生成的订单号 //商户交易流水号

		data2["order_efficient_time"] = date_time2 //订单有效期 格式yyyyMMddHHmmss,最大支持下单时间+2天
		data2["notify_url"] = input.NoticeURL      //订单支付成功后商户接收订单通知的地址 http://xxx.xxx.com
		data2["callback_url"] = input.ReturnURL    //客户端下单完成支付后返回的商户网页跳转地址
		data2["order_info"] = input.PlatformInfo   //订单标题,在使用收银台扫码支付时必输入,交易时送往账户端
		//data2["goods_mark"] = input.AttachInfo   //商品信息标识 (1:含商品信息,不填默认不含商品信息)

		//微信JSAPI、微信小程序
		data2["account_type"] = "WECHAT" //钱包类型
		if input.SourceCode==2 {
			data2["trans_type"] = "71" //接入方式:微信小程序
		} else {
			data2["trans_type"] = "51" //接入方式:微信JSAPI
		}

		//地址位置信息
		data3 := make(map[string]interface{})
		data3["request_ip"] = ip
		data2["location_info"] = make(map[string]interface{})
		data2["location_info"] = data3

		//地址位置信息
		data4 := make(map[string]interface{})
		data4["sub_appid"] = input.AppID //子商户公众账号ID
		data4["user_id"] = input.OpenID //用户标识(sub_openid)

		data2["acc_busi_fields"] = make(map[string]interface{})
		data2["acc_busi_fields"] = data4

		data["req_data"] = make(map[string]interface{})
		data["req_data"] = data2

	} else if input.SourceCode==9 {
		//聚合被扫(扫码枪)
		if input.DynamicID=="" {
			return nil, errors.New("输入项「dynamic_id」为空错误")
		}

		//url = "https://test.wsmsd.cn/sit/api/v3/labs/trans/micropay" //聚合被扫
		url = setting.Conf.Lakala.UrlMicropay //聚合被扫

		data2 := make(map[string]interface{})
		data2["merchant_no"] = merchant_no4
		data2["term_no"] = term_no4
		data2["out_trade_no"] = orderID //随机生成的订单号 //商户交易流水号
		//扫码支付授权码,设备读取用户APP中的条码或者二维码信息,用户付款码条形码规则见说明
		//data2["auth_code"] = "135178236713755038"
		data2["auth_code"] = input.DynamicID
		data2["total_amount"] = input.GoodsPrice*100

		data3 := make(map[string]interface{})
		//data3["request_ip"] = "10.176.1.192"
		data3["request_ip"] = ip
		//data3["location"] = "+37.123456789,-121.123456789"
		data2["location_info"] = make(map[string]interface{})
		data2["location_info"] = data3

		data["req_data"] = make(map[string]interface{})
		data["req_data"] = data2

	} else {
		return nil, errors.New("输入参数「source_code」错误,有效值为[1-6,9,15,16]")
	}
	//数据重组 - end
	fmt.Println("拉卡拉输入参数")
	fmt.Println(data)
	fmt.Println("拉卡拉接口url")
	fmt.Println(url)

	// 插入下单请求参数
	err = InsertPayBillDetailRequestBody(tx, billID, data)
	if err != nil {
		return nil, err
	}

	data_json, err := json.Marshal(data)
	if err != nil {
		//this.Data["json"] = utils.CheckError(errors.New("Map转化为byte数组失败"),"异常")
		//this.ServeJSON()
		return nil, err
	}

	//调拉卡拉接口
	err, response, lakala_rtn := lakala_post(input, url, data_json)
	if err != nil {
		InsertPayBillDetailResponseBody(tx, billID, lakala_rtn) //todo
		return nil, err
	}

	// 插入下单成功后返回的参数
	err = InsertPayBillDetailResponseBody(tx, billID, lakala_rtn)
	if err != nil {
		//beego.Error("下单请求成功 --- 但插入成功后的参数失败")
		return nil, err
	}

	if input.SourceCode==9 {
		//收钱吧(扫码枪)
		response := make(map[string]string)
		response["payment_order_code"] = orderID //随机生成的订单号
		return response, nil
	}

	return response, nil
}

func lakala_post(input *models.PlaceAnOrderParamInput, url string, data_json []byte) (error, interface{}, interface{}) {

	var source_code, platform_type uint8
	if input==nil {
		source_code = 0     //支付方式
		platform_type = 0   //平台类型
	} else {
		source_code = input.SourceCode     //支付方式
		platform_type = input.PlatformType //平台类型
	}

	authorization, err := getAuthorization(platform_type, string(data_json))
	if err != nil {
		return err, "", nil
	}

	fmt.Println(url)
	fmt.Println(authorization)

	req := httplib.Post(url)
	//req.Header("Authorization", "LKLAPI-SHA256withRSA appid=\"\", serial_no=\"\", timestamp=\"\", nonce_str=\"\", signature=\"2233\"")
	req.Header("Authorization", authorization)
	req.Header("Accept", "application/json")
	req.Header("Content-Type", "application/json")
	req.Body(data_json)
	body, err := req.Bytes()
	if err != nil {
		return err, "", nil
	}

	temp := make(map[string]interface{}, 0)
	if err = json.Unmarshal(body, &temp); err != nil {
		return err, "", nil
	}

	fmt.Println("拉卡拉返回值")
	fmt.Println(temp)
	//todo
	if temp["code"] != "000000" && temp["code"] != "BBS00000"{
		//this.Data["json"] = utils.CheckError(errors.New("拉卡拉错误"), temp["msg"].(string))  //todo
		//this.ServeJSON()
		return errors.New(temp["msg"].(string)), "", temp
	}
	//return nil, temp["resp_data"]["counter_url"]

	response := make(map[string]string)
	if source_code==4 || source_code==6 || source_code==1 || source_code==5 || source_code==15 || input.SourceCode==16 {
		//聚合收银台(微信H5、支付宝H5、微信扫码、支付宝扫码、快捷支付(银行卡))
		//聚合收银台(微信小程序-必康自营)
		temp2, _ := temp["resp_data"].(map[string]interface{})
		if temp2["counter_url"]=="" {
			return errors.New("拉卡拉返回值「counter_url」为空错误"), "", temp
		}
		if source_code==4 || source_code==6 || source_code==15 || input.SourceCode==16 {
			//微信H5、支付宝H5、快捷支付(银行卡)
			//聚合收银台(微信小程序-必康自营)
			response["m_web_url"] = temp2["counter_url"].(string)
		} else {
			//微信扫码、支付宝扫码
			response["qr_code_url"] = temp2["counter_url"].(string)
		}

	} else if source_code==2 || source_code==3 {
		//聚合主扫(微信JSAPI+微信小程序)
		temp2, _ := temp["resp_data"].(map[string]interface{})
		temp3, _ := temp2["acc_resp_fields"].(map[string]interface{})
		if temp2["acc_resp_fields"]=="" {
			return errors.New("拉卡拉返回值「acc_resp_fields」为空错误"), "", temp
		}
		response["app_id"] = temp3["app_id"].(string)
		response["nonce_str"] = temp3["nonce_str"].(string)
		response["package"] = temp3["package"].(string)
		response["pay_sign"] = temp3["pay_sign"].(string)
		response["prepay_id"] = temp3["prepay_id"].(string)
		response["sign_type"] = temp3["sign_type"].(string)
		response["timeStamp"] = temp3["time_stamp"].(string)
	} else if source_code==9 {
		//扫码枪
	}

	return nil, response, temp
}

func getAuthorization(platform_type uint8, body string) (string, error) {

	var path_private_key, appid, mchSerialNo string //私钥文件地址
	//平台类型 1:saas 2:shop 3:shop mobile 4:收银台 6:bk_shop 7:bk_shop_mobile
	if platform_type==2 || platform_type==3 {
		// 谛宝多多自营
		appid = setting.Conf.Lakala.DbcAppid
		mchSerialNo = setting.Conf.Lakala.DbcSerialNo
		path_private_key = setting.Conf.Lakala.DbcPathPrivateKey
	} else if platform_type==6 || platform_type==7 {
		// 必康自营
		appid = setting.Conf.Lakala.BkAppid
		mchSerialNo = setting.Conf.Lakala.BkSerialNo
		path_private_key = setting.Conf.Lakala.BkPathPrivateKey
	} else {
		// 必康医生
		appid = setting.Conf.Lakala.SaasAppid
		mchSerialNo = setting.Conf.Lakala.SaasSerialNo
		path_private_key = setting.Conf.Lakala.SaasPathPrivateKey
	}

	nonceStr := RandomString(32) // 构造随机数
	timestamp := strconv.FormatInt(time.Now().Unix(), 10)

	message := appid + "\n" + mchSerialNo + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n";


	//todo 退款时,证书???
	//return "", errors.New("输入项「平台类型(platform_type)」数据错误")

	//base64Sig, err := RSASign([]byte(message), "./cert/dev/OP00000003_private_key.pem")
	base64Sig, err := RSASign([]byte(message), path_private_key)
	if err != nil {
		return "", err
	}

	//fmt.Println("签名2:", base64Sig)
	signature := base64Sig
	authorization := "LKLAPI-SHA256withRSA " + "appid=\"" + appid + "\"," + "serial_no=\"" + mchSerialNo + "\"," + "timestamp=\"" + timestamp + "\"," + "nonce_str=\"" + nonceStr + "\"," + "signature=\"" + signature + "\"";

	//System.out.println("authorization message :" + authorization);
	return authorization, nil
}

//生产随机字符串
func RandomString(n int) string {
	var letters = []byte("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
	result := make([]byte, n)
	rand2.Seed(time.Now().Unix())
	for i := range result {
		result[i] = letters[rand2.Intn(len(letters))]
	}
	return string(result)
}

// 私钥签名过程
func RSASign(data []byte, filename string) (string, error) {
	// 1、选择hash算法,对需要签名的数据进行hash运算
	myhash := crypto.SHA256
	hashInstance := myhash.New()
	hashInstance.Write(data)
	hashed := hashInstance.Sum(nil)
	// 2、读取私钥文件,解析出私钥对象
	privateKey, err := ReadParsePrivaterKey(filename)
	if err != nil {
		return "", err
	}
	// 3、RSA数字签名(参数是随机数、私钥对象、哈希类型、签名文件的哈希串),生成base64编码的签名字符串
	bytes, err := rsa.SignPKCS1v15(rand.Reader, privateKey, myhash, hashed)
	if err != nil {
		return "", err
	}
	return base64.StdEncoding.EncodeToString(bytes), nil
}

// 读取私钥文件,解析出私钥对象
func ReadParsePrivaterKey(filename string) (*rsa.PrivateKey, error) {
	// 1、读取私钥文件,获取私钥字节
	privateKeyBytes, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, err
	}
	// 2、对私钥文件进行编码,生成加密块对象
	block, _ := pem.Decode(privateKeyBytes)
	fmt.Println(block.Type)
	if block == nil {
		return nil, errors.New("私钥信息错误!")
	}
	// 3、解析DER编码的私钥,生成私钥对象
	prkI, err := x509.ParsePKCS8PrivateKey(block.Bytes)
	if err != nil {
		return nil, err
	}
	privateKey := prkI.(*rsa.PrivateKey)

	return privateKey, nil
}

// GetNoticeURL is 获取回调地址
func GetNoticeURL(sourceCode uint8) string {

	domainName := setting.Conf.PayUrl.DomainName //todo
	return domainName + "/api/v1/pay/wx_notice" //目前微信、支付宝调同一个地址
}

//InsertPayBill is 插入 支付订单表中
func InsertPayBill(tx *sql.Tx, p *models.PlaceAnOrderParamInput, orderID string) (int64, error) {

	var billID int64

	insertSQL := `insert system_pay_bill set platform_type = ?, platform_info = ?,
source_code = ?, payment_order_code = ?, paymoney = ?*1000, commodity_describe = ?,
commodity_detail = ?, attach = ?, notify_pay_url = ?, pay_type = ?, is_serve = ?`

	result, err := tx.Exec(insertSQL, p.PlatformType, p.PlatformInfo, p.SourceCode,
		orderID, p.GoodsPrice, p.GoodsDes, p.GoodsDetail, p.AttachInfo, p.NoticeURL, p.PayType, p.IsServe)
	if err != nil {
		return billID, err
	}

	billID, err = result.LastInsertId()
	if err != nil {
		return billID, err
	}
	return billID, nil
}

// InsertPayBillDetailRequestBody is 插入支付订单详情表中的 下单参数字段 request_body
func InsertPayBillDetailRequestBody(tx *sql.Tx, billID int64, requestBody interface{}) error {

	body, err := json.Marshal(requestBody)
	if err != nil {
		return err
	}
	insertPayBillDetailSQL := `insert system_pay_bill_detail set pay_bill_id = ?, request_body = ?`
	result, err := tx.Exec(insertPayBillDetailSQL, billID, string(body))
	if err != nil {
		return err
	}

	_, err = result.LastInsertId()
	if err != nil {
		return err
	}
	return nil
}

// InsertPayBillDetailResponseBody is 插入支付订单详情表中的 下单参数字段 response_body
func InsertPayBillDetailResponseBody(tx *sql.Tx, billID int64, responseBody interface{}) error {

	body, err := json.Marshal(responseBody)
	if err != nil {
		return err
	}
	insertPayBillDetailSQL := `update system_pay_bill_detail set response_body = ? where pay_bill_id = ?`
	result, err := tx.Exec(insertPayBillDetailSQL, string(body), billID)
	if err != nil {
		return err
	}

	_, err = result.RowsAffected()
	if err != nil {
		return err
	}
	return nil
}

//func InsertPayBillDetailResponseBodyString(tx *sql.Tx, billID int64, responseBody string) error {
//
//	insertPayBillDetailSQL := `update system_pay_bill_detail set response_body = ? where pay_bill_id = ?`
//	result, err := tx.Exec(insertPayBillDetailSQL, responseBody, billID)
//	if err != nil {
//		return err
//	}
//
//	_, err = result.RowsAffected()
//	if err != nil {
//		return err
//	}
//	return nil
//}

func GetUID() string {
	u4 := uID.NewV4()
	//if err != nil {
	//	return ""
	//}

	id := fmt.Sprintf("%s", u4)
	return strings.Replace(id, "-", "", -1)
}



// 拉卡拉退款
func UnifiedRefund(input *models.RefundParamInput, ip string) (interface{}, error) {
	fmt.Println("谛宝多多输入参数(退款)")
	fmt.Println(input)

	refundID := GetUID()

	// 插入数据库
	db, err := mysql.NewPayConn()
	if err != nil {
		return 0, err
	}

	tx, err := db.Begin()
	if err != nil {
		return nil, err
	}

	defer mysql.CloseTx(tx, err)

	//退款订单存在check
	log_no, trans_term_no, source_code, platform_type, err := selectRefundBill(tx, input)
	if err != nil {
		return nil, err
	}

	billID, err := InsertRefundBill(tx, input, refundID)
	if err != nil {
		return nil, err
	}

	//数据重组 - start
	now := time.Now()
	now.Add(time.Minute * 60)
	date_time1 := now.Format("20060102150405")

	var version, out_org_code, merchant_no1, merchant_no2, merchant_no3, term_no3, merchant_no4, term_no4 string

	//平台类型 1:saas 2:shop 3:shop mobile 4:收银台 6:bk_shop 7:bk_shop_mobile
	if platform_type==2 || platform_type==3 {
		// 谛宝多多自营
		version = setting.Conf.Lakala.DbcVersion
		out_org_code = setting.Conf.Lakala.DbcAppid
		merchant_no1 = setting.Conf.Lakala.DbcMerchantNo1
		merchant_no2 = setting.Conf.Lakala.DbcMerchantNo2
		merchant_no3 = setting.Conf.Lakala.DbcMerchantNo3
		term_no3 = setting.Conf.Lakala.DbcTermNo3
		merchant_no4 = setting.Conf.Lakala.DbcMerchantNo4
		term_no4 = setting.Conf.Lakala.DbcTermNo4
	} else if platform_type==6 || platform_type==7 {
		// 必康自营
		version = setting.Conf.Lakala.BkVersion
		out_org_code = setting.Conf.Lakala.BkAppid
		merchant_no1 = setting.Conf.Lakala.BkMerchantNo1
		merchant_no2 = setting.Conf.Lakala.BkMerchantNo2
		merchant_no3 = setting.Conf.Lakala.BkMerchantNo3
		term_no3 = setting.Conf.Lakala.BkTermNo3
		merchant_no4 = setting.Conf.Lakala.BkMerchantNo4
		term_no4 = setting.Conf.Lakala.BkTermNo4
	} else {
		// 必康医生
		version = setting.Conf.Lakala.SaasVersion
		out_org_code = setting.Conf.Lakala.SaasAppid
		merchant_no1 = setting.Conf.Lakala.SaasMerchantNo1
		merchant_no2 = setting.Conf.Lakala.SaasMerchantNo2
		merchant_no3 = setting.Conf.Lakala.SaasMerchantNo3
		term_no3 = setting.Conf.Lakala.SaasTermNo3
		merchant_no4 = setting.Conf.Lakala.SaasMerchantNo4
		term_no4 = setting.Conf.Lakala.SaasTermNo4
	}

	var url string
	data := make(map[string]interface{})

	//url = "https://test.wsmsd.cn/sit/api/v3/labs/relation/refund" //聚合扫码(退款交易)
	url = setting.Conf.Lakala.UrlRefund //聚合扫码(退款交易)

	data["req_time"] = date_time1
	data["version"] = version
	data["out_org_code"] = out_org_code

	data2 := make(map[string]interface{})

	//source_code 1: 微信 Native 2:微信小程序 3:微信内支付 4:h5 跳微信
	//5:支付宝(web)-扫码或登录支付宝账户 6:alipay(mobile) 7:alipay(app)
	//9: B2C 10:bk支付宝web 11:bk 支付宝手机
	if source_code==4 || source_code==6 ||source_code==1 || source_code==5 || source_code==15 {
		//聚合收银台(微信H5、支付宝H5、微信扫码、支付宝扫码)
		//data2["merchant_no"] = "8221210701101SB"
		//data2["merchant_no"] = "8222900581201QB"
		if source_code==4 || source_code==6 || source_code==15 {
			data2["merchant_no"] = merchant_no1 //微信H5、支付宝H5、快捷支付(银行卡)
		} else {
			data2["merchant_no"] = merchant_no2 //微信扫码、支付宝扫码
		}
		//收银台支付时,没有传「term_no」,所以需要取得支付返回值的「trans_term_no」
		data2["term_no"] = trans_term_no

	} else if source_code==2 || source_code==3 {
		//聚合主扫(微信JSAPI、微信小程序)
		//data2["merchant_no"] = "8222900701107M5"
		//data2["term_no"] = "A1062976"
		//data2["merchant_no"] = "8221210701101SB"
		data2["merchant_no"] = merchant_no3
		data2["term_no"] = term_no3

	} else if source_code==9 {
		//扫码枪
		data2["merchant_no"] = merchant_no4
		data2["term_no"] = term_no4

	} else {
		return nil, errors.New("「source_code」错误,有效值为[1-6,9]")
	}

	data2["out_trade_no"] = refundID //随机生成的订单号 //商户交易流水号
	//data2["out_trade_no"] = RandomString(32)
	//扫码支付授权码,设备读取用户APP中的条码或者二维码信息,用户付款码条形码规则见说明
	//data2["auth_code"] = "135178236713755038"
	//data2["auth_code"] = input.DynamicID
	data2["refund_amount"] = input.RefundAmount*100 //退款金额
	data2["refund_reason"] = input.RefundReason //退款原因

	//input.OrderId = "2023070566210308960791"
	//data2["origin_out_trade_no"] = input.OrderId //原商户交易流水号
	//data2["origin_trade_no"] = input.OrderId //原拉卡拉交易流水号
	//data2["origin_log_no"] = input.OrderId //原对账单流水号
	data2["origin_log_no"] = log_no //原对账单流水号

	data3 := make(map[string]interface{})
	//data3["request_ip"] = "10.176.1.192"
	data3["request_ip"] = ip
	//data3["location"] = "+37.123456789,-121.123456789"
	data2["location_info"] = make(map[string]interface{})
	data2["location_info"] = data3

	data["req_data"] = make(map[string]interface{})
	data["req_data"] = data2

	//return nil, errors.New("输入参数「source_code」错误,有效值为[1-6,9]")

	//数据重组 - end
	fmt.Println("拉卡拉输入参数(退款)")
	fmt.Println(data)
	fmt.Println("拉卡拉接口url(退款)")
	fmt.Println(url)

	// 插入退款请求参数
	err = InsertPayBillDetailRequestBody(tx, billID, data)
	if err != nil {
		return nil, err
	}

	data_json, err := json.Marshal(data)
	if err != nil {
		//this.Data["json"] = utils.CheckError(errors.New("Map转化为byte数组失败"),"异常")
		//this.ServeJSON()
		return nil, err
	}

	//调拉卡拉接口
	err, _, lakala_rtn := lakala_post(nil, url, data_json)
	if err != nil {
		InsertPayBillDetailResponseBody(tx, billID, lakala_rtn)
		return nil, err
	}

	// 插入退款成功后返回的参数
	err = InsertPayBillDetailResponseBody(tx, billID, lakala_rtn)
	if err != nil {
		//beego.Error("退款请求成功 --- 但退款成功后的参数失败")
		return nil, err
	}

	response := make(map[string]string)
	response["payment_order_code"] = refundID
	return response, nil
}

//退款订单存在check
func selectRefundBill(tx *sql.Tx, input *models.RefundParamInput) (string, string, uint8, uint8, error) {

	var billID int64
	var status uint
	var platform_type uint8
	var source_code uint8
	var notice_request models.WxNoticeInput
	var notice_request2 []byte

	//payment_order_code, paymoney
	selectRefundBillSQL := `select b.id, b.result_code, b.source_code, b.platform_type, bd.notice_request_body 
		from system_pay_bill b
		left join system_pay_bill_detail bd on b.id=bd.pay_bill_id
		where b._type=0 and b.payment_order_code=?`
	err := tx.QueryRow(selectRefundBillSQL, input.RefundNo).Scan(&billID, &status, &source_code, &platform_type, &notice_request2)
	if err != nil {
		return "", "", 0, 0, err
	}
	if err := json.Unmarshal(notice_request2, &notice_request); err != nil {
		return "", "", 0, 0, err
	}

	//fmt.Println(notice_request2)
	//fmt.Println(notice_request)

	// 订单不存在
	if billID <= 0 {
		return "", "", 0, 0, errors.New("订单不存在2")
	}

	// 订单未结算
	if status != 1 {
		return "", "", 0, 0, errors.New("订单未结算")
	}

	if source_code==0 {
		return "", "", 0, 0, errors.New("「source_code」错误,有效值为[1-6,9,15,16]")
	}

	// 获取「对账单流水号」和「交易终端号」,退款用
	// 针对有的支付,不需要传「交易终端号」时,需要用支付返回的「交易终端号」进行退款
	log_no := notice_request.OrderTradeInfo.(map[string]interface{})["log_no"].(string)
	if log_no=="" {
		return "", "", 0, 0, errors.New("「对账单流水号」未取得错误")
	}
	if notice_request.TransTermNo=="" {
		//todo
		return "", "", 0, 0, errors.New("「交易终端号」未取得错误")
	}

	return log_no, notice_request.TransTermNo, source_code, platform_type, nil
}

//InsertRefundBill is 插入 支付订单表中
func InsertRefundBill(tx *sql.Tx, p *models.RefundParamInput, refundID string) (int64, error) {

	var billID int64
	//todo 原source
	//insertSQL := `insert system_pay_bill set platform_type = ?, source_code = ?,
	//payment_order_code = ?, paymoney = ?*1000, pay_type = 4, attach = ?, _type = 1, original_payment_order_code = ?`

	//platformType, sourceCode, checkSn, refundAmount, attach, orderID
	//result, err := tx.Exec(insertSQL, p.PlatformType, p.PlatformInfo, p.SourceCode,
	//	orderID, p.GoodsPrice, p.GoodsDes, p.GoodsDetail, p.AttachInfo, p.NoticeURL, p.PayType, p.IsServe)

	insertSQL := `insert system_pay_bill set original_payment_order_code=?, payment_order_code=?, paymoney=?*1000, _type=1`

	//差 platformType, sourceCode, attach 和 pay_type = 4
	result, err := tx.Exec(insertSQL, p.RefundNo, refundID, p.RefundAmount)
	if err != nil {
		return billID, err
	}

	billID, err = result.LastInsertId()
	if err != nil {
		return billID, err
	}

	return billID, nil
}