印度包网
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

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)
}