订单支付后的处理【使用github.com/smartwalle/alipay/v3包】

使用gin修改订单状态,处理超时未支付…

初始化客户端

func InitAlipay() {
//使用配置信息获取
	global.AliClient, err = alipay.New(global.ServerConfig.Alipay.Appid, global.ServerConfig.Alipay.PrivateKey, false)
	if err != nil {
		zap.S().Info("实例化支付宝失败", err)
		return
	}
	err = global.AliClient.LoadAliPayPublicKey(global.ServerConfig.Alipay.PublicKey)
	if err != nil {
		zap.S().Info("载入支付宝公钥失败", err)
		return
	}
}

生成支付链接


func GenerateAlipayUrl(c *gin.Context) {

	order_sn := c.PostForm("order_sn")

	if len(order_sn) == 0 {
		api.ReturnErrorJson(c, err)
		return
	}

	//根据订单编号进行查询订单详情
	detail, err := global.OrderClient.OrderDetail(c, &orderPb.OrderReq{
		OrderSn: order_sn,
	})

	if err != nil {
		api.HandleGrpcErrorToHttp(c, err)
		return
	}
	var p = alipay.TradeWapPay{}
	total := strconv.FormatFloat(float64(detail.OrderInfo.Total), 'f', 2, 64)
	p.NotifyURL = "http://6a6d884f.r20.cpolar.top/o/v1/alipay/notify" //异步回调地址  是我们用来更改订单信息的  需要内网穿透
	p.ReturnURL = "http://192.168.1.114:8891/o/v1/alipay/return"      //同步回调地址  用来展示给用户的界面 一般是订单详情
	p.Subject = "生鲜" + detail.OrderInfo.OrderSn
	p.OutTradeNo = detail.OrderInfo.OrderSn
	p.TotalAmount = total
	p.ProductCode = "QUICK_WAP_WAY"

	url, err := global.AliClient.TradeWapPay(p)
	if err != nil {
		fmt.Println(err)
	}

	// 这个 payURL 即是用于打开支付宝支付页面的 URL,可将输出的内容复制,到浏览器中访问该 URL 即可打开支付页面。
	var payURL = url.String()
	c.JSON(http.StatusOK, gin.H{
		"code":    0,
		"message": "生成支付链接",
		"data": map[string]string{
			"pay_url": payURL,
		},
	})
}

同步回调

// ReturnUrl 同步回调
func ReturnUrl(c *gin.Context) {
	//通过订单编号查询订单详情
	out_trade_no := c.Query("out_trade_no")
	if len(out_trade_no) == 0 {
		c.JSON(http.StatusOK, gin.H{
			"code":    0,
			"message": "订单号不能为空",
		})

		return
	}

	detail, err := global.OrderClient.OrderDetail(c, &orderPb.OrderReq{
		OrderSn: out_trade_no,
	})
	if err != nil {
		api.HandleGrpcErrorToHttp(c, err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"code":    0,
		"message": "订单详情",
		"data":    detail,
	})
}

异步回调

//NotifyUrl 使用rocketMQ实现异步回调

func NotifyUrl(c *gin.Context) {
	trade_no := c.PostForm("trade_no")
	trade_status := c.PostForm("trade_status")
	out_trade_no := c.PostForm("out_trade_no")

	//除了交易成功 还有几种状态  如交易关闭  等待交易  交易完成

	// 定义订单信息变量
	var orderInfo model.OrderInfo

	// 根据交易状态设置订单信息
	//1(待支付),2(成功),3(超时关闭),4(交易失败),5(交易结束)
	switch trade_status {
	case "TRADE_SUCCESS":
		//交易成功
		orderInfo.Status = 2

	case "TRADE_PAY_FAIL":
		//交易失败
		orderInfo.Status = 4

	case "TRADE_CLOSED":
		//交易关闭
		orderInfo.Status = 3

	case "WAIT_BUYER_PAY":
		//等待买家付款
		orderInfo.Status = 1

	case "TRADE_FINISHED":
		//交易结束 不可退款
		orderInfo.Status = 5

	default:
		// 可以根据需要处理其他交易状态
		zap.S().Info("未处理交易状态: " + trade_status)
		c.String(http.StatusBadRequest, "未处理交易状态")
		return
	}
	//1代表支付类型是支付宝
	order := model.OrderInfo{
		PayType: 1,
		Status:  orderInfo.Status,
		TradeNo: trade_no,
		OrderSn: out_trade_no,
	}
	// 序列化订单信息
	msg, err := json.Marshal(order)
	if err != nil {
		zap.S().Info("序列化失败: " + err.Error())
		c.String(http.StatusInternalServerError, "序列化失败")
		return
	}

	// 将修改订单放到异步队列里面,使用唯一的队列键

	RocketMqProducer(msg)

	c.String(http.StatusOK, "success")
}

RocketMQ生产者

