一、前置条件

(1)go语言,1.18

(2)Gin第三方依赖包:gopay【github.com/gopay/gopay/alipay】https://github.com/go-pay/gopay/blob/main/doc/wechat_v3.md

(3)支付宝支付相关信息appID ,支付宝用户私钥支付宝公钥小程序需要拉起支付宝APP,不能使用沙盒账号小程序文档 – 支付宝文档中心

(4)外网访问域名用于支付成功回调本地开发自测的话,搞个内网穿透工具我用的花生壳,花了6块钱买了个域名【当时搞活动买1年,送98年】

(5)基于域名创建映射

(6)启动本地服务验证映射是否成功 

 准备工作完成,开始编码!!

二、支付客户端代码:aliPayClient 

(1)保证单列,用gosync.Once实现,具体代码如下

package lib

import (
	"github.com/go-pay/gopay/alipay"
	"log"
	. "go_online_pay/config"
	"sync"
)

var aliPayClient *alipay.Client

var syOnce sync.Once

//GetAliPayClient aliPayClient
func GetAliPayClient() *alipay.Client {
	var err error
	syOnce.Do(func() {
		cf := Conf{}
		config := cf.GetConf()
		aliPayClient, err = alipay.NewClient(config.AliPayAppId, config.AliPayPrivateKey, config.AliPayIsProd)
		if err != nil {
			log.Panic(err.Error())
		}
		//配置公共参数
		aliPayClient.SetCharset("utf-8").
			SetSignType(alipay.RSA2).
			SetNotifyUrl("")

	})
	return aliPayClient
}

(2)基础配置信息,都放到conf.yaml文件内了,同时配套conf.go文件mian.go启动加载conf.ymal配置内容,后续通过conf.Xx获取属性值【config.AliPayAppId】,根据自己项目的实际情况,放置支付宝相关配置信息

#--------------支付宝支付测试账号(可真实支付)----------------
#是否生产账号
alipay_is_prod: true
#支付宝-APPID
alipay_app_id: 
#支付宝-用户私钥
alipay_private_key: 
#支付宝公钥
alipay_public_key:
#支付宝支付回调地址
alipay_notify_url: https://XXX/alipayNotify

三、支付服务代码:AlipayService

(1)代码中含有:面对面(收款码链接),小程序支付,查询支付结果,退款,查询退款结果

package service

import (
	"context"
	"fmt"
	"github.com/go-pay/gopay"
	"github.com/go-pay/gopay/alipay"
	"go_online_pay/config"
	"go_online_pay/lib"
)

type AlipayService struct {
}

//TradePreCreate 当面付 扫码支付,获取二维码
func (AlipayService) TradePreCreate(bm gopay.BodyMap) string {
	client := lib.GetAliPayClient()
	client.SetNotifyUrl(config.GetConfLib().AliPayNotifyUrl)
	//统一收单线下交易创建
	payParam, err := client.TradePrecreate(context.Background(), bm)
	if err != nil {
		fmt.Println(fmt.Sprintf("-----aliPay TradePreCreate()-------error:%s", err.Error()))
		return ""
	}
	return payParam.Response.QrCode
}

//TradeCreate 统一收单交易创建接口
func (AlipayService) TradeCreate(bm gopay.BodyMap) (*alipay.TradeCreateResponse, error) {
	client := lib.GetAliPayClient()
	//统一收单线下交易创建
	payParam, err := client.TradeCreate(context.Background(), bm)
	if err != nil {
		fmt.Println(fmt.Sprintf("-----aliPay TradeCreate()-------error:%s", err.Error()))
		return nil, err
	}
	return payParam, nil
}

//Refund 退款接口
func (AlipayService) Refund(bm gopay.BodyMap) *alipay.TradeRefundResponse {
	client := lib.GetAliPayClient()
	//统一收单线下交易创建
	payParam, err := client.TradeRefund(context.Background(), bm)
	if err != nil {
		fmt.Println(fmt.Sprintf("-----aliPay Refund()-------error:%s", err.Error()))
		return nil
	}
	//接口返回fund_change=Y为退款成功,fund_change=N或无此字段返回时需通过退款查询接口一步确认退款状态
	return payParam
}

//QueryRefund 查询退款接口
func (AlipayService) QueryRefund(orderNo, refundNo string) (*alipay.TradeFastpayRefundQueryResponse, error) {
	client := lib.GetAliPayClient()
	//统一收单线下交易创建
	bm := make(gopay.BodyMap)
	//商户订单号
	bm.Set("out_trade_no", orderNo)
	//退款请求号
	bm.Set("out_request_no", refundNo)
	payParam, err := client.TradeFastPayRefundQuery(context.Background(), bm)
	if err != nil {
		fmt.Println(fmt.Sprintf("-----aliPay QueryRefund()-------error:%s", err.Error()))
	}
	//接口返回fund_change=Y为退款成功,fund_change=N或无此字段值返回时需通过退款查询接口进一步确认退款状态
	return payParam, err
}

