This commit is contained in:
unknown
2026-02-04 20:27:13 +08:00
commit 3b042d1dad
9410 changed files with 1488147 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package payments
import (
"github.com/TeaOSLab/EdgeAPI/internal/db/models/accounts"
"net/url"
)
type Payment interface {
GeneratePayURL(order *accounts.UserOrder, method *accounts.OrderMethod) (url string, err error)
Verify(formValues url.Values) (orderId int64, err error)
}

View File

@@ -0,0 +1,146 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package payments
import (
"encoding/json"
"errors"
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/accounts"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/iwind/TeaGo/dbs"
"github.com/smartwalle/alipay/v3"
"net/url"
"strings"
)
type AlipayPayment struct {
}
func NewAlipayPayment() *AlipayPayment {
return &AlipayPayment{}
}
// GeneratePayURL 构造支付URL
func (this *AlipayPayment) GeneratePayURL(order *accounts.UserOrder, method *accounts.OrderMethod) (string, error) {
var params = &userconfigs.AlipayPayMethodParams{}
err := json.Unmarshal(method.Params, params)
if err != nil {
return "", errors.New("decode params: " + err.Error())
}
client, err := this.client(params)
if err != nil {
return "", err
}
var def = userconfigs.FindPresetPayMethodWithCode(userconfigs.PayMethodAlipay)
if def == nil {
return "", errors.New("can not find payment method")
}
// 用户节点访问地址
userNodeAddr, err := models.SharedUserNodeDAO.FindUserNodeAccessAddr(nil)
if err != nil {
return "", err
}
var p = alipay.TradeWapPay{}
p.NotifyURL = strings.ReplaceAll(def.NotifyURL, "${baseAddr}", userNodeAddr)
p.ReturnURL = userNodeAddr + "/finance/pay?code=" + order.Code
p.Subject = userconfigs.FindOrderTypeName(order.Type)
p.OutTradeNo = order.Code
p.TotalAmount = fmt.Sprintf("%.2f", order.Amount)
p.ProductCode = params.ProductCode
result, err := client.TradeWapPay(p)
if err != nil {
return "", err
}
return result.String(), nil
}
// Verify 校验订单
// "gmt_create=2022-09-28+08%3A39%3A15&charset=utf-8&seller_email=thpabq1166%40sandbox.com&subject=%E5%85%85%E5%80%BC&sign=PAu%2BDHv2EerXiE4fUTfwTXWL7g4N%2BVv2zBcr8jw%2FJd2ciNsDyayqMudSNcvDzWGPwIC6P0fFqGPuoA4jod3lbCXS0uPOWANfkG%2BOS8OAIweyeNwEz%2B6G6HjMIDvD07wNMe5NKOnNc82UXOY4sIYo%2Fgfbtgw96CdUWxvAjEWTNSld4YExUf6y%2BjHZqaU%2FijNIku4q3u2UsUxszf81q9HsgOVRXuk9BTjKcgK3Eqbf5LwSF2zFYXdmUSvbGJWzl6uIsWtZMeRfMmtkGZbNIqRMLDjb9QbMv2o4foWF9EoZ%2Bev3cjDkHrzJtcpyUEyf1QobqOhP%2FEZ0Hm0R4blscAt2qQ%3D%3D&buyer_id=2088622987776411&invoice_amount=0.01&notify_id=2022092800222083918076410521014666&fund_bill_list=%5B%7B%22amount%22%3A%220.01%22%2C%22fundChannel%22%3A%22ALIPAYACCOUNT%22%7D%5D&notify_type=trade_status_sync&trade_status=TRADE_SUCCESS&receipt_amount=0.01&buyer_pay_amount=0.01&app_id=2021000121667766&sign_type=RSA2&seller_id=2088621993221476&gmt_payment=2022-09-28+08%3A39%3A17&notify_time=2022-09-28+08%3A39%3A19&version=1.0&out_trade_no=10001&total_amount=0.01&trade_no=2022092822001476410502203660&auth_app_id=2021000121667766&buyer_logon_id=phy***%40sandbox.com&point_amount=0.00"
func (this *AlipayPayment) Verify(formValues url.Values) (orderId int64, err error) {
var orderCode = formValues.Get("out_trade_no")
if len(orderCode) == 0 {
return 0, errors.New("'out_trade_no' required")
}
var tradeStatus = formValues.Get("trade_status")
if tradeStatus != "TRADE_SUCCESS" {
return 0, errors.New("failed to pay: trade status: " + tradeStatus)
}
var tx *dbs.Tx
order, err := accounts.SharedUserOrderDAO.FindUserOrderWithCode(tx, orderCode)
if err != nil {
return
}
if order == nil {
return 0, errors.New("could not find order with code '" + orderCode + "'")
}
orderId = int64(order.Id)
method, err := accounts.SharedOrderMethodDAO.FindEnabledOrderMethod(tx, int64(order.MethodId))
if err != nil {
return 0, err
}
if method == nil {
return 0, errors.New("can not find payment method")
}
if method.ParentCode != userconfigs.PayMethodAlipay {
return 0, errors.New("invalid method parent code '" + method.ParentCode + "', should be '" + userconfigs.PayMethodAlipay + "'")
}
var params = &userconfigs.AlipayPayMethodParams{}
err = json.Unmarshal(method.Params, params)
if err != nil {
return 0, errors.New("decode params: " + err.Error())
}
client, err := this.client(params)
if err != nil {
return 0, err
}
err = client.VerifySign(formValues)
if err != nil {
return 0, err
}
return
}
// 获取客户端
// TODO 考虑重用性
func (this *AlipayPayment) client(params *userconfigs.AlipayPayMethodParams) (*alipay.Client, error) {
client, err := alipay.New(params.AppId, params.PrivateKey, !params.IsSandbox)
if err != nil {
return nil, err
}
err = client.LoadAppCertPublicKey(params.AppPublicCert)
if err != nil {
return nil, errors.New("load app public cert failed: " + err.Error())
}
err = client.LoadAliPayRootCert(params.AlipayRootCert)
if err != nil {
return nil, errors.New("load alipay root cert failed: " + err.Error())
}
err = client.LoadAlipayCertPublicKey(params.AlipayPublicCert)
if err != nil {
return nil, errors.New("load alipay public cert failed: " + err.Error())
}
return client, nil
}