func RocketMqProducer(msgs []byte) {

	intn := rand.Intn(100)
	name := GenerateOrderSn(int32(intn))

	p, err := rocketmq.NewProducer(
		producer.WithGroupName(name),
		producer.WithNameServer([]string{fmt.Sprintf("%s:%d", global.ServerConfig.Rocketmq.Host, global.ServerConfig.Rocketmq.Port)}),
	)
	if err != nil {
		zap.S().Info("生产者失败", err)
		return
	}

	err = p.Start()
	if err != nil {
		fmt.Printf("start producer error: %s", err.Error())
		os.Exit(1)
	}

	msg := &primitive.Message{
		Topic: "alipay",
		Body:  msgs,
	}
	_, err = p.SendSync(context.Background(), msg)

	if err != nil {
		zap.S().Info("支付发送消息失败", err)
		return
	}

}

RocketMq消费者

func RocketMqConsumer() {
	// 创建消费者

	c, err := rocketmq.NewPushConsumer(

		consumer.WithGroupName("testGroup1"),

		consumer.WithNsResolver(primitive.NewPassthroughResolver([]string{"192.168.1.114:9876"})),

		consumer.WithRetry(2),
	)

	//如果订阅的主题不存在,进行每2秒重试一次,直至订阅成功为止

	if err != nil {

		zap.S().Info("初始化消费者失败", err)

		return
	}

	// 订阅主题`delay_order`,并设置回调函数
	err = c.Subscribe("alipay", consumer.MessageSelector{}, UpdateOrder)

	if err != nil {

		zap.S().Info("delay_order_consumer error", err.Error())

		return
	}

	err = c.Start()

	if err != nil {

		zap.S().Info("delay_order_consumer error", err.Error())

		return
	}
}

更改订单状态

func UpdateOrder(ctx context.Context, messages ...*primitive.MessageExt) (consumer.ConsumeResult, error) {

	//把messages的信息反解到订单结构体

	for _, msg := range messages {
		var orderInfo model.OrderInfo
		//将延迟队列里的消息反解到orderInfo结构体
		err := json.Unmarshal(msg.Body, &orderInfo)
		if err != nil {
			zap.S().Info("反序列化失败")
			return 0, err
		}

		now := time.Now().Format(time.DateTime)
		// 更新订单状态
		_, err = global.OrderClient.UpdateOrder(context.Background(), &orderPb.UpdateOrderInfo{
			PayType: orderInfo.PayType,
			Status:  orderInfo.Status,
			TradeNo: orderInfo.TradeNo,
			OrderSn: orderInfo.OrderSn,
			PayTime: now,
		})

		if err != nil {
			zap.S().Info("订单更新失败: " + err.Error())
			return consumer.ConsumeRetryLater, nil
		}

		log.Println("修改订单状态成功")
	}

	return consumer.ConsumeSuccess, nil
}

退款

// Refund 支付宝退款
// 退款之前要查询订单信息  如果是交易状态是交易完成  就不能进行退款
func Refund(c *gin.Context) {

	// 从请求中获取退款参数,例如:outTradeNo(商户订单号), refundAmount(退款金额)等
	outTradeNo := c.PostForm("trade_no")
	refundAmount := c.PostForm("refund_amount")
	refundReason := c.PostForm("refund_reason")
	tradeNo := c.PostForm("trade_no")

	if len(outTradeNo) == 0 || len(refundAmount) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{
			"code": -1,
			"msg":  "参数不能为空",
		})
		return
	}

	//查询订单状态

	detail, err := global.OrderClient.OrderDetail(c, &orderPb.OrderReq{
		OrderSn: outTradeNo,
	})
	if err != nil {
		api.HandleGrpcErrorToHttp(c, err)
		return
	}
	//1(待支付),2(成功),3(超时关闭),4(交易创建),5(交易结束)
	if detail.OrderInfo.Status == 5 {
		//代表交易结束 不能够退款
		c.JSON(http.StatusOK, gin.H{
			"code": 0,
			"msg":  "交易已完成,无法退款",
		})
		return
	} else if detail.OrderInfo.Status == 1 {
		//代表交易创建  也不能退款
		c.JSON(http.StatusOK, gin.H{
			"code": 0,
			"msg":  "订单未支付  无法退款",
		})
		return
	}
	//查询退款记录表
	//1 未退款 2 已退款 3 无法退款

	// 创建退款请求
	req := alipay.TradeRefund{
		OutTradeNo:   outTradeNo,
		TradeNo:      tradeNo,
		RefundAmount: refundAmount,
		RefundReason: refundReason,
	}

	// 发起退款请求
	resp, err := global.AliClient.TradeRefund(c, req)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": "退款失败", "message": err.Error()})
		return
	}

	// 检查退款结果
	if resp.IsSuccess() {
		c.JSON(http.StatusOK, gin.H{"success": "退款成功"})
	} else {
		c.JSON(http.StatusOK, gin.H{"error": "退款失败", "message": resp.Msg + ": " + resp.SubMsg})
	}

}

日常更新中,有问题可留言…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值