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

268 lines
6.4 KiB

package alipay
import (
"errors"
"fmt"
"os"
"path/filepath"
"recook/internal/api/mobile/pay/public"
"recook/internal/back"
"recook/internal/dbc"
"recook/internal/domain"
"recook/internal/model/order"
"recook/internal/model/pay"
"recook/internal/service/comFunc"
"recook/tools"
"strconv"
"time"
"github.com/gin-gonic/gin"
"github.com/jinzhu/gorm"
"github.com/shopspring/decimal"
"github.com/smartwalle/alipay/v3"
)
type createH5AlipayReq struct {
UserID uint `json:"userId" validate:"required,numeric"`
OrderID uint `json:"orderId" validate:"required,numeric"`
}
func createH5Order(orderID uint, ip string, userID uint) (error, string) {
now := time.Now().Unix()
var od []order.Information
if err := dbc.DB.Find(&od, "virtual_id = ?", orderID).Error; err != nil {
return err, ""
}
if err := public.UpdateVirtualPay(orderID); err != nil {
return err, ""
}
amount := decimal.Zero
for _, v := range od {
if err := public.ValidateOrderInfo(&v, now); err != nil {
return err, ""
}
amount = amount.Add(v.ActualTotalAmount)
}
// 零支付
if amount.IsZero() {
return errors.New("接口调用错误"), ""
}
var detail pay.AlipayH5Detail
if err := dbc.DB.First(&detail, "order_id = ?", orderID).Error; err != nil && err != gorm.ErrRecordNotFound {
return err, ""
}
if detail.ID > 0 {
tx := dbc.DB.Begin()
{
for _, v := range od {
if v.PayMethod != order.AlipayH5ForOrderInfo {
if err := tx.Model(&v).Updates(order.Information{
PayIP: ip,
TradeNo: detail.TradeNo,
PayMethod: order.AlipayH5ForOrderInfo,
}).Error; err != nil {
tx.Rollback()
return err, ""
}
}
}
}
tx.Commit()
return nil, detail.CreateOrderSign
} else {
if url, tradeNo, err := genUrl(od[0].Title, userID, orderID, amount); err != nil {
return errors.New("失败"), ""
} else {
tx := dbc.DB.Begin()
{
for _, v := range od {
if err = dbc.DB.Model(&v).Updates(order.Information{
PayIP: ip,
TradeNo: tradeNo,
PayMethod: order.AlipayH5ForOrderInfo,
}).Error; err != nil {
tx.Rollback()
return err, ""
}
}
detail = pay.AlipayH5Detail{
OrderId: int64(orderID),
TradeNo: tradeNo,
CreateOrderSign: url,
}
if err = tx.Create(&detail).Error; err != nil {
tx.Rollback()
return err, ""
}
}
tx.Commit()
return nil, url
}
}
}
/**
逻辑处理从之前的app支付过来的
*/
func CreateH5Alipay(c *gin.Context) {
var p createH5AlipayReq
err := tools.ParseParams(&p, c)
if err != nil {
back.Fail(c, err.Error())
return
}
if !public.Judge(p.OrderID) {
if err, result := createH5Order(p.OrderID, c.ClientIP(), p.UserID); err != nil {
back.Err(c, err.Error())
return
} else {
back.Suc(c, "操作成功", gin.H{
"payUrl": result,
})
return
}
}
if err = public.UpdateNormalPay(p.OrderID); err != nil {
back.Err(c, err.Error())
return
}
now := time.Now().Unix()
var orderInfo order.Information
err = dbc.DB.First(&orderInfo, "id = ?", p.OrderID).Error
if err != nil {
back.Err(c, err.Error())
return
}
// 零支付
if orderInfo.ActualTotalAmount.Equal(decimal.NewFromFloat(0.0)) {
back.Fail(c, "接口调用错误")
return
}
err = public.ValidateOrderInfo(&orderInfo, now)
if err != nil {
back.Fail(c, err.Error())
return
}
var detail pay.AlipayH5Detail
err = dbc.DB.First(&detail, "order_id = ?", orderInfo.ID).Error
if err != nil && !gorm.IsRecordNotFoundError(err) {
back.Err(c, err.Error())
return
}
if detail.ID > 0 { // 如果生成过记录了
back.Suc(c, "", gin.H{
"payUrl": detail.CreateOrderSign,
})
if orderInfo.PayMethod != order.AlipayH5ForOrderInfo {
err = dbc.DB.Model(&orderInfo).Updates(order.Information{
PayIP: c.ClientIP(),
TradeNo: detail.TradeNo,
PayMethod: order.AlipayH5ForOrderInfo,
}).Error
if err != nil {
back.Err(c, err.Error())
return
}
}
} else {
if url, tradeNo, err := genUrl(orderInfo.Title, p.UserID, orderInfo.ID, orderInfo.ActualTotalAmount); err != nil {
back.Fail(c, "失败")
} else {
err = dbc.DB.Model(&orderInfo).Updates(order.Information{
PayIP: c.ClientIP(),
TradeNo: tradeNo,
PayMethod: order.AlipayH5ForOrderInfo,
}).Error
if err != nil {
back.Err(c, err.Error())
return
}
detail = pay.AlipayH5Detail{
OrderId: int64(orderInfo.ID),
TradeNo: tradeNo,
CreateOrderSign: url,
}
dbc.DB.Create(&detail)
back.Suc(c, "", gin.H{
"payUrl": url,
})
}
}
}
func genUrl(title string, userID uint, orderID uint, actualAmount decimal.Decimal) (string, string, error) {
var privateKey = RecookToAliPayPrivateKeyForTest
client, err := alipay.New(AppID0602, privateKey, true)
if err != nil {
errMsg := fmt.Sprintf("加载出现错误%s,", err)
comFunc.PrintErr(errMsg)
return "", "", err
}
dir, _ := os.Executable()
exPath := filepath.Dir(dir)
alipayH5Path := exPath + "/credentials/alipay_h5/"
err = client.LoadAppPublicCertFromFile(alipayH5Path + "appCertPublicKey_2021001152664931.crt") // 加载应用公钥证书
if err != nil {
panic(err)
}
err = client.LoadAliPayRootCertFromFile(alipayH5Path + "alipayRootCert.crt") // 加载支付宝根证书
if err != nil {
panic(err)
}
err = client.LoadAliPayPublicCertFromFile(alipayH5Path + "alipayCertPublicKey_RSA2.crt") // 加载支付宝公钥证书
if err != nil {
panic(err)
}
var pa = alipay.TradeWapPay{}
// 回调地址
pa.NotifyURL = domain.GetName() + "/api/v1/pay/alipay/h5_callback"
// 跳转页面
pa.ReturnURL = "https://h5.reecook.cn/app/paydone.html"
// 应该是商城名称
pa.Subject = title
// 生成唯一订单号
outTradeNo := public.GenerateOrderAliPayOutTradeNo(userID, orderID)
pa.OutTradeNo = outTradeNo
amount, _ := strconv.ParseFloat(actualAmount.String(), 2)
pa.TotalAmount = strconv.FormatFloat(amount, 'f', 2, 64)
pa.ProductCode = "AlipayH5"
// pa.ProductCode = "QUICK_WAP_WAY"
pa.TimeExpire = time.Now().Add(60 * time.Minute).Format("2006-01-02 15:04")
pa.TimeoutExpress = time.Now().Add(15 * time.Minute).Format("2006-01-02 15:04:05")
// bs, _ := json.Marshal(pa)
// beego.Info(string(bs))
payUrl, err := client.TradeWapPay(pa)
if err != nil {
errMsg := fmt.Sprintf("alipay-h5 支付出现错误%s,", err)
comFunc.PrintErr(errMsg)
return "", "", err
}
var payURL = payUrl.String()
return payURL, outTradeNo, nil
}