View File

@@ -0,0 +1,57 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
package payments
import (
"crypto/sha256"
"fmt"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/accounts"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/iwind/TeaGo/types"
"net/url"
"sort"
"strings"
"time"
)
// GeneratePayURL PayURL 构造支付URL
func GeneratePayURL(order *accounts.UserOrder, method *accounts.OrderMethod) (payURL string, err error) {
if method == nil || !method.IsOn {
return "", errors.New("invalid method with id '" + types.String(method.Id) + "'")
}
// 内置支付方式
switch method.ParentCode {
case userconfigs.PayMethodAlipay: // 支付宝
return NewAlipayPayment().GeneratePayURL(order, method)
}
// 自定义
var args = []string{}
args = append(args, "EdgeOrderMethod="+url.QueryEscape(method.Code))
args = append(args, "EdgeOrderCode="+url.QueryEscape(order.Code))
args = append(args, "EdgeOrderTimestamp="+types.String(time.Now().Unix()))
args = append(args, "EdgeOrderAmount="+fmt.Sprintf("%.2f", order.Amount))
sort.Strings(args)
var signArgs = append([]string{}, args...)
signArgs = append(signArgs, method.Secret)
var sign = fmt.Sprintf("%x", sha256.Sum256([]byte(strings.Join(signArgs, "&"))))
args = append(args, "EdgeOrderSign="+sign)
if strings.Contains(method.Url, "?") {
return method.Url + "&" + strings.Join(args, "&"), nil
}
return method.Url + "?" + strings.Join(args, "&"), nil
}
func Verify(payMethod userconfigs.PayMethod, formValues url.Values) (orderId int64, err error) {
switch payMethod {
case userconfigs.PayMethodAlipay: // 支付宝
return NewAlipayPayment().Verify(formValues)
}
return 0, errors.New("invalid payment method '" + payMethod + "'")
}