You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

226 lines
5.9 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package api
import (
"bytes"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"github.com/smartwalle/alipay/v3"
"io"
"jypay/errors"
"jypay/global"
"jypay/model"
"jypay/request"
"jypay/utils"
"log"
"net/http"
"strconv"
"time"
)
func Index(c *gin.Context) (utils.Data, error) {
return utils.Data{"hello": "elf"}, nil
}
func Error(c *gin.Context) (utils.Data, error) {
return nil, errors.NewBusinessError("测试", "1122")
}
func Pay(c *gin.Context) (utils.Data, error) {
req := request.OrderRequest{}
err := c.BindJSON(&req)
if err != nil {
fmt.Printf("bind json err:%v", err)
return nil, errors.NewBusinessError("参数错误")
}
order, err := saveOrder(req)
if err != nil {
return nil, err
}
var param = alipay.TradeWapPay{}
param.OutTradeNo = order.OrderNo
param.TotalAmount = strconv.FormatFloat(order.PayAmount, 'E', -1, 64)
param.Subject = order.Subject
// global.Config.Server.Domain
param.NotifyURL = global.Config.Server.Domain + "/notify"
param.ReturnURL = global.Config.Server.Domain + "/return"
client, err := alipay.New(global.Config.Alipay.AppId, global.Config.Alipay.PrivateKey, true)
if err != nil {
return nil, errors.NewBusinessError("初始化支付宝失败")
}
result, err := client.TradeWapPay(param)
if err != nil {
return nil, errors.NewBusinessError("请求支付宝失败:" + err.Error())
}
fmt.Println(result.String())
order.PayUrl = result.String()
// utils.Md5(order.OrderNo + strconv.Itoa(order.UserId) + strconv.FormatInt(time.Now().Unix(), 10))
order.Token = order.OrderNo
global.DB.Save(order)
data := utils.Data{
"pay_url": global.Config.Server.Domain + "/payment/" + order.OrderNo,
}
return data, nil
}
func saveOrder(req request.OrderRequest) (*model.Order, error) {
if req.OrderNo == "" {
return nil, errors.NewBusinessError("订单号[orderNo]不能为空")
}
order := model.Order{}
global.DB.Where("order_no = ?", req.OrderNo).First(&order)
order.OrderNo = req.OrderNo
order.UserId = req.UserId
order.UserAccount = req.UserAccount
order.GameId = req.GameId
order.GameName = req.GameName
order.ServerId = req.ServerId
order.ServerName = req.ServerName
order.Subject = req.Subject
order.RoleId = req.RoleId
order.RoleName = req.RoleName
order.PayAmount = float64(req.PayAmount) / 100
order.NotifyUrl = req.NotifyUrl
order.ReturnUrl = req.ReturnUrl
order.PromoteId = req.PromoteId
order.PromoteAccount = req.PromoteAccount
order.PayStatus = 0
result := global.DB.Create(&order)
if result.Error != nil {
return nil, errors.NewBusinessError("数据异常")
}
return &order, nil
}
func Notify(c *gin.Context) {
err := c.Request.ParseForm()
if err != nil {
log.Printf("参数错误:%v", err)
return
}
client, err := alipay.New(global.Config.Alipay.AppId, global.Config.Alipay.PrivateKey, true)
if err != nil {
log.Printf("初始化支付宝失败:%v", err)
return
}
notification, err := client.DecodeNotification(c.Request.Form)
if err != nil {
log.Printf("解析异步通知发生错误:%v", err)
return
}
order := model.Order{}
tx := global.DB.Where("order_no = ?", notification.OutTradeNo).First(&order)
if tx.Error != nil {
log.Printf("订单不存在:%s", notification.OutTradeNo)
return
}
now := time.Now()
if notification.TradeStatus == "TRADE_SUCCESS" || notification.TradeStatus == "TRADE_FINISHED" {
order.PayStatus = 1
order.PayTime = &now
tx := global.DB.Save(order)
if tx.Error != nil {
log.Printf("更新订单失败:%s", notification.OutTradeNo)
return
}
}
notifyData := make(map[string]interface{})
notifyData["trade_no"] = notification.TradeNo
notifyData["out_trade_no"] = notification.OutTradeNo
notifyData["trade_status"] = notification.TradeStatus
notifyData["total_amount"] = notification.TotalAmount
notifyResult := postToSdk(order.NotifyUrl, notifyData)
if notifyResult == "success" {
client.ACKNotification(c.Writer)
}
}
func TestPost(c *gin.Context) (utils.Data, error) {
notifyData := make(map[string]interface{})
notifyData["trade_no"] = "112233"
notifyData["out_trade_no"] = "2222222"
notifyData["trade_status"] = "1"
notifyData["total_amount"] = "11.11"
notifyResult := postToSdk("https://api.jianghuifa.cn/callback.php/Notify/kd_callback", notifyData)
return utils.Data{"hello": notifyResult}, nil
}
func postToSdk(url string, data map[string]interface{}) string {
content, err := json.Marshal(data)
if err != nil {
log.Fatalf("无法编码JSON数据%v", err)
return "fail"
}
client := &http.Client{}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(content))
if err != nil {
log.Fatalf("无法创建新的请求:%v", err)
return "fail"
}
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
log.Fatalf("无法发送POST请求%v", err)
return "fail"
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatalf("无法读取响应体内容:%v", err)
return "fail"
}
return string(body)
}
func Return(c *gin.Context) {
var req request.ReturnRequest
// 将路由参数绑定到结构体中
if err := c.ShouldBindUri(&req); err != nil {
c.Writer.WriteHeader(http.StatusOK)
c.Writer.Write([]byte("参数错误"))
return
}
order := model.Order{}
tx := global.DB.Where("order_no = ?", req.OrderNo).First(&order)
if tx.Error != nil {
c.Writer.WriteHeader(http.StatusOK)
c.Writer.Write([]byte("订单不存在"))
return
}
c.Redirect(http.StatusFound, order.ReturnUrl)
}
func Payment(c *gin.Context) {
var req request.PaymentRequest
// 将路由参数绑定到结构体中
if err := c.ShouldBindUri(&req); err != nil {
c.Writer.WriteHeader(http.StatusOK)
c.Writer.Write([]byte("参数错误"))
return
}
order := model.Order{}
tx := global.DB.Where("token = ?", req.Token).First(&order)
if tx.Error != nil {
c.Writer.WriteHeader(http.StatusOK)
c.Writer.Write([]byte("订单不存在"))
return
}
c.Redirect(http.StatusFound, order.PayUrl)
}