|
@@ -29,15 +29,17 @@ type AliPayStruct struct {
|
|
|
Appid string
|
|
|
PrivateKey *rsa.PrivateKey //请求接口秘钥
|
|
|
AliPublicKey *rsa.PublicKey //支付完成回调,校验使用(取支付宝后台)
|
|
|
- Qr_width int //二维码宽度
|
|
|
- CallBackUrl string //支付完成回调地址
|
|
|
- ReturnUrl string //支付完成页面跳转地址
|
|
|
Requseturl string //接口请求地址
|
|
|
Subject string //支付小标题
|
|
|
+
|
|
|
+ PC_Qr_width int //PC扫码二维码宽度
|
|
|
+ PC_CallBackUrl string //pc扫码支付完成回调地址
|
|
|
+
|
|
|
+ APP_CallBackUrl string //app支付完成回调地址
|
|
|
}
|
|
|
|
|
|
-//支付订单生成请求参数(扫码支付)
|
|
|
-type BizContent struct {
|
|
|
+//扫码支付订单生成请求参数
|
|
|
+type BizPcContent struct {
|
|
|
Subject string `json:"subject"`
|
|
|
OutTradeNo string `json:"out_trade_no"`
|
|
|
TotalAmount float64 `json:"total_amount"`
|
|
@@ -47,14 +49,18 @@ type BizContent struct {
|
|
|
Time_expire string `json:"time_expire"` //支付超时时间yyyy-MM-dd HH:mm:ss
|
|
|
}
|
|
|
|
|
|
-//支付订单关闭请求参数
|
|
|
+//App支付订单生成请求参数
|
|
|
+type BizAppContent struct {
|
|
|
+ Subject string `json:"subject"`
|
|
|
+ OutTradeNo string `json:"out_trade_no"`
|
|
|
+ TotalAmount float64 `json:"total_amount"`
|
|
|
+ ProductCode string `json:"product_code"`
|
|
|
+}
|
|
|
+
|
|
|
+//扫码支付订单关闭结构体
|
|
|
type CloseContent struct {
|
|
|
OutTradeNo string `json:"out_trade_no"`
|
|
|
}
|
|
|
-type AliPayAction struct {
|
|
|
- *xweb.Action
|
|
|
- payCallback xweb.Mapper `xweb:"/alipay/pay/callback"` //微信支付回调
|
|
|
-}
|
|
|
|
|
|
var Alipay *AliPayStruct
|
|
|
var alipayConf map[string]interface{}
|
|
@@ -75,43 +81,49 @@ func init() {
|
|
|
Appid: util.ObjToString(alipayConf["appid"]),
|
|
|
PrivateKey: privateKey,
|
|
|
AliPublicKey: aliPublicKey,
|
|
|
- CallBackUrl: util.ObjToString(config.Sysconfig["webdomain"]) + "/alipay/pay/callback",
|
|
|
- Qr_width: 250,
|
|
|
- ReturnUrl: "", //不配置
|
|
|
Requseturl: util.ObjToString(alipayConf["reqUrl"]),
|
|
|
Subject: util.ObjToString(alipayConf["Subject"]),
|
|
|
+ //pc扫码参数
|
|
|
+ PC_CallBackUrl: util.ObjToString(config.Sysconfig["webdomain"]) + "/alipay/pay/callback",
|
|
|
+ PC_Qr_width: 250,
|
|
|
+ //app支付参数
|
|
|
+ APP_CallBackUrl: util.ObjToString(config.Sysconfig["webdomain"]) + "/app/alipay/pay/callback",
|
|
|
+ }
|
|
|
+
|
|
|
+ //注册路由
|
|
|
+ if alipayConf["isApp"] == "T" {
|
|
|
+ xweb.AddAction(&AliAppPayAction{})
|
|
|
+ } else {
|
|
|
+ xweb.AddAction(&AliPcPayAction{})
|
|
|
}
|
|
|
- xweb.AddAction(&AliPayAction{})
|
|
|
+
|
|
|
}
|
|
|
|
|
|
func (w *AliPayStruct) GetTradeno() string {
|
|
|
return fmt.Sprintf("%s_%d%s%s", "z", time.Now().UnixNano(), util.GetRandom(5), util.GetLetterRandom(6))
|
|
|
}
|
|
|
|
|
|
-//获取支付连接
|
|
|
+//pc扫码获取支付二维码地址
|
|
|
func (a *AliPayStruct) GetPayUrl(order_money float64, time_expire string) (string, string, error) {
|
|
|
tradeno := a.GetTradeno()
|
|
|
- bizContent := BizContent{
|
|
|
+ bizPcContent := BizPcContent{
|
|
|
Subject: a.Subject,
|
|
|
OutTradeNo: tradeno,
|
|
|
TotalAmount: order_money / 100,
|
|
|
ProductCode: "FAST_INSTANT_TRADE_PAY",
|
|
|
Qr_pay_mode: "4",
|
|
|
- Qrcode_width: a.Qr_width,
|
|
|
+ Qrcode_width: a.PC_Qr_width,
|
|
|
Time_expire: time_expire,
|
|
|
}
|
|
|
- bizbyte, err := json.Marshal(bizContent)
|
|
|
+ bizbyte, err := json.Marshal(bizPcContent)
|
|
|
if err != nil {
|
|
|
return "", "", err
|
|
|
}
|
|
|
var data = url.Values{}
|
|
|
data.Add("app_id", Alipay.Appid)
|
|
|
data.Add("method", "alipay.trade.page.pay")
|
|
|
- if a.CallBackUrl != "" {
|
|
|
- data.Add("notify_url", a.CallBackUrl) //支付完成回调地址
|
|
|
- }
|
|
|
- if a.ReturnUrl != "" {
|
|
|
- data.Add("return_url", a.ReturnUrl)
|
|
|
+ if a.PC_CallBackUrl != "" {
|
|
|
+ data.Add("notify_url", a.PC_CallBackUrl) //支付完成回调地址
|
|
|
}
|
|
|
data.Add("format", "json")
|
|
|
data.Add("charset", "UTF-8")
|
|
@@ -129,6 +141,41 @@ func (a *AliPayStruct) GetPayUrl(order_money float64, time_expire string) (strin
|
|
|
return a.Requseturl + "?" + data.Encode(), tradeno, nil
|
|
|
}
|
|
|
|
|
|
+//app支付获取支付token
|
|
|
+func (a *AliPayStruct) GetAliPayToken(order_money float64) (string, string, error) {
|
|
|
+ tradeno := a.GetTradeno()
|
|
|
+ bizAppContent := BizAppContent{
|
|
|
+ Subject: a.Subject,
|
|
|
+ OutTradeNo: tradeno,
|
|
|
+ TotalAmount: order_money / 100,
|
|
|
+ ProductCode: "QUICK_MSECURITY_PAY",
|
|
|
+ }
|
|
|
+ bizbyte, err := json.Marshal(bizAppContent)
|
|
|
+ if err != nil {
|
|
|
+ return "", "", err
|
|
|
+ }
|
|
|
+ var data = url.Values{}
|
|
|
+ data.Add("app_id", Alipay.Appid)
|
|
|
+ data.Add("method", "alipay.trade.app.pay")
|
|
|
+ if a.APP_CallBackUrl != "" {
|
|
|
+ data.Add("notify_url", a.APP_CallBackUrl) //支付完成回调地址
|
|
|
+ }
|
|
|
+ data.Add("format", "json")
|
|
|
+ data.Add("charset", "UTF-8")
|
|
|
+ data.Add("sign_type", "RSA2")
|
|
|
+ data.Add("timestamp", time.Now().Format("2006-01-02 15:04:05"))
|
|
|
+ data.Add("version", "1.0")
|
|
|
+ data.Add("biz_content", string(bizbyte))
|
|
|
+
|
|
|
+ signContentBytes, _ := url.QueryUnescape(data.Encode())
|
|
|
+ signature, err := a.getSign([]byte(signContentBytes))
|
|
|
+ if err != nil {
|
|
|
+ return "", "", err
|
|
|
+ }
|
|
|
+ data.Add("sign", signature)
|
|
|
+ return data.Encode(), tradeno, nil
|
|
|
+}
|
|
|
+
|
|
|
//加载秘钥
|
|
|
func parsePrivateKey(key string) (*rsa.PrivateKey, error) {
|
|
|
block, _ := pem.Decode([]byte(key))
|
|
@@ -200,9 +247,82 @@ func (a *AliPayStruct) checkCallBackSign(param, sign string) bool {
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
-//支付宝支付回调
|
|
|
-func (a *AliPayAction) PayCallback() {
|
|
|
- checkSign := a.GetForm()
|
|
|
+//支付宝关闭订单(生成的订单二维码,未扫码无法关闭订单)
|
|
|
+func (a *AliPayStruct) CloseOrder(tradeno string) bool {
|
|
|
+ toClose := CloseContent{
|
|
|
+ OutTradeNo: tradeno,
|
|
|
+ }
|
|
|
+ bizbyte, err := json.Marshal(toClose)
|
|
|
+ if err != nil {
|
|
|
+ log.Println()
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ var data = url.Values{}
|
|
|
+ data.Add("app_id", Alipay.Appid)
|
|
|
+ data.Add("method", "alipay.trade.close")
|
|
|
+ data.Add("format", "json")
|
|
|
+ data.Add("charset", "UTF-8")
|
|
|
+ data.Add("sign_type", "RSA2")
|
|
|
+ data.Add("timestamp", time.Now().Format("2006-01-02 15:04:05"))
|
|
|
+ data.Add("version", "1.0")
|
|
|
+ data.Add("biz_content", string(bizbyte))
|
|
|
+ signContentBytes, _ := url.QueryUnescape(data.Encode())
|
|
|
+ log.Println(signContentBytes)
|
|
|
+ signature, err := a.getSign([]byte(signContentBytes))
|
|
|
+ if err != nil {
|
|
|
+ log.Println(tradeno, "获取签名出错", err)
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ data.Add("sign", signature)
|
|
|
+
|
|
|
+ url := a.Requseturl + "?" + data.Encode()
|
|
|
+ //clien 优化
|
|
|
+ client := http.Client{Jar: nil}
|
|
|
+ req, _ := http.NewRequest("POST", url, nil)
|
|
|
+ res, err := client.Do(req)
|
|
|
+ if err != nil {
|
|
|
+ log.Printf("%s支付宝关闭订单 请求出错%v\n", tradeno, err)
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ bArr, err := ioutil.ReadAll(res.Body)
|
|
|
+ if err != nil {
|
|
|
+ log.Printf("%s支付宝关闭订单 读取相应出错%v\n", tradeno, err)
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ m := map[string]interface{}{}
|
|
|
+ err = json.Unmarshal(bArr, &m)
|
|
|
+ if err != nil {
|
|
|
+ log.Println(string(bArr))
|
|
|
+ log.Println("%s支付宝关闭订单 解析相应参数出错%v\n", tradeno, err)
|
|
|
+ }
|
|
|
+ msg := (*util.ObjToMap(m["alipay_trade_close_response"]))["sub_msg"]
|
|
|
+ log.Printf("%s msg:%s 订单关闭相应参数 %+v", tradeno, msg, m)
|
|
|
+ if msg == "交易状态不合法" || msg == "REASON_ILLEGAL_STATUS" { //已支付
|
|
|
+ return false
|
|
|
+ }
|
|
|
+ return true
|
|
|
+}
|
|
|
+
|
|
|
+//pc支付回调地址
|
|
|
+type AliPcPayAction struct {
|
|
|
+ *xweb.Action
|
|
|
+ payCallback xweb.Mapper `xweb:"/alipay/pay/callback"`
|
|
|
+}
|
|
|
+
|
|
|
+//app支付回调地址
|
|
|
+type AliAppPayAction struct {
|
|
|
+ *xweb.Action
|
|
|
+ payCallback xweb.Mapper `xweb:"/app/alipay/pay/callback"`
|
|
|
+}
|
|
|
+
|
|
|
+func (a *AliPcPayAction) PayCallback() {
|
|
|
+ PayCallbackDetail(a.Request)
|
|
|
+}
|
|
|
+func (a *AliAppPayAction) PayCallback() {
|
|
|
+ PayCallbackDetail(a.Request)
|
|
|
+}
|
|
|
+func PayCallbackDetail(a *http.Request) {
|
|
|
+ checkSign := a.Form
|
|
|
sign := checkSign.Get("sign") //待验证签名
|
|
|
checkSign.Del("sign")
|
|
|
checkSign.Del("sign_type")
|
|
@@ -275,59 +395,3 @@ func (a *AliPayAction) PayCallback() {
|
|
|
log.Println("insertAliPay", insertAliPay)
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
-//支付宝关闭订单(生成的订单二维码,未扫码无法关闭订单)
|
|
|
-func (a *AliPayStruct) CloseOrder(tradeno string) bool {
|
|
|
- toClose := CloseContent{
|
|
|
- OutTradeNo: tradeno,
|
|
|
- }
|
|
|
- bizbyte, err := json.Marshal(toClose)
|
|
|
- if err != nil {
|
|
|
- log.Println()
|
|
|
- return false
|
|
|
- }
|
|
|
- var data = url.Values{}
|
|
|
- data.Add("app_id", Alipay.Appid)
|
|
|
- data.Add("method", "alipay.trade.close")
|
|
|
- data.Add("format", "json")
|
|
|
- data.Add("charset", "UTF-8")
|
|
|
- data.Add("sign_type", "RSA2")
|
|
|
- data.Add("timestamp", time.Now().Format("2006-01-02 15:04:05"))
|
|
|
- data.Add("version", "1.0")
|
|
|
- data.Add("biz_content", string(bizbyte))
|
|
|
- signContentBytes, _ := url.QueryUnescape(data.Encode())
|
|
|
- log.Println(signContentBytes)
|
|
|
- signature, err := a.getSign([]byte(signContentBytes))
|
|
|
- if err != nil {
|
|
|
- log.Println(tradeno, "获取签名出错", err)
|
|
|
- return false
|
|
|
- }
|
|
|
- data.Add("sign", signature)
|
|
|
-
|
|
|
- url := a.Requseturl + "?" + data.Encode()
|
|
|
- //clien 优化
|
|
|
- client := http.Client{Jar: nil}
|
|
|
- req, _ := http.NewRequest("POST", url, nil)
|
|
|
- res, err := client.Do(req)
|
|
|
- if err != nil {
|
|
|
- log.Printf("%s支付宝关闭订单 请求出错%v\n", tradeno, err)
|
|
|
- return false
|
|
|
- }
|
|
|
- bArr, err := ioutil.ReadAll(res.Body)
|
|
|
- if err != nil {
|
|
|
- log.Printf("%s支付宝关闭订单 读取相应出错%v\n", tradeno, err)
|
|
|
- return false
|
|
|
- }
|
|
|
- m := map[string]interface{}{}
|
|
|
- err = json.Unmarshal(bArr, &m)
|
|
|
- if err != nil {
|
|
|
- log.Println(string(bArr))
|
|
|
- log.Println("%s支付宝关闭订单 解析相应参数出错%v\n", tradeno, err)
|
|
|
- }
|
|
|
- msg := (*util.ObjToMap(m["alipay_trade_close_response"]))["sub_msg"]
|
|
|
- log.Printf("%s msg:%s 订单关闭相应参数 %+v", tradeno, msg, m)
|
|
|
- if msg == "交易状态不合法" || msg == "REASON_ILLEGAL_STATUS" { //已支付
|
|
|
- return false
|
|
|
- }
|
|
|
- return true
|
|
|
-}
|