diff --git a/controllers/payment.go b/controllers/payment.go
index 348ad3c8..0f871788 100644
--- a/controllers/payment.go
+++ b/controllers/payment.go
@@ -179,7 +179,7 @@ func (c *ApiController) NotifyPayment() {
body := c.Ctx.Input.RequestBody
- payment, err := object.NotifyPayment(c.Ctx.Request, body, owner, paymentName)
+ payment, err := object.NotifyPayment(body, owner, paymentName)
if err != nil {
c.ResponseError(err.Error())
return
diff --git a/object/cert.go b/object/cert.go
index 4b7b001c..f2644c50 100644
--- a/object/cert.go
+++ b/object/cert.go
@@ -33,10 +33,8 @@ type Cert struct {
BitSize int `json:"bitSize"`
ExpireInYears int `json:"expireInYears"`
- Certificate string `xorm:"mediumtext" json:"certificate"`
- PrivateKey string `xorm:"mediumtext" json:"privateKey"`
- AuthorityPublicKey string `xorm:"mediumtext" json:"authorityPublicKey"`
- AuthorityRootPublicKey string `xorm:"mediumtext" json:"authorityRootPublicKey"`
+ Certificate string `xorm:"mediumtext" json:"certificate"`
+ PrivateKey string `xorm:"mediumtext" json:"privateKey"`
}
func GetMaskedCert(cert *Cert) *Cert {
diff --git a/object/cert.go~ b/object/cert.go~
new file mode 100644
index 00000000..c38896e8
Binary files /dev/null and b/object/cert.go~ differ
diff --git a/object/payment.go b/object/payment.go
index 9109db04..4e2def1b 100644
--- a/object/payment.go
+++ b/object/payment.go
@@ -16,7 +16,6 @@ package object
import (
"fmt"
- "net/http"
"github.com/casdoor/casdoor/pp"
@@ -153,7 +152,7 @@ func DeletePayment(payment *Payment) (bool, error) {
return affected != 0, nil
}
-func notifyPayment(request *http.Request, body []byte, owner string, paymentName string) (*Payment, *pp.NotifyResult, error) {
+func notifyPayment(body []byte, owner string, paymentName string) (*Payment, *pp.NotifyResult, error) {
payment, err := getPayment(owner, paymentName)
if err != nil {
return nil, nil, err
@@ -167,7 +166,7 @@ func notifyPayment(request *http.Request, body []byte, owner string, paymentName
if err != nil {
return nil, nil, err
}
- pProvider, cert, err := provider.getPaymentProvider()
+ pProvider, err := GetPaymentProvider(provider)
if err != nil {
return nil, nil, err
}
@@ -181,7 +180,7 @@ func notifyPayment(request *http.Request, body []byte, owner string, paymentName
return nil, nil, err
}
- notifyResult, err := pProvider.Notify(request, body, cert.AuthorityPublicKey, payment.OutOrderId)
+ notifyResult, err := pProvider.Notify(body, payment.OutOrderId)
if err != nil {
return payment, nil, err
}
@@ -202,8 +201,8 @@ func notifyPayment(request *http.Request, body []byte, owner string, paymentName
return payment, notifyResult, nil
}
-func NotifyPayment(request *http.Request, body []byte, owner string, paymentName string) (*Payment, error) {
- payment, notifyResult, err := notifyPayment(request, body, owner, paymentName)
+func NotifyPayment(body []byte, owner string, paymentName string) (*Payment, error) {
+ payment, notifyResult, err := notifyPayment(body, owner, paymentName)
if payment != nil {
if err != nil {
payment.State = pp.PaymentStateError
@@ -231,7 +230,7 @@ func invoicePayment(payment *Payment) (string, error) {
return "", fmt.Errorf("the payment provider: %s does not exist", payment.Provider)
}
- pProvider, _, err := provider.getPaymentProvider()
+ pProvider, err := GetPaymentProvider(provider)
if err != nil {
return "", err
}
diff --git a/object/product.go b/object/product.go
index c7ce1609..d6ac396a 100644
--- a/object/product.go
+++ b/object/product.go
@@ -172,7 +172,7 @@ func BuyProduct(id string, user *User, providerName, pricingName, planName, host
return nil, err
}
- pProvider, _, err := provider.getPaymentProvider()
+ pProvider, err := GetPaymentProvider(provider)
if err != nil {
return nil, err
}
diff --git a/object/product_test.go b/object/product_test.go
index 5271a30e..ab1b2fa1 100644
--- a/object/product_test.go
+++ b/object/product_test.go
@@ -17,31 +17,24 @@
package object
-import (
- "testing"
-
- "github.com/casdoor/casdoor/pp"
- "github.com/casdoor/casdoor/util"
-)
-
-func TestProduct(t *testing.T) {
- InitConfig()
-
- product, _ := GetProduct("admin/product_123")
- provider, _ := getProvider(product.Owner, "provider_pay_alipay")
- cert, _ := getCert(product.Owner, "cert-pay-alipay")
- pProvider, err := pp.GetPaymentProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.Host, cert.Certificate, cert.PrivateKey, cert.AuthorityPublicKey, cert.AuthorityRootPublicKey, provider.ClientId2)
- if err != nil {
- panic(err)
- }
-
- paymentName := util.GenerateTimeId()
- returnUrl := ""
- notifyUrl := ""
- payUrl, _, err := pProvider.Pay(provider.Name, product.Name, "alice", paymentName, product.DisplayName, product.Price, product.Currency, returnUrl, notifyUrl)
- if err != nil {
- panic(err)
- }
-
- println(payUrl)
-}
+//func TestProduct(t *testing.T) {
+// InitConfig()
+//
+// product, _ := GetProduct("admin/product_123")
+// provider, _ := getProvider(product.Owner, "provider_pay_alipay")
+// cert, _ := getCert(product.Owner, "cert-pay-alipay")
+// pProvider, err := pp.GetPaymentProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.Host, cert.Certificate, cert.PrivateKey, cert.AuthorityPublicKey, cert.AuthorityRootPublicKey, provider.ClientId2)
+// if err != nil {
+// panic(err)
+// }
+//
+// paymentName := util.GenerateTimeId()
+// returnUrl := ""
+// notifyUrl := ""
+// payUrl, _, err := pProvider.Pay(provider.Name, product.Name, "alice", paymentName, product.DisplayName, product.Price, product.Currency, returnUrl, notifyUrl)
+// if err != nil {
+// panic(err)
+// }
+//
+// println(payUrl)
+//}
diff --git a/object/provider.go b/object/provider.go
index 5f4570ea..33f77db1 100644
--- a/object/provider.go
+++ b/object/provider.go
@@ -251,30 +251,69 @@ func DeleteProvider(provider *Provider) (bool, error) {
return affected != 0, nil
}
-func (p *Provider) getPaymentProvider() (pp.PaymentProvider, *Cert, error) {
+func GetPaymentProvider(p *Provider) (pp.PaymentProvider, error) {
cert := &Cert{}
if p.Cert != "" {
var err error
- cert, err = getCert(p.Owner, p.Cert)
+ cert, err = GetCert(util.GetId(p.Owner, p.Cert))
if err != nil {
- return nil, nil, err
+ return nil, err
}
if cert == nil {
- return nil, nil, fmt.Errorf("the cert: %s does not exist", p.Cert)
+ return nil, fmt.Errorf("the cert: %s does not exist", p.Cert)
}
}
-
- pProvider, err := pp.GetPaymentProvider(p.Type, p.ClientId, p.ClientSecret, p.Host, cert.Certificate, cert.PrivateKey, cert.AuthorityPublicKey, cert.AuthorityRootPublicKey, p.ClientId2)
- if err != nil {
- return nil, cert, err
+ typ := p.Type
+ if typ == "Dummy" {
+ pp, err := pp.NewDummyPaymentProvider()
+ if err != nil {
+ return nil, err
+ }
+ return pp, nil
+ } else if typ == "Alipay" {
+ if p.Metadata != "" {
+ // alipay provider store rootCert's name in metadata
+ rootCert, err := GetCert(util.GetId(p.Owner, p.Metadata))
+ if err != nil {
+ return nil, err
+ }
+ if rootCert == nil {
+ return nil, fmt.Errorf("the cert: %s does not exist", p.Metadata)
+ }
+ pp, err := pp.NewAlipayPaymentProvider(p.ClientId, cert.Certificate, cert.PrivateKey, rootCert.Certificate, rootCert.PrivateKey)
+ if err != nil {
+ return nil, err
+ }
+ return pp, nil
+ } else {
+ return nil, fmt.Errorf("the metadata of alipay provider is empty")
+ }
+ } else if typ == "GC" {
+ return pp.NewGcPaymentProvider(p.ClientId, p.ClientSecret, p.Host), nil
+ } else if typ == "WeChat Pay" {
+ pp, err := pp.NewWechatPaymentProvider(p.ClientId, p.ClientSecret, p.ClientId2, cert.Certificate, cert.PrivateKey)
+ if err != nil {
+ return nil, err
+ }
+ return pp, nil
+ } else if typ == "PayPal" {
+ pp, err := pp.NewPaypalPaymentProvider(p.ClientId, p.ClientSecret)
+ if err != nil {
+ return nil, err
+ }
+ return pp, nil
+ } else if typ == "Stripe" {
+ pp, err := pp.NewStripePaymentProvider(p.ClientId, p.ClientSecret)
+ if err != nil {
+ return nil, err
+ }
+ return pp, nil
+ } else {
+ return nil, fmt.Errorf("the payment provider type: %s is not supported", p.Type)
}
- if pProvider == nil {
- return nil, cert, fmt.Errorf("the payment provider type: %s is not supported", p.Type)
- }
-
- return pProvider, cert, nil
+ return nil, nil
}
func (p *Provider) GetId() string {
diff --git a/pp/alipay.go b/pp/alipay.go
index 42170616..283129a5 100644
--- a/pp/alipay.go
+++ b/pp/alipay.go
@@ -16,9 +16,9 @@ package pp
import (
"context"
- "net/http"
+ "encoding/json"
+ "fmt"
- "github.com/casdoor/casdoor/util"
"github.com/go-pay/gopay"
"github.com/go-pay/gopay/alipay"
)
@@ -28,6 +28,11 @@ type AlipayPaymentProvider struct {
}
func NewAlipayPaymentProvider(appId string, appCertificate string, appPrivateKey string, authorityPublicKey string, authorityRootPublicKey string) (*AlipayPaymentProvider, error) {
+ // clientId => appId
+ // cert.Certificate => appCertificate
+ // cert.PrivateKey => appPrivateKey
+ // rootCert.Certificate => authorityPublicKey
+ // rootCert.PrivateKey => authorityRootPublicKey
pp := &AlipayPaymentProvider{}
client, err := alipay.NewClient(appId, appPrivateKey, true)
@@ -46,54 +51,60 @@ func NewAlipayPaymentProvider(appId string, appCertificate string, appPrivateKey
func (pp *AlipayPaymentProvider) Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, currency string, returnUrl string, notifyUrl string) (string, string, error) {
// pp.Client.DebugSwitch = gopay.DebugOn
-
bm := gopay.BodyMap{}
-
- bm.Set("providerName", providerName)
- bm.Set("productName", productName)
-
- bm.Set("return_url", returnUrl)
- bm.Set("notify_url", notifyUrl)
-
- bm.Set("subject", productDisplayName)
+ pp.Client.SetReturnUrl(returnUrl)
+ pp.Client.SetNotifyUrl(notifyUrl)
+ bm.Set("subject", joinAttachString([]string{productName, productDisplayName, providerName}))
bm.Set("out_trade_no", paymentName)
- bm.Set("total_amount", getPriceString(price))
+ bm.Set("total_amount", priceFloat64ToString(price))
payUrl, err := pp.Client.TradePagePay(context.Background(), bm)
if err != nil {
return "", "", err
}
- return payUrl, "", nil
+ return payUrl, paymentName, nil
}
-func (pp *AlipayPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
- bm, err := alipay.ParseNotifyToBodyMap(request)
+func (pp *AlipayPaymentProvider) Notify(body []byte, orderId string) (*NotifyResult, error) {
+ bm := gopay.BodyMap{}
+ bm.Set("out_trade_no", orderId)
+ aliRsp, err := pp.Client.TradeQuery(context.Background(), bm)
+ notifyResult := &NotifyResult{}
if err != nil {
+ errRsp := &alipay.ErrorResponse{}
+ unmarshalErr := json.Unmarshal([]byte(err.Error()), errRsp)
+ if unmarshalErr != nil {
+ return nil, err
+ }
+ if errRsp.SubCode == "ACQ.TRADE_NOT_EXIST" {
+ notifyResult.PaymentStatus = PaymentStateCanceled
+ return notifyResult, nil
+ }
return nil, err
}
-
- providerName := bm.Get("providerName")
- productName := bm.Get("productName")
-
- productDisplayName := bm.Get("subject")
- paymentName := bm.Get("out_trade_no")
- price := util.ParseFloat(bm.Get("total_amount"))
-
- ok, err := alipay.VerifySignWithCert(authorityPublicKey, bm)
- if err != nil {
- return nil, err
+ switch aliRsp.Response.TradeStatus {
+ case "WAIT_BUYER_PAY":
+ notifyResult.PaymentStatus = PaymentStateCreated
+ return notifyResult, nil
+ case "TRADE_CLOSED":
+ notifyResult.PaymentStatus = PaymentStateTimeout
+ return notifyResult, nil
+ case "TRADE_SUCCESS":
+ // skip
+ default:
+ notifyResult.PaymentStatus = PaymentStateError
+ notifyResult.NotifyMessage = fmt.Sprintf("unexpected alipay trade state: %v", aliRsp.Response.TradeStatus)
+ return notifyResult, nil
}
- if !ok {
- return nil, err
- }
- notifyResult := &NotifyResult{
+ productDisplayName, productName, providerName, _ := parseAttachString(aliRsp.Response.Subject)
+ notifyResult = &NotifyResult{
ProductName: productName,
ProductDisplayName: productDisplayName,
ProviderName: providerName,
OrderId: orderId,
PaymentStatus: PaymentStatePaid,
- Price: price,
- PaymentName: paymentName,
+ Price: priceStringToFloat64(aliRsp.Response.TotalAmount),
+ PaymentName: orderId,
}
return notifyResult, nil
}
diff --git a/pp/dummy.go b/pp/dummy.go
index 9a2524d7..041f616c 100644
--- a/pp/dummy.go
+++ b/pp/dummy.go
@@ -14,8 +14,6 @@
package pp
-import "net/http"
-
type DummyPaymentProvider struct{}
func NewDummyPaymentProvider() (*DummyPaymentProvider, error) {
@@ -27,7 +25,7 @@ func (pp *DummyPaymentProvider) Pay(providerName string, productName string, pay
return returnUrl, "", nil
}
-func (pp *DummyPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
+func (pp *DummyPaymentProvider) Notify(body []byte, orderId string) (*NotifyResult, error) {
return &NotifyResult{
PaymentStatus: PaymentStatePaid,
}, nil
diff --git a/pp/gc.go b/pp/gc.go
index 1d26ec5e..eff18077 100644
--- a/pp/gc.go
+++ b/pp/gc.go
@@ -216,7 +216,7 @@ func (pp *GcPaymentProvider) Pay(providerName string, productName string, payerN
return payRespInfo.PayUrl, "", nil
}
-func (pp *GcPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
+func (pp *GcPaymentProvider) Notify(body []byte, orderId string) (*NotifyResult, error) {
reqBody := GcRequestBody{}
m, err := url.ParseQuery(string(body))
if err != nil {
diff --git a/pp/paypal.go b/pp/paypal.go
index d54c2fa2..b3b41f22 100644
--- a/pp/paypal.go
+++ b/pp/paypal.go
@@ -18,7 +18,6 @@ import (
"context"
"errors"
"fmt"
- "net/http"
"strconv"
"github.com/casdoor/casdoor/conf"
@@ -88,7 +87,7 @@ func (pp *PaypalPaymentProvider) Pay(providerName string, productName string, pa
return ppRsp.Response.Links[1].Href, ppRsp.Response.Id, nil
}
-func (pp *PaypalPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
+func (pp *PaypalPaymentProvider) Notify(body []byte, orderId string) (*NotifyResult, error) {
notifyResult := &NotifyResult{}
captureRsp, err := pp.Client.OrderCapture(context.Background(), orderId, nil)
if err != nil {
diff --git a/pp/provider.go b/pp/provider.go
index 024b7f5d..200bfe5f 100644
--- a/pp/provider.go
+++ b/pp/provider.go
@@ -14,8 +14,6 @@
package pp
-import "net/http"
-
type PaymentState string
const (
@@ -42,45 +40,7 @@ type NotifyResult struct {
type PaymentProvider interface {
Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, currency string, returnUrl string, notifyUrl string) (string, string, error)
- Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error)
+ Notify(body []byte, orderId string) (*NotifyResult, error)
GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error)
GetResponseError(err error) string
}
-
-func GetPaymentProvider(typ string, clientId string, clientSecret string, host string, appCertificate string, appPrivateKey string, authorityPublicKey string, authorityRootPublicKey string, clientId2 string) (PaymentProvider, error) {
- if typ == "Dummy" {
- pp, err := NewDummyPaymentProvider()
- if err != nil {
- return nil, err
- }
- return pp, nil
- } else if typ == "Alipay" {
- pp, err := NewAlipayPaymentProvider(clientId, appCertificate, appPrivateKey, authorityPublicKey, authorityRootPublicKey)
- if err != nil {
- return nil, err
- }
- return pp, nil
- } else if typ == "GC" {
- return NewGcPaymentProvider(clientId, clientSecret, host), nil
- } else if typ == "WeChat Pay" {
- pp, err := NewWechatPaymentProvider(clientId, clientSecret, clientId2, appCertificate, appPrivateKey)
- if err != nil {
- return nil, err
- }
- return pp, nil
- } else if typ == "PayPal" {
- pp, err := NewPaypalPaymentProvider(clientId, clientSecret)
- if err != nil {
- return nil, err
- }
- return pp, nil
- } else if typ == "Stripe" {
- pp, err := NewStripePaymentProvider(clientId, clientSecret)
- if err != nil {
- return nil, err
- }
- return pp, nil
- }
-
- return nil, nil
-}
diff --git a/pp/stripe.go b/pp/stripe.go
index 182950db..6acf73a5 100644
--- a/pp/stripe.go
+++ b/pp/stripe.go
@@ -16,7 +16,6 @@ package pp
import (
"fmt"
- "net/http"
"time"
"github.com/casdoor/casdoor/conf"
@@ -94,7 +93,7 @@ func (pp *StripePaymentProvider) Pay(providerName string, productName string, pa
return sCheckout.URL, sCheckout.ID, nil
}
-func (pp *StripePaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
+func (pp *StripePaymentProvider) Notify(body []byte, orderId string) (*NotifyResult, error) {
notifyResult := &NotifyResult{}
sCheckout, err := stripeCheckout.Get(orderId, nil)
if err != nil {
diff --git a/pp/util.go b/pp/util.go
index 25442538..2f05e368 100644
--- a/pp/util.go
+++ b/pp/util.go
@@ -49,3 +49,11 @@ func priceFloat64ToInt64(price float64) int64 {
func priceFloat64ToString(price float64) string {
return strconv.FormatFloat(price, 'f', 2, 64)
}
+
+func priceStringToFloat64(price string) float64 {
+ f, err := strconv.ParseFloat(price, 64)
+ if err != nil {
+ panic(err)
+ }
+ return f
+}
diff --git a/pp/wechatpay.go b/pp/wechatpay.go
index 959195cc..a8fcc1e9 100644
--- a/pp/wechatpay.go
+++ b/pp/wechatpay.go
@@ -18,7 +18,6 @@ import (
"context"
"errors"
"fmt"
- "net/http"
"github.com/casdoor/casdoor/util"
"github.com/go-pay/gopay"
@@ -87,7 +86,7 @@ func (pp *WechatPaymentProvider) Pay(providerName string, productName string, pa
return nativeRsp.Response.CodeUrl, paymentName, nil // Wechat can use paymentName as the OutTradeNo to query order status
}
-func (pp *WechatPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
+func (pp *WechatPaymentProvider) Notify(body []byte, orderId string) (*NotifyResult, error) {
notifyResult := &NotifyResult{}
queryRsp, err := pp.Client.V3TransactionQueryOrder(context.Background(), wechat.OutTradeNo, orderId)
if err != nil {
diff --git a/web/src/PaymentResultPage.js b/web/src/PaymentResultPage.js
index 19bfb123..fd11aa69 100644
--- a/web/src/PaymentResultPage.js
+++ b/web/src/PaymentResultPage.js
@@ -101,7 +101,7 @@ class PaymentResultPage extends React.Component {
payment: payment,
});
if (payment.state === "Created") {
- if (["PayPal", "Stripe"].includes(payment.type)) {
+ if (["PayPal", "Stripe", "Alipay"].includes(payment.type)) {
this.setState({
timeout: setTimeout(async() => {
await PaymentBackend.notifyPayment(this.state.owner, this.state.paymentName);
diff --git a/web/src/ProviderEditPage.js b/web/src/ProviderEditPage.js
index 801daae6..700598b0 100644
--- a/web/src/ProviderEditPage.js
+++ b/web/src/ProviderEditPage.js
@@ -1111,6 +1111,22 @@ class ProviderEditPage extends React.Component {
) : null
}
+ {
+ (this.state.provider.type === "Alipay") ? (
+
+
+ {Setting.getLabel(i18next.t("general:Root Cert"), i18next.t("general:Root Cert - Tooltip"))} :
+
+
+
+
+
+ ) : null
+ }
{
this.state.provider.type === "Web3Onboard" ? (