//TradeQuery 交易查询接口
func (AlipayService) TradeQuery(orderNo string) *alipay.TradeQueryResponse {
	client := lib.GetAliPayClient()
	//请求参数
	bm := make(gopay.BodyMap)
	bm.Set("out_trade_no", orderNo)
	//统一收单线下交易创建
	payParam, err := client.TradeQuery(context.Background(), bm)
	if err != nil {
		fmt.Println(fmt.Sprintf("-----aliPay TradeQuery(%s)-------error:%s", orderNo, err.Error()))
		return nil
	}
	return payParam
}

四、具体方法使用

(1)小程序支付部分代码

    //第三方30分钟过期
	expire := time.Now().Add(30 * 60 * time.Second).Format(time.RFC3339)
	description := util.ExtractStrByLen(orderInfo.CommodityName, 40)

		//请求参数
		bm := make(gopay.BodyMap)
		bm.Set("notify_url", config.GlobalConf.AliPayNotifyUrl)
		bm.Set("subject", description).
			//买家支付宝用户ID
			Set("buyer_id", openId).
			//商户订单号。由商家自定义
			Set("out_trade_no", payNo).
			//元,小数点两位,去掉千分位
			Set("total_amount", strings.Replace(payAmount, ",", "", -1))
		//统一收单线下交易创建
		payParam, errAli := AlipayService{}.TradeCreate(bm)
		if errAli != nil {
			fmt.Println(fmt.Sprintf("-----aliPay TradeCreate() 返回值  ---errString -> %s", errAli.Error()))
			errMap := util.JsonToMap(errAli.Error())
			if val, ok := errMap["code"]; ok {
				result["errorMsg"] = "拉起支付宝支付失败:" + val.(string)
				return e.ERROR, result
			}
		}
		if payParam == nil || len(payParam.Response.TradeNo) == 0 {
			result["errorMsg"] = "拉起支付宝支付失败:无AliPrepayId"
			return e.ERROR, result
		}
		result["ali_prepay_Id"] = payParam.Response.TradeNo

前端拿到ali_prepay_Id后,通过sdk拉起支付宝APP

(2) 其他方法,都可以仿照小程序入参方式,根据支付宝接口文档填写相应的key即可

(3)支付回调方法代码:回调后写入队列异步处理

//AlipayNotify 解析支付宝支付异步通知参数到BodyMap
func AlipayNotify(c *gin.Context) {
	logger.Info("---------------------AlipayNotify START -------------")
	// c.Request 是 gin 框架写法
	notifyReq, err := alipay.ParseNotifyToBodyMap(c.Request)
	if err != nil {
		logger.Info("------AlipayNotify ERR -------------,err:", err.Error())
		return
	}
	logger.Info("-----AlipayNotify notifyReq: ", notifyReq)

	ok, err := alipay.VerifySign(config.GlobalConf.AliPayPublicKey, notifyReq)
	if ok {
		if notifyReq["receipt_amount"] == nil {
			logger.Info("------ AlipayNotify 支付宝退款回调,忽略 -------------")
		} else {
			//验签成功
			var alReq = make(map[string]interface{})
			//商户订单号:商户系统内部订单号
			alReq["pay_no"] = notifyReq["out_trade_no"]
			alReq["trade_no"] = notifyReq["trade_no"]
			//与支付宝同步
			alReq["trade_status"] = notifyReq["trade_status"]
			alReq["notify_time"] = notifyReq["notify_time"]
			//订单金额。本次交易支付的订单金额,单位为人民币(元)
			totalAmountF, _ := strconv.ParseFloat(notifyReq["total_amount"].(string), 64)
			totalAmount := int(totalAmountF * 100)
			//实收金额。商家交易中实际收到的款项,单位为人民币(元)。
			receiptAmountF, _ := strconv.ParseFloat(notifyReq["receipt_amount"].(string), 64)
			receiptAmount := int(receiptAmountF * 100)
			alReq["total_amount"] = totalAmount
			alReq["receipt_amount"] = receiptAmount

			var mapData = make(map[string]interface{})
			mapData["data_type"] = "PayNotify"
			mapData["param"] = map[string]interface{}{"payType": "aliPay", "notifyReq": alReq}
			reqJson, _ := json.Marshal(mapData)
			lib.PushMessToPayQueue(reqJson)
		}

	}

	/*	notifyReq["order_no"] = "订单号"
		notifyReq["trade_no"] = "2022061322001402060501532448"
		notifyReq["trade_status"] = "TRADE_SUCCESS"
		notifyReq["notify_time"] = "2022-06-13 10:09:36"
		notifyReq["total_amount"] = 202000
		notifyReq["receipt_amount"] = 200000
		var mapData = make(map[string]interface{})
		mapData["data_type"] = "PayNotify"
		mapData["param"] = map[string]interface{}{"payType": "aliPay", "notifyReq": notifyReq}
		reqJson, _ := json.Marshal(mapData)
		lib.PushMessToPayQueue(reqJson)*/

	// 此写法gin 框架返回支付宝的写法
	c.String(http.StatusOK, "%s", "success")
	logger.Info("---------------------AlipayNotify END -------------")
	return
}

原文地址:https://blog.csdn.net/One_Rabbit2016/article/details/131571091

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_17221.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注