mirror of
https://github.com/casdoor/casdoor.git
synced 2025-05-23 02:35:49 +08:00
feat: add wechatpay support. (#1710)
* feat: add wechatpay support. * feat: add wechatpay support. * Update wechatv3pay.go * fix: update format. * Update wechatv3pay.go * Update wechatv3pay.go * Update wechatv3pay.go * fix: update file format. * fix: improve the front of wechat payment. * fix: change clientId2 to clientId. * fix: fix the code format. * fix: return backend error information to frontend.
This commit is contained in:
parent
2d55252261
commit
ad6f2ad2e1
@ -30,7 +30,7 @@ func TestProduct(t *testing.T) {
|
||||
product := GetProduct("admin/product_123")
|
||||
provider := getProvider(product.Owner, "provider_pay_alipay")
|
||||
cert := getCert(product.Owner, "cert-pay-alipay")
|
||||
pProvider := pp.GetPaymentProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.Host, cert.Certificate, cert.PrivateKey, cert.AuthorityPublicKey, cert.AuthorityRootPublicKey)
|
||||
pProvider := pp.GetPaymentProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.Host, cert.Certificate, cert.PrivateKey, cert.AuthorityPublicKey, cert.AuthorityRootPublicKey, provider.ClientId2)
|
||||
|
||||
paymentName := util.GenerateTimeId()
|
||||
returnUrl := ""
|
||||
|
@ -256,7 +256,11 @@ func (p *Provider) getPaymentProvider() (pp.PaymentProvider, *Cert, error) {
|
||||
}
|
||||
}
|
||||
|
||||
pProvider := pp.GetPaymentProvider(p.Type, p.ClientId, p.ClientSecret, p.Host, cert.Certificate, cert.PrivateKey, cert.AuthorityPublicKey, cert.AuthorityRootPublicKey)
|
||||
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
|
||||
}
|
||||
|
||||
if pProvider == nil {
|
||||
return nil, cert, fmt.Errorf("the payment provider type: %s is not supported", p.Type)
|
||||
}
|
||||
|
@ -28,21 +28,21 @@ type AlipayPaymentProvider struct {
|
||||
Client *alipay.Client
|
||||
}
|
||||
|
||||
func NewAlipayPaymentProvider(appId string, appCertificate string, appPrivateKey string, authorityPublicKey string, authorityRootPublicKey string) *AlipayPaymentProvider {
|
||||
func NewAlipayPaymentProvider(appId string, appCertificate string, appPrivateKey string, authorityPublicKey string, authorityRootPublicKey string) (*AlipayPaymentProvider, error) {
|
||||
pp := &AlipayPaymentProvider{}
|
||||
|
||||
client, err := alipay.NewClient(appId, appPrivateKey, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = client.SetCertSnByContent([]byte(appCertificate), []byte(authorityRootPublicKey), []byte(authorityPublicKey))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pp.Client = client
|
||||
return pp
|
||||
return pp, nil
|
||||
}
|
||||
|
||||
func (pp *AlipayPaymentProvider) Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, returnUrl string, notifyUrl string) (string, error) {
|
||||
|
@ -22,11 +22,23 @@ type PaymentProvider interface {
|
||||
GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error)
|
||||
}
|
||||
|
||||
func GetPaymentProvider(typ string, appId string, clientSecret string, host string, appCertificate string, appPrivateKey string, authorityPublicKey string, authorityRootPublicKey string) PaymentProvider {
|
||||
func GetPaymentProvider(typ string, appId string, clientSecret string, host string, appCertificate string, appPrivateKey string, authorityPublicKey string, authorityRootPublicKey string, clientId2 string) (PaymentProvider, error) {
|
||||
if typ == "Alipay" {
|
||||
return NewAlipayPaymentProvider(appId, appCertificate, appPrivateKey, authorityPublicKey, authorityRootPublicKey)
|
||||
newAlipayPaymentProvider, err := NewAlipayPaymentProvider(appId, appCertificate, appPrivateKey, authorityPublicKey, authorityRootPublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newAlipayPaymentProvider, nil
|
||||
} else if typ == "GC" {
|
||||
return NewGcPaymentProvider(appId, clientSecret, host)
|
||||
return NewGcPaymentProvider(appId, clientSecret, host), nil
|
||||
} else if typ == "WeChat Pay" {
|
||||
// appId, mchId, mchCertSerialNumber, apiV3Key, privateKey
|
||||
newWechatPaymentProvider, err := NewWechatPaymentProvider(clientId2, appId, authorityPublicKey, clientSecret, appPrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newWechatPaymentProvider, nil
|
||||
}
|
||||
return nil
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
102
pp/wechatpay.go
Normal file
102
pp/wechatpay.go
Normal file
@ -0,0 +1,102 @@
|
||||
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package pp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"github.com/go-pay/gopay"
|
||||
"github.com/go-pay/gopay/wechat/v3"
|
||||
)
|
||||
|
||||
type WechatPaymentProvider struct {
|
||||
ClientV3 *wechat.ClientV3
|
||||
appId string
|
||||
}
|
||||
|
||||
func NewWechatPaymentProvider(appId string, mchId string, mchCertSerialNumber string, apiV3Key string, privateKey string) (*WechatPaymentProvider, error) {
|
||||
pp := &WechatPaymentProvider{appId: appId}
|
||||
|
||||
clientV3, err := wechat.NewClientV3(mchId, mchCertSerialNumber, apiV3Key, privateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = clientV3.AutoVerifySign()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pp.ClientV3 = clientV3
|
||||
return pp, nil
|
||||
}
|
||||
|
||||
func (pp *WechatPaymentProvider) Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, returnUrl string, notifyUrl 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("body", productDisplayName)
|
||||
bm.Set("out_trade_no", paymentName)
|
||||
bm.Set("total_fee", getPriceString(price))
|
||||
|
||||
wechatRsp, err := pp.ClientV3.V3TransactionJsapi(context.Background(), bm)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
payUrl := fmt.Sprintf("https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect", pp.appId, wechatRsp.Response.PrepayId)
|
||||
return payUrl, nil
|
||||
}
|
||||
|
||||
func (pp *WechatPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string) (string, string, float64, string, string, error) {
|
||||
bm, err := wechat.V3ParseNotifyToBodyMap(request)
|
||||
if err != nil {
|
||||
return "", "", 0, "", "", err
|
||||
}
|
||||
|
||||
providerName := bm.Get("providerName")
|
||||
productName := bm.Get("productName")
|
||||
|
||||
productDisplayName := bm.Get("body")
|
||||
paymentName := bm.Get("out_trade_no")
|
||||
price := util.ParseFloat(bm.Get("total_fee"))
|
||||
|
||||
notifyReq, err := wechat.V3ParseNotify(request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cert := pp.ClientV3.WxPublicKey()
|
||||
|
||||
err = notifyReq.VerifySignByPK(cert)
|
||||
if err != nil {
|
||||
return "", "", 0, "", "", err
|
||||
}
|
||||
|
||||
return productDisplayName, paymentName, price, productName, providerName, nil
|
||||
}
|
||||
|
||||
func (pp *WechatPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {
|
||||
return "", nil
|
||||
}
|
@ -461,13 +461,15 @@ class ProviderEditPage extends React.Component {
|
||||
)
|
||||
}
|
||||
{
|
||||
this.state.provider.type !== "WeChat" && this.state.provider.type !== "Aliyun Captcha" ? null : (
|
||||
this.state.provider.type !== "WeChat" && this.state.provider.type !== "Aliyun Captcha" && this.state.provider.type !== "WeChat Pay" ? null : (
|
||||
<React.Fragment>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{this.state.provider.type === "Aliyun Captcha"
|
||||
? Setting.getLabel(i18next.t("provider:Scene"), i18next.t("provider:Scene - Tooltip"))
|
||||
: Setting.getLabel(i18next.t("provider:Client ID 2"), i18next.t("provider:Client ID 2 - Tooltip"))}
|
||||
: this.state.provider.type === "WeChat Pay"
|
||||
? Setting.getLabel("appId", "appId")
|
||||
: Setting.getLabel(i18next.t("provider:Client ID 2"), i18next.t("provider:Client ID 2 - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.provider.clientId2} onChange={e => {
|
||||
@ -475,18 +477,22 @@ class ProviderEditPage extends React.Component {
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{this.state.provider.type === "Aliyun Captcha"
|
||||
? Setting.getLabel(i18next.t("provider:App key"), i18next.t("provider:App key - Tooltip"))
|
||||
: Setting.getLabel(i18next.t("provider:Client secret 2"), i18next.t("provider:Client secret 2 - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.provider.clientSecret2} onChange={e => {
|
||||
this.updateProviderField("clientSecret2", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
{
|
||||
this.state.provider.type === "WeChat Pay" ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{this.state.provider.type === "Aliyun Captcha"
|
||||
? Setting.getLabel(i18next.t("provider:App key"), i18next.t("provider:App key - Tooltip"))
|
||||
: Setting.getLabel(i18next.t("provider:Client secret 2"), i18next.t("provider:Client secret 2 - Tooltip"))}
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input value={this.state.provider.clientSecret2} onChange={e => {
|
||||
this.updateProviderField("clientSecret2", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
)
|
||||
}
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user