You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
11 KiB
251 lines
11 KiB
|
1 year ago
|
package bfpay
|
||
|
|
|
||
|
|
import (
|
||
|
|
"encoding/json"
|
||
|
|
"net/url"
|
||
|
|
"server/util"
|
||
|
|
|
||
|
|
"github.com/liangdas/mqant/log"
|
||
|
|
)
|
||
|
|
|
||
|
|
const (
|
||
|
|
baseURL = "https://brl.bf-pay.com"
|
||
|
|
payURL = "/gateway/api/commPay"
|
||
|
|
withdrawURL = "/df/gateway/proxyrequest"
|
||
|
|
mid = "2000611000770152"
|
||
|
|
key = "afca030583d24e6faceceed3cddff3c9"
|
||
|
|
)
|
||
|
|
|
||
|
|
var privateKeyPkCs8 = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||
|
|
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAJ5hQDWLXdURqCIc
|
||
|
|
Er3ID1D/ovQw2K+UaXP4vJ5t8d56gzFitOeCx92Qeu4wO8rINH599AZyiO3HuQM+
|
||
|
|
P7ueBqJyDmv/vOAOld+PwiTk42DVHlEj/h9kuGXV8vZfsU6BhgNGlq9bsSn0olbM
|
||
|
|
kz2WX8Qw2CRnGbMZvYK73yEl83E1AgMBAAECgYA+9p6WKs+k0x4qYUq6E/yy0M4x
|
||
|
|
kfGy66d4qVwjB8ZuEfpx+bG9j+pxFO0qIBbFKQ5lcyE+Ju50yT+uIGMp7UrpTYuX
|
||
|
|
aU55OVFrUaLAt/XeyaKcOSPB9xK+ObRnKUrZ92FN/PU/tHkaRjFxPaNiZGqwbBcQ
|
||
|
|
RdtcHpo/ZkooRvbWyQJBAM/tLpvLIwnC6Gi8JhGunSDwZFxbLyLW/S3x4b6S0IaC
|
||
|
|
Uor/AsplshWs8VQ0L0edyShnyYcFpxw4t5oP0RtHCaMCQQDC/30hiwPJMfRZ/6oF
|
||
|
|
ljV4nyN47rQssHG2EYo/HfL7tZn+URlcZ5oSSoM2Qe6cmzg4Vaoo+CRWwKbjsh/n
|
||
|
|
d3dHAkA2uAV/DHuBEyEUhwdBugEx7PGMeJa0BX4FfFVbUMm9zEgquiei2hZ+q8+q
|
||
|
|
yDz1DOomTwHzHaK3w5lV2vm9wvkfAkA7or1XI9e9kWyElb8exEiIIktL8dziiffM
|
||
|
|
0eJw2Sz1tB1rfMv/yaOCEo28az+ZX5M7D1/h9bnPWk3v9wrw1EWDAkBZNzIZ47TS
|
||
|
|
Mj9ipSQDsSklZYPGquqlRsjRm7OcDZXC7zW6qs3mTPPuISRuMVhmFr3Lz3YMT1o/
|
||
|
|
S0Agrn9Dq3fM
|
||
|
|
-----END RSA PRIVATE KEY-----`)
|
||
|
|
|
||
|
|
// var privateKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||
|
|
// MIICXgIBAAKBgQDgIesHgi+Qj0kkhwvJdGzt/QZDYR8VFzDxVgt5KdA8Ec1WCrhv
|
||
|
|
// GrmIEF2aKaqnPesv4/xn/0cLrXizYnF7wbgy/rrSzDmbWKEB6GZZc8Xz9iTxqoDT
|
||
|
|
// 2TpZclSUwKjeicdnw35PDGdBKKCbfLJeg9pXMs/L9VnY/QtDp03a3760owIDAQAB
|
||
|
|
// AoGBANQkZoA54elzJej0Bd0NXNk5x8bY04Gz7LhRGBT71cQ1mWQaS42l/vvheack
|
||
|
|
// TwlzGvu+UDbjMgzEid1IjV908XFVAnmJQxFxsHJt3HUz9qK5caXtqzwqP7Vt0Bl/
|
||
|
|
// Nt7wXhn1xq9gljLRuVV9+MoaF6punFuksqp4Qh/AAZ/zGVcJAkEA/ITUGawSY+AX
|
||
|
|
// Gz1uAYadEnkA/Ce1rk/uL5OCSHxIvBLL3DmFp68E7+NTwyf2ilsnB0jtqOgBqrZ8
|
||
|
|
// KoVfUjsxtwJBAOM46RGxijUhcDEoIZYUE+M+ugWskekdpwq4W9y1sNFULUjdXkwn
|
||
|
|
// UKeSlwTis8zFCw8mkZDOgNQzRsd0eFjm5HUCQQCt2MipD/TtO7bMsyML++Ahepr5
|
||
|
|
// /mCvLCpAKN62BpKQoKQm7pcclXrhqHDfV6D9KboZ4tRzx552KAIdyAqS81vLAkB7
|
||
|
|
// CVLy+L7MvDmC9KcTG/YU499YuTQdFahg3qknXt7Kypjmzq+D7vn2cyMBSzxu0feG
|
||
|
|
// Ea1ayubpgIZ/9CpCgWwNAkEA+f/5Ilnb3Dn9fRhGAuhttUIA9+vec3BH6rKc9oW/
|
||
|
|
// JvLtLxuSpfg2D2D74nsZd48OVk+BJ0DqVeMb7sw6zjzH9A==
|
||
|
|
// -----END RSA PRIVATE KEY-----`)
|
||
|
|
var publicKey = []byte(`-----BEGIN PUBLIC KEY-----
|
||
|
|
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrTw3IoR3Q6oRukb6q0LR6dc/GRXVh0ngRPZzRsq87j6817v4HNjfsf2gYkefWK3AcEGyZT7uqji1C0drDfVy82HE68hYjmxgyXQO2YRjNZkYNHNPHD9EO4y5fr4qQsSMCYA1a7fgWqbqZiGPQgCSUvrpbFbJh53QxOWqpkrKoowIDAQAB-----END PUBLIC KEY-----`)
|
||
|
|
var myPublicKey = []byte(`-----BEGIN PUBLIC KEY-----
|
||
|
|
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCeYUA1i13VEagiHBK9yA9Q/6L0
|
||
|
|
MNivlGlz+LyebfHeeoMxYrTngsfdkHruMDvKyDR+ffQGcojtx7kDPj+7ngaicg5r
|
||
|
|
/7zgDpXfj8Ik5ONg1R5RI/4fZLhl1fL2X7FOgYYDRpavW7Ep9KJWzJM9ll/EMNgk
|
||
|
|
ZxmzGb2Cu98hJfNxNQIDAQAB
|
||
|
|
-----END PUBLIC KEY-----`)
|
||
|
|
|
||
|
|
// Head represents the header of the request
|
||
|
|
type Head struct {
|
||
|
|
MchtId string `json:"mchtId"` // 商户编号,不参与签名
|
||
|
|
Version string `json:"version"` // 固定值“20”,不参与签名
|
||
|
|
Biz string `json:"biz"` // 固定值,支付方式,不参与签名
|
||
|
|
}
|
||
|
|
|
||
|
|
// Body represents the body of the request
|
||
|
|
type Body struct {
|
||
|
|
OrderId string `json:"orderId"` // 订单号
|
||
|
|
OrderTime string `json:"orderTime"` // 订单时间yyyyMMddHHmmss
|
||
|
|
Amount string `json:"amount"` // 总金额,以分为单位
|
||
|
|
CurrencyType string `json:"currencyType"` // 货币种类,三位字母代码
|
||
|
|
Goods string `json:"goods"` // 商品名称(不要带中文元素)
|
||
|
|
NotifyUrl string `json:"notifyUrl"` // 接收推送通知的URL
|
||
|
|
CallBackUrl string `json:"callBackUrl"` // 网页回调地址
|
||
|
|
Desc string `json:"desc,omitempty"` // 商品描述,logo地址
|
||
|
|
AppId string `json:"appId,omitempty"` // 产品标识
|
||
|
|
AppName string `json:"appName,omitempty"` // 产品名称
|
||
|
|
Operator string `json:"operator,omitempty"` // 印度UPI支付,用户的VPA账号
|
||
|
|
ExpireTime string `json:"expireTime,omitempty"` // 订单超时时间yyyyMMddHHmmss
|
||
|
|
IP string `json:"ip,omitempty"` // 请求IP地址
|
||
|
|
Param string `json:"param,omitempty"` // 保留字段
|
||
|
|
UserId string `json:"userId,omitempty"` // 要求:小于32位
|
||
|
|
Phone string `json:"phone,omitempty"` // 手机号(币种是BRL,USDT,THB,PHP,USD,此参数可不传)
|
||
|
|
Name string `json:"name,omitempty"` // 姓名(币种是BRL,USDT,THB,PHP,USD,此参数可不传)
|
||
|
|
Email string `json:"email,omitempty"` // 邮箱(币种是BRL,USDT,THB,PHP,USD,此参数可不传)
|
||
|
|
}
|
||
|
|
|
||
|
|
type PayReq struct {
|
||
|
|
Head Head `json:"head"`
|
||
|
|
Body Body `json:"body"`
|
||
|
|
Sign string `json:"sign"` // 签名信息
|
||
|
|
}
|
||
|
|
|
||
|
|
type PayResp struct {
|
||
|
|
Head struct {
|
||
|
|
RespCode string `json:"respCode"` // 返回Code
|
||
|
|
RespMsg string `json:"respMsg"` // 返回信息
|
||
|
|
} `json:"head"` // 响应报文头
|
||
|
|
Body struct {
|
||
|
|
MchtId string `json:"mchtId"` // 商户ID
|
||
|
|
OrderId string `json:"orderId"` // 商户订单号
|
||
|
|
PayUrl string `json:"payUrl"` // 支付URL地址
|
||
|
|
TradeId string `json:"tradeId,omitempty"` // 支付平台返回的交易流水号
|
||
|
|
Param string `json:"param,omitempty"` // 保留字段
|
||
|
|
} `json:"body,omitempty"` // 响应报文体, 在respCode为"0000"时返回
|
||
|
|
Sign string `json:"sign"` // 签名信息
|
||
|
|
}
|
||
|
|
|
||
|
|
type PayCallbackReq struct {
|
||
|
|
Head struct {
|
||
|
|
RespCode string `json:"respCode"` // 返回Code
|
||
|
|
RespMsg string `json:"respMsg"` // 返回信息
|
||
|
|
} `json:"head"` // 响应报文头
|
||
|
|
Body struct {
|
||
|
|
Amount string `json:"amount"` // 金额
|
||
|
|
Biz string `json:"biz"` // 业务类型
|
||
|
|
ChargeTime string `json:"chargeTime"` // 充值时间
|
||
|
|
MchtId string `json:"mchtId"` // 商户ID
|
||
|
|
OrderId string `json:"orderId"` // 商户订单号
|
||
|
|
Seq string `json:"seq"` // 序号
|
||
|
|
Status string `json:"status"` // 状态
|
||
|
|
TradeId string `json:"tradeId"` // 交易流水号
|
||
|
|
PayType string `json:"payType"` // 支付类型
|
||
|
|
} `json:"body"` // 响应报文体
|
||
|
|
Sign string `json:"sign"` // 签名信息
|
||
|
|
}
|
||
|
|
|
||
|
|
type WithdrawReq struct {
|
||
|
|
Head Head `json:"head"`
|
||
|
|
Body string `json:"body"`
|
||
|
|
}
|
||
|
|
|
||
|
|
type WithdrawBody struct {
|
||
|
|
BatchOrderNo string `json:"batchOrderNo"` // 商户代付批次号,值唯一
|
||
|
|
TotalNum int `json:"totalNum"` // 商户代付笔数,与detail代付明细集合数一致
|
||
|
|
TotalAmount string `json:"totalAmount"` // 商户代付总金额,单位:分,为detail代付明细集合中金额总和
|
||
|
|
NotifyUrl string `json:"notifyUrl,omitempty"` // 异步通知地址
|
||
|
|
Detail []Detail `json:"detail"` // 代付订单明细,Json数组格式
|
||
|
|
// AppId string `json:"appId,omitempty"` // 产品Id
|
||
|
|
CurrencyType string `json:"currencyType"` // 币种BRL
|
||
|
|
}
|
||
|
|
|
||
|
|
type Detail struct {
|
||
|
|
Seq string `json:"seq"` // 序号,商户自定义
|
||
|
|
Amount string `json:"amount"` // 金额,单位:分
|
||
|
|
AccType string `json:"accType"` // 固定值 0
|
||
|
|
CertType string `json:"certType"` // PIX账号类型或银行卡代付固定值
|
||
|
|
CertId string `json:"certId"` // PIX账号或银行卡相关值
|
||
|
|
// BankCardNo string `json:"bankCardNo,omitempty"` // 收款人的CPF或CNPJ(PIX代付必填)
|
||
|
|
BankCardName string `json:"bankCardName"` // 收款用户姓名
|
||
|
|
// BankCode string `json:"bankCode,omitempty"` // 银行编码(银行卡代付时必传)
|
||
|
|
// Mobile string `json:"mobile,omitempty"` // 银行账户绑定的手机号码
|
||
|
|
// Email string `json:"email,omitempty"` // 邮箱
|
||
|
|
// BankCardType string `json:"bankCardType,omitempty"` // 银行卡类型,1:借记卡2:信用卡
|
||
|
|
// CreditValid string `json:"creditValid,omitempty"` // 信用卡有效期,MMyy(信用卡时必填)
|
||
|
|
// CreditCvv string `json:"creditCvv,omitempty"` // 卡背面后3位数字(信用卡时必填)
|
||
|
|
// BankProvince string `json:"bankProvince,omitempty"` // 开户行所属省份
|
||
|
|
// BankCity string `json:"bankCity,omitempty"` // 开户行所属市
|
||
|
|
// BankLineCode string `json:"bankLineCode,omitempty"` // 联行号
|
||
|
|
// BankName string `json:"bankName,omitempty"` // 银行名称
|
||
|
|
// Remark string `json:"remark,omitempty"` // 备注
|
||
|
|
// FirstName string `json:"firstName,omitempty"` // 收款人名
|
||
|
|
// LastName string `json:"lastName,omitempty"` // 收款人姓
|
||
|
|
// CardYear string `json:"cardYear,omitempty"` // 卡年份
|
||
|
|
// CardMonth string `json:"cardMonth,omitempty"` // 卡月份
|
||
|
|
}
|
||
|
|
|
||
|
|
type WithdrawResp struct {
|
||
|
|
Head struct {
|
||
|
|
RespCode string `json:"respCode"` // 返回Code
|
||
|
|
} `json:"head"` // 响应报文头
|
||
|
|
Body string `json:"body,omitempty"` // 响应报文体,以字符串表示
|
||
|
|
Sign string `json:"sign,omitempty"` // 签名信息,假设存在时
|
||
|
|
}
|
||
|
|
|
||
|
|
type WithdrawRespBody struct {
|
||
|
|
Status string `json:"status"` // 订单受理状态
|
||
|
|
TradeId string `json:"tradeId"` // 平台批次号
|
||
|
|
BatchOrderNo string `json:"batchOrderNo"` // 商户批次号
|
||
|
|
MchtId string `json:"mchtId"` // 商户编号
|
||
|
|
Desc string `json:"desc,omitempty"` // 描述, 可选字段
|
||
|
|
}
|
||
|
|
|
||
|
|
type WithdrawCallbackReq struct {
|
||
|
|
Head struct {
|
||
|
|
RespCode string `json:"respCode"` // 返回Code
|
||
|
|
RespMsg string `json:"respMsg"` // 返回信息
|
||
|
|
} `json:"head"` // 响应报文头
|
||
|
|
Body string `json:"body,omitempty"` // 响应报文体,以字符串表示
|
||
|
|
Sign string `json:"sign,omitempty"` // 签名信息,假设存在时
|
||
|
|
}
|
||
|
|
|
||
|
|
type WithdrawCallbackBody struct {
|
||
|
|
BatchOrderNo string `json:"batchOrderNo"` // 商户批次号
|
||
|
|
TradeId string `json:"tradeId"` // 平台批次号
|
||
|
|
TotalNum string `json:"totalNum"` // 代付笔数
|
||
|
|
TotalAmount string `json:"totalAmount"` // 代付总金额
|
||
|
|
Status string `json:"status"` // 状态
|
||
|
|
Desc string `json:"desc,omitempty"` // 结果描述,可选字段
|
||
|
|
Detail []WithdrawCallbackDetail `json:"detail"` // 代付明细订单详情
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
type WithdrawCallbackDetail struct {
|
||
|
|
DetailId string `json:"detailId"` // 平台明细号
|
||
|
|
Seq string `json:"seq"` // 序号
|
||
|
|
Amount string `json:"amount"` // 金额 单位:分
|
||
|
|
Status string `json:"status"` // 状态
|
||
|
|
Desc string `json:"desc,omitempty"` // 结果描述
|
||
|
|
FinishTime string `json:"finishTime,omitempty"` // 代付完成时间(币种时间)格式: yyyyMMddHHmmss
|
||
|
|
}
|
||
|
|
|
||
|
|
func Decode(str string, ret interface{}) error {
|
||
|
|
str2, err := url.QueryUnescape(str)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
res, err := util.NewXRsa(publicKey, privateKeyPkCs8)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
tmp, err := res.PrivateDecrypt(str2)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
err = json.Unmarshal([]byte(tmp), ret)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func Encode(str string) string {
|
||
|
|
res, err := util.NewXRsa(publicKey, privateKeyPkCs8)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return ""
|
||
|
|
}
|
||
|
|
tmp, err := res.PublicEncrypt(str)
|
||
|
|
if err != nil {
|
||
|
|
log.Error("err:%v", err)
|
||
|
|
return ""
|
||
|
|
}
|
||
|
|
return url.QueryEscape(tmp)
|
||
|
|
}
|