参考
github.com/go-pay/gopa…
沙盒地址
open.alipay.com/develop/san…
代码示例
package main
import (
"context"
"fmt"
"github.com/go-pay/gopay"
"github.com/go-pay/gopay/alipay"
"github.com/shopspring/decimal"
"log"
"net/http"
"time"
)
const (
kAppId = "9021000145654333"
kPrivateKey = `MIIEowIBAAKCAQEAiOqxZvy9DJwQSSL6hYRiJL8MBL8qi5ubFjz/uPHvEblkeH2UICHtHA84rXMyfZopG032KIeaEcYHN6bmJQrOtd8ss+2B3SPVqoX8PzKF80Qp8bS0T/RQkVnljfCOZqDJEaTMZxg9DnRnshB3vuAoQYhQnHW9nrzlYX8oJbn/LImCjnF9PVNcsrMjXLPEuu5nAQq17eKd4bmdDoVwPU9scdyHn3By35uWzoztAHkLnd+wL2VUl/bYgRbWgqzo/J8EAc8iJZ8tnOxa875Uo08Y9aKJgilTvn29h+N5FonsDowECNz5aBkqaa5slzfEqoH68yLD8lN3f9IVTgFr3qscIwIDAQABAoIBACB3rwviAR6dX4tIXSoOQ4u9NidmAbvLcZJrcqSz0mJcmUOtW9Pm16hgv6r5904roXXVHftsdI+kaw+6Zzb/ghdEzf/44WPEXKWsUi3WWEdgsaWcmWmgYP6m17W6Brq1hBjIAKSt7cSgu/pQx2SfGUy4+4yuqwGaf7aIBcg0fBteP/hP+W3VAK5niRgizMke73jrmvhrHBjWDNadqvIHmuefwliGyPMdiJlWhDc3sLiEwBcD8nHbeDUO2ogLKUyT3ZyyfgrKmZdH66q7boM4BStZCOfzl5eEWgpkovUzyKpolxcHc3sKPgoN24TiAqqA9o4pF/SnSShMO3TbIjIkwLkCgYEA+Y1FAcPsA3gTmY859CWFZ+7Ahd/TYbCSuegdQSbLL/JWdapNWm+bOT2c6aWp49G6JaUDxauN3xans2GidjymvlOnGMv9BsMFQabbgMAyq8PZHIQ3mew/BG+wmOOkIEEwvOS6xQa+XuaKYJiDX3A6z0utZa+tcdsiK63iMor+L2cCgYEAjHReBQG9bPkPENVmoCOfUCbYpOktF2Sovu6wPfvv71p3S3Vj6DlWaAdCDcUPCXwIaF0llzIoAWVxIx1B1v1cPbLEWVHZCDKdkPI8ZsMhCE97xRqZKRM67NbKobRgTf+C4tzMbHHdXyJqaH4cdcHzvG3s9QE/nYK7FcU9y9APg+UCgYAoAyqpWcyh0cLywDA+oTV+sJ1V2cl+xF0CSeFG7P1vNp/+RcwZUAPHbcWXAOT4jkwWdRrhutwIhQ1miaUO6DKkGa2VID/1sZdKK4LOZgK537EUDW8M0wBXqcDbAsTyFwHFh7camDY16SkOy+VkjA4h5rRqtXxN4SDdeAfoqriOyQKBgEkLX7YU4JGiuT4U7WlM/VZuzW5+QdAPrl6VvZyOwIpnLvFUXJ/x6cjyNVz55ccV9T1pa9pE4F9RhVQwrAQGAYmoxcp58Xf88srl35nF0xECXSj1mz+sW5G+ZuVP7GHEByq6j6m6UdlfCZ3MMDrhokOVm40TmCTvTyKUUH4Fd3wtAoGBAIbfymY4QDM9seiSoOg9gSN85Ak1VbjQfwOId0JhcRN3GBq7GSyIrv+Lcs97+hkxa8DH+8fcapjwPBQcBsbKRfonasSILXm1y/N8ErlIjQjoaVJRAftRBHKcsQoTzo3R8erSyMbHiA98vNeSmP9KyRGBRDGjEsjVMh2Ye53KU3lZ`
kServerPort = "8005"
kServerDomain = "https://这里写你的服务地址/server"
pubKey = `MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkLCI+JgynJE6Nl2zH+8eXZLIsQiUBm+AgWHWv4Jc94k8jor7v7hc3yskVOOWcRfF2DpCBG/+S55VNOOnIVOK4aYfzuI3cYbnVr0ttgrPZ+2Zb3HbOW2O1i4P+wZQ14mcv2p/jbt2Jr+RgrTfaRQHq4HZUbZGAEmJVa0RSdJHuGXyFdq+KPOGcSy2BCPxrAQEBKhNJabmfsiPMe7VsJPxb577eFaDyDKvs1ymyETkKTSj9b9qLFYm3ZkPz6eHYLbmJofJRp19StaKLZBzFZt1BTE7CvnH+GTsPGjwXvtZ8mP5XdvNCNrrq7h6QKfXoBBoRMfjZHvK6P9NCXD932W6QQIDAQAB`
)
var client *AlipayService
func main() {
conf := Config{
Appid: kAppId,
MchId: "2088721060395791",
PrivateKey: kPrivateKey,
NotifyUrl: kServerDomain + "/alipay/notify",
RefundUrl: kServerDomain + "/alipay/refund",
ReturnUrl: kServerDomain + "/alipay/callback",
PublicKey: pubKey,
QuitUrl: "",
}
client = NewAlipayService(context.Background(), conf)
http.HandleFunc("/v1/server/alipay/pay", pay)
http.HandleFunc("/v1/server/alipay/refund", refund)
log.Println(`启动成功`)
http.ListenAndServe(":"+kServerPort, nil)
}
func pay(writer http.ResponseWriter, request *http.Request) {
var tradeNo = fmt.Sprintf("%d", time.Now().UnixNano())
tradeNoParam := request.URL.Query().Get("tradeNo")
if tradeNoParam != "" {
tradeNo = tradeNoParam
}
charge := &Charge{
MoneyFee: 1000,
TradeNum: tradeNo,
Describe: "测试",
}
url, err := client.PcPay(charge)
if err != nil {
writer.WriteHeader(http.StatusBadRequest)
writer.Write([]byte(fmt.Sprintf("订单 %s 创建失败", tradeNoParam)))
return
}
writer.WriteHeader(http.StatusOK)
writer.Write([]byte(url))
}
func refund(writer http.ResponseWriter, request *http.Request) {
refunds := &RefundCharge{
TradeNum: "1741690269602282000",
MoneyFee: 500,
OutRefundNo: "1",
RefundReason: "测试退款",
}
err := client.Refund(refunds)
if err != nil {
writer.WriteHeader(http.StatusBadRequest)
writer.Write([]byte(fmt.Sprintf("订单 %s 退款失败", refunds.OutRefundNo)))
return
}
writer.WriteHeader(http.StatusOK)
writer.Write([]byte(`success`))
}
type Config struct {
Appid string
MchId string
PrivateKey string
NotifyUrl string
RefundUrl string
ReturnUrl string
PublicKey string
QuitUrl string
}
type AlipayService struct {
ctx context.Context
config Config
alipay *alipay.Client
}
func NewAlipayService(ctx context.Context, config Config) *AlipayService {
alipayCli, err := alipay.NewClient(config.Appid, config.PrivateKey, false)
if err != nil {
panic(err)
}
alipayCli.DebugSwitch = gopay.DebugOn
alipayCli.SetCharset(alipay.UTF8).SetSignType(alipay.RSA2)
return &AlipayService{
ctx: ctx,
config: config,
alipay: alipayCli,
}
}
type Charge struct {
MoneyFee int64
TradeNum string
Describe string
}
func (a *AlipayService) PcPay(charge *Charge) (string, error) {
a.alipay = a.alipay.SetReturnUrl(a.config.ReturnUrl).SetNotifyUrl(a.config.NotifyUrl)
amount := decimal.NewFromInt(charge.MoneyFee).DivRound(decimal.NewFromInt(100), 2).String()
bm := make(gopay.BodyMap)
bm.Set("subject", charge.Describe).
Set("out_trade_no", charge.TradeNum).
Set("total_amount", amount).
Set("qr_pay_mode", 4).
Set("qrcode_width", 120)
return a.alipay.TradePagePay(a.ctx, bm)
}
type RefundCharge struct {
TradeNum string `json:"tradeNum,omitempty"`
MoneyFee int64 `json:"MoneyFee,omitempty"`
OutRefundNo string `json:"out_refund_no,omitempty"`
RefundReason string `json:"refund_reason,omitempty"`
}
func (a *AlipayService) Refund(charge *RefundCharge) error {
amount := decimal.NewFromInt(charge.MoneyFee).DivRound(decimal.NewFromInt(100), 2).String()
bm := make(gopay.BodyMap)
bm.Set("out_trade_no", charge.TradeNum).
Set("refund_reason", charge.RefundReason).
Set("out_request_no", charge.OutRefundNo).
Set("refund_amount", amount)
res, err := a.alipay.TradeRefund(a.ctx, bm)
log.Println(`TradeRefund:`, res, err)
return err
}
type AliWebPayResult struct {
OutTradeNo string `json:"out_trade_no"`
TradeStatus string `json:"trade_status"`
}
func (a *AlipayService) GetNotifyResult(r *http.Request) (result *AliWebPayResult, err error) {
notifyReq, err := alipay.ParseNotifyToBodyMap(r)
if err != nil {
return
}
_, err = alipay.VerifySign(a.config.PublicKey, notifyReq)
if err != nil {
return
}
if err = notifyReq.Unmarshal(result); err != nil {
return
}
return
}