mirror of
https://github.com/casdoor/casdoor.git
synced 2025-05-23 10:45:47 +08:00
fix: fix paypal payment provider and refactor payment code (#2159)
* feat: support paypal payment provider * feat: support paypal flow * feat: use owner replace org for payment * feat: update paypal logic * feat: gofumpt * feat: update payment * fix: fix notify * feat: delete log
This commit is contained in:
parent
026fb207b3
commit
eefa1e6df4
@ -31,7 +31,6 @@ import (
|
|||||||
// @router /get-payments [get]
|
// @router /get-payments [get]
|
||||||
func (c *ApiController) GetPayments() {
|
func (c *ApiController) GetPayments() {
|
||||||
owner := c.Input().Get("owner")
|
owner := c.Input().Get("owner")
|
||||||
organization := c.Input().Get("organization")
|
|
||||||
limit := c.Input().Get("pageSize")
|
limit := c.Input().Get("pageSize")
|
||||||
page := c.Input().Get("p")
|
page := c.Input().Get("p")
|
||||||
field := c.Input().Get("field")
|
field := c.Input().Get("field")
|
||||||
@ -49,14 +48,14 @@ func (c *ApiController) GetPayments() {
|
|||||||
c.ResponseOk(payments)
|
c.ResponseOk(payments)
|
||||||
} else {
|
} else {
|
||||||
limit := util.ParseInt(limit)
|
limit := util.ParseInt(limit)
|
||||||
count, err := object.GetPaymentCount(owner, organization, field, value)
|
count, err := object.GetPaymentCount(owner, field, value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
paginator := pagination.SetPaginator(c.Ctx, limit, count)
|
||||||
payments, err := object.GetPaginationPayments(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
payments, err := object.GetPaginationPayments(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
@ -77,10 +76,9 @@ func (c *ApiController) GetPayments() {
|
|||||||
// @router /get-user-payments [get]
|
// @router /get-user-payments [get]
|
||||||
func (c *ApiController) GetUserPayments() {
|
func (c *ApiController) GetUserPayments() {
|
||||||
owner := c.Input().Get("owner")
|
owner := c.Input().Get("owner")
|
||||||
organization := c.Input().Get("organization")
|
|
||||||
user := c.Input().Get("user")
|
user := c.Input().Get("user")
|
||||||
|
|
||||||
payments, err := object.GetUserPayments(owner, organization, user)
|
payments, err := object.GetUserPayments(owner, user)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
@ -177,24 +175,18 @@ func (c *ApiController) DeletePayment() {
|
|||||||
// @router /notify-payment [post]
|
// @router /notify-payment [post]
|
||||||
func (c *ApiController) NotifyPayment() {
|
func (c *ApiController) NotifyPayment() {
|
||||||
owner := c.Ctx.Input.Param(":owner")
|
owner := c.Ctx.Input.Param(":owner")
|
||||||
providerName := c.Ctx.Input.Param(":provider")
|
|
||||||
productName := c.Ctx.Input.Param(":product")
|
|
||||||
paymentName := c.Ctx.Input.Param(":payment")
|
paymentName := c.Ctx.Input.Param(":payment")
|
||||||
orderId := c.Ctx.Input.Param("order")
|
orderId := c.Ctx.Input.Param("order")
|
||||||
|
|
||||||
body := c.Ctx.Input.RequestBody
|
body := c.Ctx.Input.RequestBody
|
||||||
|
|
||||||
err, errorResponse := object.NotifyPayment(c.Ctx.Request, body, owner, providerName, productName, paymentName, orderId)
|
payment, err := object.NotifyPayment(c.Ctx.Request, body, owner, paymentName, orderId)
|
||||||
|
|
||||||
_, err2 := c.Ctx.ResponseWriter.Write([]byte(errorResponse))
|
|
||||||
if err2 != nil {
|
|
||||||
panic(err2)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.ResponseOk(payment)
|
||||||
}
|
}
|
||||||
|
|
||||||
// InvoicePayment
|
// InvoicePayment
|
||||||
|
@ -431,7 +431,7 @@ func organizationChangeTrigger(oldName string, newName string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
payment := new(Payment)
|
payment := new(Payment)
|
||||||
payment.Organization = newName
|
payment.Owner = newName
|
||||||
_, err = session.Where("organization=?", oldName).Update(payment)
|
_, err = session.Where("organization=?", oldName).Update(payment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -18,6 +18,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/pp"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
"github.com/xorm-io/core"
|
"github.com/xorm-io/core"
|
||||||
)
|
)
|
||||||
@ -27,38 +29,39 @@ type Payment struct {
|
|||||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||||
|
// Payment Provider Info
|
||||||
Provider string `xorm:"varchar(100)" json:"provider"`
|
Provider string `xorm:"varchar(100)" json:"provider"`
|
||||||
Type string `xorm:"varchar(100)" json:"type"`
|
Type string `xorm:"varchar(100)" json:"type"`
|
||||||
Organization string `xorm:"varchar(100)" json:"organization"`
|
// Product Info
|
||||||
User string `xorm:"varchar(100)" json:"user"`
|
ProductName string `xorm:"varchar(100)" json:"productName"`
|
||||||
ProductName string `xorm:"varchar(100)" json:"productName"`
|
ProductDisplayName string `xorm:"varchar(100)" json:"productDisplayName"`
|
||||||
ProductDisplayName string `xorm:"varchar(100)" json:"productDisplayName"`
|
Detail string `xorm:"varchar(255)" json:"detail"`
|
||||||
|
Tag string `xorm:"varchar(100)" json:"tag"`
|
||||||
Detail string `xorm:"varchar(255)" json:"detail"`
|
Currency string `xorm:"varchar(100)" json:"currency"`
|
||||||
Tag string `xorm:"varchar(100)" json:"tag"`
|
Price float64 `json:"price"`
|
||||||
Currency string `xorm:"varchar(100)" json:"currency"`
|
ReturnUrl string `xorm:"varchar(1000)" json:"returnUrl"`
|
||||||
Price float64 `json:"price"`
|
// Payer Info
|
||||||
|
User string `xorm:"varchar(100)" json:"user"`
|
||||||
PayUrl string `xorm:"varchar(2000)" json:"payUrl"`
|
PersonName string `xorm:"varchar(100)" json:"personName"`
|
||||||
ReturnUrl string `xorm:"varchar(1000)" json:"returnUrl"`
|
PersonIdCard string `xorm:"varchar(100)" json:"personIdCard"`
|
||||||
State string `xorm:"varchar(100)" json:"state"`
|
PersonEmail string `xorm:"varchar(100)" json:"personEmail"`
|
||||||
Message string `xorm:"varchar(2000)" json:"message"`
|
PersonPhone string `xorm:"varchar(100)" json:"personPhone"`
|
||||||
|
// Invoice Info
|
||||||
PersonName string `xorm:"varchar(100)" json:"personName"`
|
|
||||||
PersonIdCard string `xorm:"varchar(100)" json:"personIdCard"`
|
|
||||||
PersonEmail string `xorm:"varchar(100)" json:"personEmail"`
|
|
||||||
PersonPhone string `xorm:"varchar(100)" json:"personPhone"`
|
|
||||||
InvoiceType string `xorm:"varchar(100)" json:"invoiceType"`
|
InvoiceType string `xorm:"varchar(100)" json:"invoiceType"`
|
||||||
InvoiceTitle string `xorm:"varchar(100)" json:"invoiceTitle"`
|
InvoiceTitle string `xorm:"varchar(100)" json:"invoiceTitle"`
|
||||||
InvoiceTaxId string `xorm:"varchar(100)" json:"invoiceTaxId"`
|
InvoiceTaxId string `xorm:"varchar(100)" json:"invoiceTaxId"`
|
||||||
InvoiceRemark string `xorm:"varchar(100)" json:"invoiceRemark"`
|
InvoiceRemark string `xorm:"varchar(100)" json:"invoiceRemark"`
|
||||||
InvoiceUrl string `xorm:"varchar(255)" json:"invoiceUrl"`
|
InvoiceUrl string `xorm:"varchar(255)" json:"invoiceUrl"`
|
||||||
|
// Order Info
|
||||||
|
OutOrderId string `xorm:"varchar(100)" json:"outOrderId"`
|
||||||
|
PayUrl string `xorm:"varchar(2000)" json:"payUrl"`
|
||||||
|
State pp.PaymentState `xorm:"varchar(100)" json:"state"`
|
||||||
|
Message string `xorm:"varchar(2000)" json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPaymentCount(owner, organization, field, value string) (int64, error) {
|
func GetPaymentCount(owner, field, value string) (int64, error) {
|
||||||
session := GetSession(owner, -1, -1, field, value, "", "")
|
session := GetSession(owner, -1, -1, field, value, "", "")
|
||||||
return session.Count(&Payment{Organization: organization})
|
return session.Count(&Payment{Owner: owner})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPayments(owner string) ([]*Payment, error) {
|
func GetPayments(owner string) ([]*Payment, error) {
|
||||||
@ -71,9 +74,9 @@ func GetPayments(owner string) ([]*Payment, error) {
|
|||||||
return payments, nil
|
return payments, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserPayments(owner string, organization string, user string) ([]*Payment, error) {
|
func GetUserPayments(owner, user string) ([]*Payment, error) {
|
||||||
payments := []*Payment{}
|
payments := []*Payment{}
|
||||||
err := ormer.Engine.Desc("created_time").Find(&payments, &Payment{Owner: owner, Organization: organization, User: user})
|
err := ormer.Engine.Desc("created_time").Find(&payments, &Payment{Owner: owner, User: user})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -81,10 +84,10 @@ func GetUserPayments(owner string, organization string, user string) ([]*Payment
|
|||||||
return payments, nil
|
return payments, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetPaginationPayments(owner, organization string, offset, limit int, field, value, sortField, sortOrder string) ([]*Payment, error) {
|
func GetPaginationPayments(owner string, offset, limit int, field, value, sortField, sortOrder string) ([]*Payment, error) {
|
||||||
payments := []*Payment{}
|
payments := []*Payment{}
|
||||||
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
|
||||||
err := session.Find(&payments, &Payment{Organization: organization})
|
err := session.Find(&payments, &Payment{Owner: owner})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -125,7 +128,7 @@ func UpdatePayment(id string, payment *Payment) (bool, error) {
|
|||||||
|
|
||||||
affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(payment)
|
affected, err := ormer.Engine.ID(core.PK{owner, name}).AllCols().Update(payment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return affected != 0, nil
|
return affected != 0, nil
|
||||||
@ -149,73 +152,72 @@ func DeletePayment(payment *Payment) (bool, error) {
|
|||||||
return affected != 0, nil
|
return affected != 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func notifyPayment(request *http.Request, body []byte, owner string, providerName string, productName string, paymentName string, orderId string) (*Payment, error, string) {
|
func notifyPayment(request *http.Request, body []byte, owner string, paymentName string, orderId string) (*Payment, *pp.NotifyResult, error) {
|
||||||
provider, err := getProvider(owner, providerName)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
pProvider, cert, err := provider.getPaymentProvider()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
payment, err := getPayment(owner, paymentName)
|
payment, err := getPayment(owner, paymentName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if payment == nil {
|
if payment == nil {
|
||||||
err = fmt.Errorf("the payment: %s does not exist", paymentName)
|
err = fmt.Errorf("the payment: %s does not exist", paymentName)
|
||||||
return nil, err, pProvider.GetResponseError(err)
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
product, err := getProduct(owner, productName)
|
provider, err := getProvider(owner, payment.Provider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
pProvider, cert, err := provider.getPaymentProvider()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
product, err := getProduct(owner, payment.ProductName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
if product == nil {
|
if product == nil {
|
||||||
err = fmt.Errorf("the product: %s does not exist", productName)
|
err = fmt.Errorf("the product: %s does not exist", payment.ProductName)
|
||||||
return payment, err, pProvider.GetResponseError(err)
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
productDisplayName, paymentName, price, productName, providerName, err := pProvider.Notify(request, body, cert.AuthorityPublicKey, orderId)
|
if orderId == "" {
|
||||||
|
orderId = payment.OutOrderId
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyResult, err := pProvider.Notify(request, body, cert.AuthorityPublicKey, orderId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return payment, err, pProvider.GetResponseError(err)
|
return payment, notifyResult, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if productDisplayName != "" && productDisplayName != product.DisplayName {
|
if notifyResult.ProductDisplayName != "" && notifyResult.ProductDisplayName != product.DisplayName {
|
||||||
err = fmt.Errorf("the payment's product name: %s doesn't equal to the expected product name: %s", productDisplayName, product.DisplayName)
|
err = fmt.Errorf("the payment's product name: %s doesn't equal to the expected product name: %s", notifyResult.ProductDisplayName, product.DisplayName)
|
||||||
return payment, err, pProvider.GetResponseError(err)
|
return payment, notifyResult, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if price != product.Price {
|
if notifyResult.Price != product.Price {
|
||||||
err = fmt.Errorf("the payment's price: %f doesn't equal to the expected price: %f", price, product.Price)
|
err = fmt.Errorf("the payment's price: %f doesn't equal to the expected price: %f", notifyResult.Price, product.Price)
|
||||||
return payment, err, pProvider.GetResponseError(err)
|
return payment, notifyResult, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = nil
|
return payment, notifyResult, err
|
||||||
return payment, err, pProvider.GetResponseError(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NotifyPayment(request *http.Request, body []byte, owner string, providerName string, productName string, paymentName string, orderId string) (error, string) {
|
func NotifyPayment(request *http.Request, body []byte, owner string, paymentName string, orderId string) (*Payment, error) {
|
||||||
payment, err, errorResponse := notifyPayment(request, body, owner, providerName, productName, paymentName, orderId)
|
payment, notifyResult, err := notifyPayment(request, body, owner, paymentName, orderId)
|
||||||
if payment != nil {
|
if payment != nil {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
payment.State = "Error"
|
payment.State = pp.PaymentStateError
|
||||||
payment.Message = err.Error()
|
payment.Message = err.Error()
|
||||||
} else {
|
} else {
|
||||||
payment.State = "Paid"
|
payment.State = notifyResult.PaymentStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = UpdatePayment(payment.GetId(), payment)
|
_, err = UpdatePayment(payment.GetId(), payment)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err, errorResponse
|
return payment, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func invoicePayment(payment *Payment) (string, error) {
|
func invoicePayment(payment *Payment) (string, error) {
|
||||||
@ -242,7 +244,7 @@ func invoicePayment(payment *Payment) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func InvoicePayment(payment *Payment) (string, error) {
|
func InvoicePayment(payment *Payment) (string, error) {
|
||||||
if payment.State != "Paid" {
|
if payment.State != pp.PaymentStatePaid {
|
||||||
return "", fmt.Errorf("the payment state is supposed to be: \"%s\", got: \"%s\"", "Paid", payment.State)
|
return "", fmt.Errorf("the payment state is supposed to be: \"%s\", got: \"%s\"", "Paid", payment.State)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@ package object
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/pp"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
"github.com/xorm-io/core"
|
"github.com/xorm-io/core"
|
||||||
)
|
)
|
||||||
@ -183,36 +185,39 @@ func BuyProduct(id string, providerName string, user *User, host string) (string
|
|||||||
productDisplayName := product.DisplayName
|
productDisplayName := product.DisplayName
|
||||||
|
|
||||||
originFrontend, originBackend := getOriginFromHost(host)
|
originFrontend, originBackend := getOriginFromHost(host)
|
||||||
returnUrl := fmt.Sprintf("%s/payments/%s/result", originFrontend, paymentName)
|
returnUrl := fmt.Sprintf("%s/payments/%s/%s/result", originFrontend, owner, paymentName)
|
||||||
notifyUrl := fmt.Sprintf("%s/api/notify-payment/%s/%s/%s/%s", originBackend, owner, providerName, productName, paymentName)
|
notifyUrl := fmt.Sprintf("%s/api/notify-payment/%s/%s", originBackend, owner, paymentName)
|
||||||
|
// Create an Order and get the payUrl
|
||||||
payUrl, orderId, err := pProvider.Pay(providerName, productName, payerName, paymentName, productDisplayName, product.Price, product.Currency, returnUrl, notifyUrl)
|
payUrl, orderId, err := pProvider.Pay(providerName, productName, payerName, paymentName, productDisplayName, product.Price, product.Currency, returnUrl, notifyUrl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
|
// Create a Payment linked with Product and Order
|
||||||
payment := Payment{
|
payment := Payment{
|
||||||
Owner: "admin",
|
Owner: product.Owner,
|
||||||
Name: paymentName,
|
Name: paymentName,
|
||||||
CreatedTime: util.GetCurrentTime(),
|
CreatedTime: util.GetCurrentTime(),
|
||||||
DisplayName: paymentName,
|
DisplayName: paymentName,
|
||||||
Provider: provider.Name,
|
|
||||||
Type: provider.Type,
|
Provider: provider.Name,
|
||||||
Organization: user.Owner,
|
Type: provider.Type,
|
||||||
User: user.Name,
|
|
||||||
ProductName: productName,
|
ProductName: productName,
|
||||||
ProductDisplayName: productDisplayName,
|
ProductDisplayName: productDisplayName,
|
||||||
Detail: product.Detail,
|
Detail: product.Detail,
|
||||||
Tag: product.Tag,
|
Tag: product.Tag,
|
||||||
Currency: product.Currency,
|
Currency: product.Currency,
|
||||||
Price: product.Price,
|
Price: product.Price,
|
||||||
PayUrl: payUrl,
|
|
||||||
ReturnUrl: product.ReturnUrl,
|
ReturnUrl: product.ReturnUrl,
|
||||||
State: "Created",
|
|
||||||
|
User: user.Name,
|
||||||
|
PayUrl: payUrl,
|
||||||
|
State: pp.PaymentStateCreated,
|
||||||
|
OutOrderId: orderId,
|
||||||
}
|
}
|
||||||
|
|
||||||
if provider.Type == "Dummy" {
|
if provider.Type == "Dummy" {
|
||||||
payment.State = "Paid"
|
payment.State = pp.PaymentStatePaid
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := AddPayment(&payment)
|
affected, err := AddPayment(&payment)
|
||||||
|
21
pp/alipay.go
21
pp/alipay.go
@ -16,7 +16,6 @@ package pp
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
@ -67,10 +66,10 @@ func (pp *AlipayPaymentProvider) Pay(providerName string, productName string, pa
|
|||||||
return payUrl, "", nil
|
return payUrl, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *AlipayPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (string, string, float64, string, string, error) {
|
func (pp *AlipayPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
|
||||||
bm, err := alipay.ParseNotifyToBodyMap(request)
|
bm, err := alipay.ParseNotifyToBodyMap(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", 0, "", "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
providerName := bm.Get("providerName")
|
providerName := bm.Get("providerName")
|
||||||
@ -82,13 +81,21 @@ func (pp *AlipayPaymentProvider) Notify(request *http.Request, body []byte, auth
|
|||||||
|
|
||||||
ok, err := alipay.VerifySignWithCert(authorityPublicKey, bm)
|
ok, err := alipay.VerifySignWithCert(authorityPublicKey, bm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", 0, "", "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", "", 0, "", "", fmt.Errorf("VerifySignWithCert() failed: %v", ok)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
notifyResult := &NotifyResult{
|
||||||
return productDisplayName, paymentName, price, productName, providerName, nil
|
ProductName: productName,
|
||||||
|
ProductDisplayName: productDisplayName,
|
||||||
|
ProviderName: providerName,
|
||||||
|
OutOrderId: orderId,
|
||||||
|
PaymentStatus: PaymentStatePaid,
|
||||||
|
Price: price,
|
||||||
|
PaymentName: paymentName,
|
||||||
|
}
|
||||||
|
return notifyResult, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *AlipayPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {
|
func (pp *AlipayPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {
|
||||||
|
@ -31,8 +31,10 @@ func (pp *DummyPaymentProvider) Pay(providerName string, productName string, pay
|
|||||||
return payUrl, "", nil
|
return payUrl, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *DummyPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (string, string, float64, string, string, error) {
|
func (pp *DummyPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
|
||||||
return "", "", 0, "", "", nil
|
return &NotifyResult{
|
||||||
|
PaymentStatus: PaymentStatePaid,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *DummyPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {
|
func (pp *DummyPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {
|
||||||
|
22
pp/gc.go
22
pp/gc.go
@ -216,11 +216,11 @@ func (pp *GcPaymentProvider) Pay(providerName string, productName string, payerN
|
|||||||
return payRespInfo.PayUrl, "", nil
|
return payRespInfo.PayUrl, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *GcPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (string, string, float64, string, string, error) {
|
func (pp *GcPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
|
||||||
reqBody := GcRequestBody{}
|
reqBody := GcRequestBody{}
|
||||||
m, err := url.ParseQuery(string(body))
|
m, err := url.ParseQuery(string(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", 0, "", "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
reqBody.Op = m["op"][0]
|
reqBody.Op = m["op"][0]
|
||||||
@ -232,13 +232,13 @@ func (pp *GcPaymentProvider) Notify(request *http.Request, body []byte, authorit
|
|||||||
|
|
||||||
notifyReqInfoBytes, err := base64.StdEncoding.DecodeString(reqBody.Data)
|
notifyReqInfoBytes, err := base64.StdEncoding.DecodeString(reqBody.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", 0, "", "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var notifyRespInfo GcNotifyRespInfo
|
var notifyRespInfo GcNotifyRespInfo
|
||||||
err = json.Unmarshal(notifyReqInfoBytes, ¬ifyRespInfo)
|
err = json.Unmarshal(notifyReqInfoBytes, ¬ifyRespInfo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", 0, "", "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
providerName := ""
|
providerName := ""
|
||||||
@ -249,10 +249,18 @@ func (pp *GcPaymentProvider) Notify(request *http.Request, body []byte, authorit
|
|||||||
price := notifyRespInfo.Amount
|
price := notifyRespInfo.Amount
|
||||||
|
|
||||||
if notifyRespInfo.OrderState != "1" {
|
if notifyRespInfo.OrderState != "1" {
|
||||||
return "", "", 0, "", "", fmt.Errorf("error order state: %s", notifyRespInfo.OrderDate)
|
return nil, fmt.Errorf("error order state: %s", notifyRespInfo.OrderDate)
|
||||||
}
|
}
|
||||||
|
notifyResult := &NotifyResult{
|
||||||
return productDisplayName, paymentName, price, productName, providerName, nil
|
ProductName: productName,
|
||||||
|
ProductDisplayName: productDisplayName,
|
||||||
|
ProviderName: providerName,
|
||||||
|
OutOrderId: orderId,
|
||||||
|
Price: price,
|
||||||
|
PaymentStatus: PaymentStatePaid,
|
||||||
|
PaymentName: paymentName,
|
||||||
|
}
|
||||||
|
return notifyResult, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *GcPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {
|
func (pp *GcPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {
|
||||||
|
88
pp/paypal.go
88
pp/paypal.go
@ -20,6 +20,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/casdoor/casdoor/conf"
|
||||||
|
|
||||||
"github.com/go-pay/gopay"
|
"github.com/go-pay/gopay"
|
||||||
"github.com/go-pay/gopay/paypal"
|
"github.com/go-pay/gopay/paypal"
|
||||||
"github.com/go-pay/gopay/pkg/util"
|
"github.com/go-pay/gopay/pkg/util"
|
||||||
@ -31,8 +33,14 @@ type PaypalPaymentProvider struct {
|
|||||||
|
|
||||||
func NewPaypalPaymentProvider(clientID string, secret string) (*PaypalPaymentProvider, error) {
|
func NewPaypalPaymentProvider(clientID string, secret string) (*PaypalPaymentProvider, error) {
|
||||||
pp := &PaypalPaymentProvider{}
|
pp := &PaypalPaymentProvider{}
|
||||||
|
isProd := false
|
||||||
client, err := paypal.NewClient(clientID, secret, false)
|
if conf.GetConfigString("runmode") == "prod" {
|
||||||
|
isProd = true
|
||||||
|
}
|
||||||
|
client, err := paypal.NewClient(clientID, secret, isProd)
|
||||||
|
//if !isProd {
|
||||||
|
// client.DebugSwitch = gopay.DebugOn
|
||||||
|
//}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -42,27 +50,27 @@ func NewPaypalPaymentProvider(clientID string, secret string) (*PaypalPaymentPro
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pp *PaypalPaymentProvider) Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, currency string, returnUrl string, notifyUrl string) (string, string, error) {
|
func (pp *PaypalPaymentProvider) 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 // Set log to terminal stdout
|
// https://github.com/go-pay/gopay/blob/main/doc/paypal.md
|
||||||
|
|
||||||
priceStr := strconv.FormatFloat(price, 'f', 2, 64)
|
priceStr := strconv.FormatFloat(price, 'f', 2, 64)
|
||||||
var pus []*paypal.PurchaseUnit
|
units := make([]*paypal.PurchaseUnit, 0, 1)
|
||||||
item := &paypal.PurchaseUnit{
|
unit := &paypal.PurchaseUnit{
|
||||||
ReferenceId: util.GetRandomString(16),
|
ReferenceId: util.GetRandomString(16),
|
||||||
Amount: &paypal.Amount{
|
Amount: &paypal.Amount{
|
||||||
CurrencyCode: currency,
|
CurrencyCode: currency, // e.g."USD"
|
||||||
Value: priceStr,
|
Value: priceStr, // e.g."100.00"
|
||||||
},
|
},
|
||||||
Description: joinAttachString([]string{productDisplayName, productName, providerName}),
|
Description: joinAttachString([]string{productDisplayName, productName, providerName}),
|
||||||
}
|
}
|
||||||
pus = append(pus, item)
|
units = append(units, unit)
|
||||||
|
|
||||||
bm := make(gopay.BodyMap)
|
bm := make(gopay.BodyMap)
|
||||||
bm.Set("intent", "CAPTURE")
|
bm.Set("intent", "CAPTURE")
|
||||||
bm.Set("purchase_units", pus)
|
bm.Set("purchase_units", units)
|
||||||
bm.SetBodyMap("application_context", func(b gopay.BodyMap) {
|
bm.SetBodyMap("application_context", func(b gopay.BodyMap) {
|
||||||
b.Set("brand_name", "Casdoor")
|
b.Set("brand_name", "Casdoor")
|
||||||
b.Set("locale", "en-PT")
|
b.Set("locale", "en-PT")
|
||||||
b.Set("return_url", returnUrl)
|
b.Set("return_url", returnUrl)
|
||||||
|
b.Set("cancel_url", returnUrl)
|
||||||
})
|
})
|
||||||
|
|
||||||
ppRsp, err := pp.Client.CreateOrder(context.Background(), bm)
|
ppRsp, err := pp.Client.CreateOrder(context.Background(), bm)
|
||||||
@ -72,31 +80,65 @@ func (pp *PaypalPaymentProvider) Pay(providerName string, productName string, pa
|
|||||||
if ppRsp.Code != paypal.Success {
|
if ppRsp.Code != paypal.Success {
|
||||||
return "", "", errors.New(ppRsp.Error)
|
return "", "", errors.New(ppRsp.Error)
|
||||||
}
|
}
|
||||||
|
// {"id":"9BR68863NE220374S","status":"CREATED",
|
||||||
|
// "links":[{"href":"https://api.sandbox.paypal.com/v2/checkout/orders/9BR68863NE220374S","rel":"self","method":"GET"},
|
||||||
|
// {"href":"https://www.sandbox.paypal.com/checkoutnow?token=9BR68863NE220374S","rel":"approve","method":"GET"},
|
||||||
|
// {"href":"https://api.sandbox.paypal.com/v2/checkout/orders/9BR68863NE220374S","rel":"update","method":"PATCH"},
|
||||||
|
// {"href":"https://api.sandbox.paypal.com/v2/checkout/orders/9BR68863NE220374S/capture","rel":"capture","method":"POST"}]}
|
||||||
return ppRsp.Response.Links[1].Href, ppRsp.Response.Id, nil
|
return ppRsp.Response.Links[1].Href, ppRsp.Response.Id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *PaypalPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (string, string, float64, string, string, error) {
|
func (pp *PaypalPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
|
||||||
ppRsp, err := pp.Client.OrderCapture(context.Background(), orderId, nil)
|
captureRsp, err := pp.Client.OrderCapture(context.Background(), orderId, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", 0, "", "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
if ppRsp.Code != paypal.Success {
|
if captureRsp.Code != paypal.Success {
|
||||||
return "", "", 0, "", "", errors.New(ppRsp.Error)
|
// If order is already captured, just skip this type of error and check the order detail
|
||||||
|
if !(len(captureRsp.ErrorResponse.Details) == 1 && captureRsp.ErrorResponse.Details[0].Issue == "ORDER_ALREADY_CAPTURED") {
|
||||||
|
return nil, errors.New(captureRsp.ErrorResponse.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check the order detail
|
||||||
|
detailRsp, err := pp.Client.OrderDetail(context.Background(), orderId, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if captureRsp.Code != paypal.Success {
|
||||||
|
return nil, errors.New(captureRsp.ErrorResponse.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
paymentName := ppRsp.Response.Id
|
paymentName := detailRsp.Response.Id
|
||||||
price, err := strconv.ParseFloat(ppRsp.Response.PurchaseUnits[0].Amount.Value, 64)
|
price, err := strconv.ParseFloat(detailRsp.Response.PurchaseUnits[0].Amount.Value, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", 0, "", "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
currency := detailRsp.Response.PurchaseUnits[0].Amount.CurrencyCode
|
||||||
productDisplayName, productName, providerName, err := parseAttachString(ppRsp.Response.PurchaseUnits[0].Description)
|
productDisplayName, productName, providerName, err := parseAttachString(detailRsp.Response.PurchaseUnits[0].Description)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", 0, "", "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
// TODO: status better handler, e.g.`hanging`
|
||||||
|
var paymentStatus PaymentState
|
||||||
|
switch detailRsp.Response.Status { // CREATED、SAVED、APPROVED、VOIDED、COMPLETED、PAYER_ACTION_REQUIRED
|
||||||
|
case "COMPLETED":
|
||||||
|
paymentStatus = PaymentStatePaid
|
||||||
|
default:
|
||||||
|
paymentStatus = PaymentStateError
|
||||||
|
}
|
||||||
|
notifyResult := &NotifyResult{
|
||||||
|
PaymentStatus: paymentStatus,
|
||||||
|
PaymentName: paymentName,
|
||||||
|
|
||||||
return productDisplayName, paymentName, price, productName, providerName, nil
|
ProductName: productName,
|
||||||
|
ProductDisplayName: productDisplayName,
|
||||||
|
ProviderName: providerName,
|
||||||
|
Price: price,
|
||||||
|
Currency: currency,
|
||||||
|
|
||||||
|
OutOrderId: orderId,
|
||||||
|
}
|
||||||
|
return notifyResult, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *PaypalPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {
|
func (pp *PaypalPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {
|
||||||
|
@ -14,11 +14,34 @@
|
|||||||
|
|
||||||
package pp
|
package pp
|
||||||
|
|
||||||
import "net/http"
|
import (
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PaymentState string
|
||||||
|
|
||||||
|
const (
|
||||||
|
PaymentStatePaid PaymentState = "Paid"
|
||||||
|
PaymentStateCreated PaymentState = "Created"
|
||||||
|
PaymentStateError PaymentState = "Error"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NotifyResult struct {
|
||||||
|
PaymentName string
|
||||||
|
PaymentStatus PaymentState
|
||||||
|
ProviderName string
|
||||||
|
|
||||||
|
ProductName string
|
||||||
|
ProductDisplayName string
|
||||||
|
Price float64
|
||||||
|
Currency string
|
||||||
|
|
||||||
|
OutOrderId string
|
||||||
|
}
|
||||||
|
|
||||||
type PaymentProvider interface {
|
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)
|
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) (string, string, float64, string, string, error)
|
Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error)
|
||||||
GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error)
|
GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error)
|
||||||
GetResponseError(err error) string
|
GetResponseError(err error) string
|
||||||
}
|
}
|
||||||
|
@ -83,22 +83,22 @@ func (pp *WechatPaymentProvider) Pay(providerName string, productName string, pa
|
|||||||
return wxRsp.Response.CodeUrl, "", nil
|
return wxRsp.Response.CodeUrl, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *WechatPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (string, string, float64, string, string, error) {
|
func (pp *WechatPaymentProvider) Notify(request *http.Request, body []byte, authorityPublicKey string, orderId string) (*NotifyResult, error) {
|
||||||
notifyReq, err := wechat.V3ParseNotify(request)
|
notifyReq, err := wechat.V3ParseNotify(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cert := pp.Client.WxPublicKey()
|
cert := pp.Client.WxPublicKey()
|
||||||
err = notifyReq.VerifySignByPK(cert)
|
err = notifyReq.VerifySignByPK(cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", 0, "", "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
apiKey := string(pp.Client.ApiV3Key)
|
apiKey := string(pp.Client.ApiV3Key)
|
||||||
result, err := notifyReq.DecryptCipherText(apiKey)
|
result, err := notifyReq.DecryptCipherText(apiKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", 0, "", "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paymentName := result.OutTradeNo
|
paymentName := result.OutTradeNo
|
||||||
@ -106,10 +106,19 @@ func (pp *WechatPaymentProvider) Notify(request *http.Request, body []byte, auth
|
|||||||
|
|
||||||
productDisplayName, productName, providerName, err := parseAttachString(result.Attach)
|
productDisplayName, productName, providerName, err := parseAttachString(result.Attach)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", 0, "", "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return productDisplayName, paymentName, price, productName, providerName, nil
|
notifyResult := &NotifyResult{
|
||||||
|
ProductName: productName,
|
||||||
|
ProductDisplayName: productDisplayName,
|
||||||
|
ProviderName: providerName,
|
||||||
|
OutOrderId: orderId,
|
||||||
|
Price: price,
|
||||||
|
PaymentStatus: PaymentStatePaid,
|
||||||
|
PaymentName: paymentName,
|
||||||
|
}
|
||||||
|
return notifyResult, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pp *WechatPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {
|
func (pp *WechatPaymentProvider) GetInvoice(paymentName string, personName string, personIdCard string, personEmail string, personPhone string, invoiceType string, invoiceTitle string, invoiceTaxId string) (string, error) {
|
||||||
|
@ -255,7 +255,7 @@ func initAPI() {
|
|||||||
beego.Router("/api/update-payment", &controllers.ApiController{}, "POST:UpdatePayment")
|
beego.Router("/api/update-payment", &controllers.ApiController{}, "POST:UpdatePayment")
|
||||||
beego.Router("/api/add-payment", &controllers.ApiController{}, "POST:AddPayment")
|
beego.Router("/api/add-payment", &controllers.ApiController{}, "POST:AddPayment")
|
||||||
beego.Router("/api/delete-payment", &controllers.ApiController{}, "POST:DeletePayment")
|
beego.Router("/api/delete-payment", &controllers.ApiController{}, "POST:DeletePayment")
|
||||||
beego.Router("/api/notify-payment/?:owner/?:provider/?:product/?:payment", &controllers.ApiController{}, "POST:NotifyPayment")
|
beego.Router("/api/notify-payment/?:owner/?:payment", &controllers.ApiController{}, "POST:NotifyPayment")
|
||||||
beego.Router("/api/invoice-payment", &controllers.ApiController{}, "POST:InvoicePayment")
|
beego.Router("/api/invoice-payment", &controllers.ApiController{}, "POST:InvoicePayment")
|
||||||
|
|
||||||
beego.Router("/api/send-email", &controllers.ApiController{}, "POST:SendEmail")
|
beego.Router("/api/send-email", &controllers.ApiController{}, "POST:SendEmail")
|
||||||
|
@ -643,8 +643,8 @@ class App extends Component {
|
|||||||
<Route exact path="/products/:organizationName/:productName" render={(props) => this.renderLoginIfNotLoggedIn(<ProductEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/products/:organizationName/:productName" render={(props) => this.renderLoginIfNotLoggedIn(<ProductEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/products/:organizationName/:productName/buy" render={(props) => this.renderLoginIfNotLoggedIn(<ProductBuyPage account={this.state.account} {...props} />)} />
|
<Route exact path="/products/:organizationName/:productName/buy" render={(props) => this.renderLoginIfNotLoggedIn(<ProductBuyPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/payments" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/payments" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/payments/:paymentName" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentEditPage account={this.state.account} {...props} />)} />
|
<Route exact path="/payments/:organizationName/:paymentName" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentEditPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/payments/:paymentName/result" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentResultPage account={this.state.account} {...props} />)} />
|
<Route exact path="/payments/:organizationName/:paymentName/result" render={(props) => this.renderLoginIfNotLoggedIn(<PaymentResultPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/records" render={(props) => this.renderLoginIfNotLoggedIn(<RecordListPage account={this.state.account} {...props} />)} />
|
<Route exact path="/records" render={(props) => this.renderLoginIfNotLoggedIn(<RecordListPage account={this.state.account} {...props} />)} />
|
||||||
<Route exact path="/mfa/setup" render={(props) => this.renderLoginIfNotLoggedIn(<MfaSetupPage account={this.state.account} onfinish={() => this.setState({requiredEnableMfa: false})} {...props} />)} />
|
<Route exact path="/mfa/setup" render={(props) => this.renderLoginIfNotLoggedIn(<MfaSetupPage account={this.state.account} onfinish={() => this.setState({requiredEnableMfa: false})} {...props} />)} />
|
||||||
<Route exact path="/.well-known/openid-configuration" render={(props) => <OdicDiscoveryPage />} />
|
<Route exact path="/.well-known/openid-configuration" render={(props) => <OdicDiscoveryPage />} />
|
||||||
|
@ -40,7 +40,7 @@ class PaymentEditPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getPayment() {
|
getPayment() {
|
||||||
PaymentBackend.getPayment("admin", this.state.paymentName)
|
PaymentBackend.getPayment(this.state.organizationName, this.state.paymentName)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.data === null) {
|
if (res.data === null) {
|
||||||
this.props.history.push("/404");
|
this.props.history.push("/404");
|
||||||
|
@ -28,13 +28,12 @@ class PaymentListPage extends BaseListPage {
|
|||||||
const randomName = Setting.getRandomName();
|
const randomName = Setting.getRandomName();
|
||||||
const organizationName = Setting.getRequestOrganization(this.props.account);
|
const organizationName = Setting.getRequestOrganization(this.props.account);
|
||||||
return {
|
return {
|
||||||
owner: "admin",
|
owner: organizationName,
|
||||||
name: `payment_${randomName}`,
|
name: `payment_${randomName}`,
|
||||||
createdTime: moment().format(),
|
createdTime: moment().format(),
|
||||||
displayName: `New Payment - ${randomName}`,
|
displayName: `New Payment - ${randomName}`,
|
||||||
provider: "provider_pay_paypal",
|
provider: "provider_pay_paypal",
|
||||||
type: "PayPal",
|
type: "PayPal",
|
||||||
organization: organizationName,
|
|
||||||
user: "admin",
|
user: "admin",
|
||||||
productName: "computer-1",
|
productName: "computer-1",
|
||||||
productDisplayName: "A notebook computer",
|
productDisplayName: "A notebook computer",
|
||||||
@ -54,7 +53,7 @@ class PaymentListPage extends BaseListPage {
|
|||||||
PaymentBackend.addPayment(newPayment)
|
PaymentBackend.addPayment(newPayment)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === "ok") {
|
if (res.status === "ok") {
|
||||||
this.props.history.push({pathname: `/payments/${newPayment.name}`, mode: "add"});
|
this.props.history.push({pathname: `/payments/${newPayment.owner}/${newPayment.name}`, mode: "add"});
|
||||||
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
Setting.showMessage("success", i18next.t("general:Successfully added"));
|
||||||
} else {
|
} else {
|
||||||
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
Setting.showMessage("error", `${i18next.t("general:Failed to add")}: ${res.msg}`);
|
||||||
@ -96,7 +95,7 @@ class PaymentListPage extends BaseListPage {
|
|||||||
...this.getColumnSearchProps("name"),
|
...this.getColumnSearchProps("name"),
|
||||||
render: (text, record, index) => {
|
render: (text, record, index) => {
|
||||||
return (
|
return (
|
||||||
<Link to={`/payments/${text}`}>
|
<Link to={`/payments/${record.owner}/${text}`}>
|
||||||
{text}
|
{text}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
@ -112,7 +111,7 @@ class PaymentListPage extends BaseListPage {
|
|||||||
...this.getColumnSearchProps("provider"),
|
...this.getColumnSearchProps("provider"),
|
||||||
render: (text, record, index) => {
|
render: (text, record, index) => {
|
||||||
return (
|
return (
|
||||||
<Link to={`/providers/${text}`}>
|
<Link to={`/providers/${record.owner}/${text}`}>
|
||||||
{text}
|
{text}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
@ -120,11 +119,11 @@ class PaymentListPage extends BaseListPage {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: i18next.t("general:Organization"),
|
title: i18next.t("general:Organization"),
|
||||||
dataIndex: "organization",
|
dataIndex: "owner",
|
||||||
key: "organization",
|
key: "owner",
|
||||||
width: "120px",
|
width: "120px",
|
||||||
sorter: true,
|
sorter: true,
|
||||||
...this.getColumnSearchProps("organization"),
|
...this.getColumnSearchProps("owner"),
|
||||||
render: (text, record, index) => {
|
render: (text, record, index) => {
|
||||||
return (
|
return (
|
||||||
<Link to={`/organizations/${text}`}>
|
<Link to={`/organizations/${text}`}>
|
||||||
@ -142,7 +141,7 @@ class PaymentListPage extends BaseListPage {
|
|||||||
...this.getColumnSearchProps("user"),
|
...this.getColumnSearchProps("user"),
|
||||||
render: (text, record, index) => {
|
render: (text, record, index) => {
|
||||||
return (
|
return (
|
||||||
<Link to={`/users/${record.organization}/${text}`}>
|
<Link to={`/users/${record.owner}/${text}`}>
|
||||||
{text}
|
{text}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
@ -222,8 +221,8 @@ class PaymentListPage extends BaseListPage {
|
|||||||
render: (text, record, index) => {
|
render: (text, record, index) => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} onClick={() => this.props.history.push(`/payments/${record.name}/result`)}>{i18next.t("payment:Result")}</Button>
|
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} onClick={() => this.props.history.push(`/payments/${record.owner}/${record.name}/result`)}>{i18next.t("payment:Result")}</Button>
|
||||||
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/payments/${record.name}`)}>{i18next.t("general:Edit")}</Button>
|
<Button style={{marginTop: "10px", marginBottom: "10px", marginRight: "10px"}} type="primary" onClick={() => this.props.history.push(`/payments/${record.owner}/${record.name}`)}>{i18next.t("general:Edit")}</Button>
|
||||||
<PopconfirmModal
|
<PopconfirmModal
|
||||||
title={i18next.t("general:Sure to delete") + `: ${record.name} ?`}
|
title={i18next.t("general:Sure to delete") + `: ${record.name} ?`}
|
||||||
onConfirm={() => this.deletePayment(index)}
|
onConfirm={() => this.deletePayment(index)}
|
||||||
@ -266,7 +265,7 @@ class PaymentListPage extends BaseListPage {
|
|||||||
value = params.type;
|
value = params.type;
|
||||||
}
|
}
|
||||||
this.setState({loading: true});
|
this.setState({loading: true});
|
||||||
PaymentBackend.getPayments("admin", Setting.isDefaultOrganizationSelected(this.props.account) ? "" : Setting.getRequestOrganization(this.props.account), params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
PaymentBackend.getPayments(Setting.getRequestOrganization(this.props.account), Setting.isDefaultOrganizationSelected(this.props.account) ? "" : Setting.getRequestOrganization(this.props.account), params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
|
@ -24,6 +24,7 @@ class PaymentResultPage extends React.Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
classes: props,
|
classes: props,
|
||||||
paymentName: props.match.params.paymentName,
|
paymentName: props.match.params.paymentName,
|
||||||
|
organizationName: props.match.params.organizationName,
|
||||||
payment: null,
|
payment: null,
|
||||||
timeout: null,
|
timeout: null,
|
||||||
};
|
};
|
||||||
@ -40,18 +41,37 @@ class PaymentResultPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getPayment() {
|
getPayment() {
|
||||||
PaymentBackend.getPayment("admin", this.state.paymentName)
|
PaymentBackend.getPayment(this.state.organizationName, this.state.paymentName)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
payment: res.data,
|
payment: res.data,
|
||||||
});
|
});
|
||||||
|
// window.console.log("payment=", res.data);
|
||||||
if (res.data.state === "Created") {
|
if (res.data.state === "Created") {
|
||||||
this.setState({timeout: setTimeout(() => this.getPayment(), 1000)});
|
if (res.data.type === "PayPal") {
|
||||||
|
this.setState({
|
||||||
|
timeout: setTimeout(() => {
|
||||||
|
PaymentBackend.notifyPayment(this.state.organizationName, this.state.paymentName)
|
||||||
|
.then((res) => {
|
||||||
|
this.getPayment();
|
||||||
|
});
|
||||||
|
}, 1000),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({timeout: setTimeout(() => this.getPayment(), 1000)});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goToPaymentUrl(payment) {
|
||||||
|
if (payment.returnUrl === undefined || payment.returnUrl === null || payment.returnUrl === "") {
|
||||||
|
Setting.goToLink(`${window.location.origin}/products/${payment.owner}/${payment.productName}/buy`);
|
||||||
|
} else {
|
||||||
|
Setting.goToLink(payment.returnUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const payment = this.state.payment;
|
const payment = this.state.payment;
|
||||||
|
|
||||||
@ -71,7 +91,7 @@ class PaymentResultPage extends React.Component {
|
|||||||
subTitle={i18next.t("payment:Please click the below button to return to the original website")}
|
subTitle={i18next.t("payment:Please click the below button to return to the original website")}
|
||||||
extra={[
|
extra={[
|
||||||
<Button type="primary" key="returnUrl" onClick={() => {
|
<Button type="primary" key="returnUrl" onClick={() => {
|
||||||
Setting.goToLink(payment.returnUrl);
|
this.goToPaymentUrl(payment);
|
||||||
}}>
|
}}>
|
||||||
{i18next.t("payment:Return to Website")}
|
{i18next.t("payment:Return to Website")}
|
||||||
</Button>,
|
</Button>,
|
||||||
@ -107,7 +127,7 @@ class PaymentResultPage extends React.Component {
|
|||||||
subTitle={i18next.t("payment:Please click the below button to return to the original website")}
|
subTitle={i18next.t("payment:Please click the below button to return to the original website")}
|
||||||
extra={[
|
extra={[
|
||||||
<Button type="primary" key="returnUrl" onClick={() => {
|
<Button type="primary" key="returnUrl" onClick={() => {
|
||||||
Setting.goToLink(payment.returnUrl);
|
this.goToPaymentUrl(payment);
|
||||||
}}>
|
}}>
|
||||||
{i18next.t("payment:Return to Website")}
|
{i18next.t("payment:Return to Website")}
|
||||||
</Button>,
|
</Button>,
|
||||||
|
@ -24,7 +24,8 @@ class ProductBuyPage extends React.Component {
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
classes: props,
|
classes: props,
|
||||||
productName: props.match?.params.productName,
|
organizationName: props.organizationName !== undefined ? props.organizationName : props?.match?.params?.organizationName,
|
||||||
|
productName: props.productName !== undefined ? props.productName : props?.match?.params?.productName,
|
||||||
product: null,
|
product: null,
|
||||||
isPlacingOrder: false,
|
isPlacingOrder: false,
|
||||||
qrCodeModalProvider: null,
|
qrCodeModalProvider: null,
|
||||||
@ -36,17 +37,15 @@ class ProductBuyPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getProduct() {
|
getProduct() {
|
||||||
if (this.state.productName === undefined) {
|
if (this.state.productName === undefined || this.state.organizationName === undefined) {
|
||||||
return;
|
return ;
|
||||||
}
|
}
|
||||||
|
ProductBackend.getProduct(this.state.organizationName, this.state.productName)
|
||||||
ProductBackend.getProduct(this.props.account.owner, this.state.productName)
|
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === "error") {
|
if (res.status === "error") {
|
||||||
Setting.showMessage("error", res.msg);
|
Setting.showMessage("error", res.msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
product: res.data,
|
product: res.data,
|
||||||
});
|
});
|
||||||
@ -97,7 +96,7 @@ class ProductBuyPage extends React.Component {
|
|||||||
isPlacingOrder: true,
|
isPlacingOrder: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
ProductBackend.buyProduct(this.state.product.owner, this.state.productName, provider.name)
|
ProductBackend.buyProduct(product.owner, product.name, provider.name)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === "ok") {
|
if (res.status === "ok") {
|
||||||
const payUrl = res.data;
|
const payUrl = res.data;
|
||||||
|
@ -102,6 +102,13 @@ class ProductListPage extends BaseListPage {
|
|||||||
width: "150px",
|
width: "150px",
|
||||||
sorter: true,
|
sorter: true,
|
||||||
...this.getColumnSearchProps("owner"),
|
...this.getColumnSearchProps("owner"),
|
||||||
|
render: (text, record, index) => {
|
||||||
|
return (
|
||||||
|
<Link to={`/organizations/${text}`}>
|
||||||
|
{text}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: i18next.t("general:Created time"),
|
title: i18next.t("general:Created time"),
|
||||||
@ -189,6 +196,7 @@ class ProductListPage extends BaseListPage {
|
|||||||
width: "500px",
|
width: "500px",
|
||||||
...this.getColumnSearchProps("providers"),
|
...this.getColumnSearchProps("providers"),
|
||||||
render: (text, record, index) => {
|
render: (text, record, index) => {
|
||||||
|
const providerOwner = record.owner;
|
||||||
const providers = text;
|
const providers = text;
|
||||||
if (providers.length === 0) {
|
if (providers.length === 0) {
|
||||||
return `(${i18next.t("general:empty")})`;
|
return `(${i18next.t("general:empty")})`;
|
||||||
@ -207,9 +215,9 @@ class ProductListPage extends BaseListPage {
|
|||||||
<List.Item>
|
<List.Item>
|
||||||
<div style={{display: "inline"}}>
|
<div style={{display: "inline"}}>
|
||||||
<Tooltip placement="topLeft" title="Edit">
|
<Tooltip placement="topLeft" title="Edit">
|
||||||
<Button style={{marginRight: "5px"}} icon={<EditOutlined />} size="small" onClick={() => Setting.goToLinkSoft(this, `/providers/${providerName}`)} />
|
<Button style={{marginRight: "5px"}} icon={<EditOutlined />} size="small" onClick={() => Setting.goToLinkSoft(this, `/providers/${providerOwner}/${providerName}`)} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Link to={`/providers/${providerName}`}>
|
<Link to={`/providers/${providerOwner}/${providerName}`}>
|
||||||
{providerName}
|
{providerName}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
@ -79,3 +79,13 @@ export function invoicePayment(owner, name) {
|
|||||||
},
|
},
|
||||||
}).then(res => res.json());
|
}).then(res => res.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function notifyPayment(owner, name) {
|
||||||
|
return fetch(`${Setting.ServerUrl}/api/notify-payment/${owner}/${name}`, {
|
||||||
|
method: "POST",
|
||||||
|
credentials: "include",
|
||||||
|
headers: {
|
||||||
|
"Accept-Language": Setting.getAcceptLanguage(),
|
||||||
|
},
|
||||||
|
}).then(res => res.json());
|
||||||
|
}
|
||||||
|
@ -152,6 +152,10 @@
|
|||||||
"Sending": "Sendet",
|
"Sending": "Sendet",
|
||||||
"Submit and complete": "Einreichen und abschließen"
|
"Submit and complete": "Einreichen und abschließen"
|
||||||
},
|
},
|
||||||
|
"enforcer": {
|
||||||
|
"Edit Enforcer": "Edit Enforcer",
|
||||||
|
"New Enforcer": "New Enforcer"
|
||||||
|
},
|
||||||
"forget": {
|
"forget": {
|
||||||
"Account": "Konto",
|
"Account": "Konto",
|
||||||
"Change Password": "Passwort ändern",
|
"Change Password": "Passwort ändern",
|
||||||
@ -215,6 +219,7 @@
|
|||||||
"Enable": "Enable",
|
"Enable": "Enable",
|
||||||
"Enabled": "Enabled",
|
"Enabled": "Enabled",
|
||||||
"Enabled successfully": "Enabled successfully",
|
"Enabled successfully": "Enabled successfully",
|
||||||
|
"Enforcers": "Enforcers",
|
||||||
"Failed to add": "Fehler beim hinzufügen",
|
"Failed to add": "Fehler beim hinzufügen",
|
||||||
"Failed to connect to server": "Die Verbindung zum Server konnte nicht hergestellt werden",
|
"Failed to connect to server": "Die Verbindung zum Server konnte nicht hergestellt werden",
|
||||||
"Failed to delete": "Konnte nicht gelöscht werden",
|
"Failed to delete": "Konnte nicht gelöscht werden",
|
||||||
|
@ -152,6 +152,10 @@
|
|||||||
"Sending": "Sending",
|
"Sending": "Sending",
|
||||||
"Submit and complete": "Submit and complete"
|
"Submit and complete": "Submit and complete"
|
||||||
},
|
},
|
||||||
|
"enforcer": {
|
||||||
|
"Edit Enforcer": "Edit Enforcer",
|
||||||
|
"New Enforcer": "New Enforcer"
|
||||||
|
},
|
||||||
"forget": {
|
"forget": {
|
||||||
"Account": "Account",
|
"Account": "Account",
|
||||||
"Change Password": "Change Password",
|
"Change Password": "Change Password",
|
||||||
@ -215,6 +219,7 @@
|
|||||||
"Enable": "Enable",
|
"Enable": "Enable",
|
||||||
"Enabled": "Enabled",
|
"Enabled": "Enabled",
|
||||||
"Enabled successfully": "Enabled successfully",
|
"Enabled successfully": "Enabled successfully",
|
||||||
|
"Enforcers": "Enforcers",
|
||||||
"Failed to add": "Failed to add",
|
"Failed to add": "Failed to add",
|
||||||
"Failed to connect to server": "Failed to connect to server",
|
"Failed to connect to server": "Failed to connect to server",
|
||||||
"Failed to delete": "Failed to delete",
|
"Failed to delete": "Failed to delete",
|
||||||
|
@ -152,6 +152,10 @@
|
|||||||
"Sending": "Envío",
|
"Sending": "Envío",
|
||||||
"Submit and complete": "Enviar y completar"
|
"Submit and complete": "Enviar y completar"
|
||||||
},
|
},
|
||||||
|
"enforcer": {
|
||||||
|
"Edit Enforcer": "Edit Enforcer",
|
||||||
|
"New Enforcer": "New Enforcer"
|
||||||
|
},
|
||||||
"forget": {
|
"forget": {
|
||||||
"Account": "Cuenta",
|
"Account": "Cuenta",
|
||||||
"Change Password": "Cambiar contraseña",
|
"Change Password": "Cambiar contraseña",
|
||||||
@ -215,6 +219,7 @@
|
|||||||
"Enable": "Enable",
|
"Enable": "Enable",
|
||||||
"Enabled": "Enabled",
|
"Enabled": "Enabled",
|
||||||
"Enabled successfully": "Enabled successfully",
|
"Enabled successfully": "Enabled successfully",
|
||||||
|
"Enforcers": "Enforcers",
|
||||||
"Failed to add": "No se pudo agregar",
|
"Failed to add": "No se pudo agregar",
|
||||||
"Failed to connect to server": "No se pudo conectar al servidor",
|
"Failed to connect to server": "No se pudo conectar al servidor",
|
||||||
"Failed to delete": "No se pudo eliminar",
|
"Failed to delete": "No se pudo eliminar",
|
||||||
|
@ -152,6 +152,10 @@
|
|||||||
"Sending": "Envoi",
|
"Sending": "Envoi",
|
||||||
"Submit and complete": "Soumettre et compléter"
|
"Submit and complete": "Soumettre et compléter"
|
||||||
},
|
},
|
||||||
|
"enforcer": {
|
||||||
|
"Edit Enforcer": "Edit Enforcer",
|
||||||
|
"New Enforcer": "New Enforcer"
|
||||||
|
},
|
||||||
"forget": {
|
"forget": {
|
||||||
"Account": "Compte",
|
"Account": "Compte",
|
||||||
"Change Password": "Changer le mot de passe",
|
"Change Password": "Changer le mot de passe",
|
||||||
@ -215,6 +219,7 @@
|
|||||||
"Enable": "Enable",
|
"Enable": "Enable",
|
||||||
"Enabled": "Enabled",
|
"Enabled": "Enabled",
|
||||||
"Enabled successfully": "Enabled successfully",
|
"Enabled successfully": "Enabled successfully",
|
||||||
|
"Enforcers": "Enforcers",
|
||||||
"Failed to add": "Échec d'ajout",
|
"Failed to add": "Échec d'ajout",
|
||||||
"Failed to connect to server": "Échec de la connexion au serveur",
|
"Failed to connect to server": "Échec de la connexion au serveur",
|
||||||
"Failed to delete": "Échec de la suppression",
|
"Failed to delete": "Échec de la suppression",
|
||||||
|
@ -152,6 +152,10 @@
|
|||||||
"Sending": "Mengirimkan",
|
"Sending": "Mengirimkan",
|
||||||
"Submit and complete": "Kirim dan selesaikan"
|
"Submit and complete": "Kirim dan selesaikan"
|
||||||
},
|
},
|
||||||
|
"enforcer": {
|
||||||
|
"Edit Enforcer": "Edit Enforcer",
|
||||||
|
"New Enforcer": "New Enforcer"
|
||||||
|
},
|
||||||
"forget": {
|
"forget": {
|
||||||
"Account": "Akun",
|
"Account": "Akun",
|
||||||
"Change Password": "Ubah Kata Sandi",
|
"Change Password": "Ubah Kata Sandi",
|
||||||
@ -215,6 +219,7 @@
|
|||||||
"Enable": "Enable",
|
"Enable": "Enable",
|
||||||
"Enabled": "Enabled",
|
"Enabled": "Enabled",
|
||||||
"Enabled successfully": "Enabled successfully",
|
"Enabled successfully": "Enabled successfully",
|
||||||
|
"Enforcers": "Enforcers",
|
||||||
"Failed to add": "Gagal menambahkan",
|
"Failed to add": "Gagal menambahkan",
|
||||||
"Failed to connect to server": "Gagal terhubung ke server",
|
"Failed to connect to server": "Gagal terhubung ke server",
|
||||||
"Failed to delete": "Gagal menghapus",
|
"Failed to delete": "Gagal menghapus",
|
||||||
|
@ -152,6 +152,10 @@
|
|||||||
"Sending": "送信",
|
"Sending": "送信",
|
||||||
"Submit and complete": "提出して完了してください"
|
"Submit and complete": "提出して完了してください"
|
||||||
},
|
},
|
||||||
|
"enforcer": {
|
||||||
|
"Edit Enforcer": "Edit Enforcer",
|
||||||
|
"New Enforcer": "New Enforcer"
|
||||||
|
},
|
||||||
"forget": {
|
"forget": {
|
||||||
"Account": "アカウント",
|
"Account": "アカウント",
|
||||||
"Change Password": "パスワードを変更",
|
"Change Password": "パスワードを変更",
|
||||||
@ -215,6 +219,7 @@
|
|||||||
"Enable": "Enable",
|
"Enable": "Enable",
|
||||||
"Enabled": "Enabled",
|
"Enabled": "Enabled",
|
||||||
"Enabled successfully": "Enabled successfully",
|
"Enabled successfully": "Enabled successfully",
|
||||||
|
"Enforcers": "Enforcers",
|
||||||
"Failed to add": "追加できませんでした",
|
"Failed to add": "追加できませんでした",
|
||||||
"Failed to connect to server": "サーバーに接続できませんでした",
|
"Failed to connect to server": "サーバーに接続できませんでした",
|
||||||
"Failed to delete": "削除に失敗しました",
|
"Failed to delete": "削除に失敗しました",
|
||||||
|
@ -152,6 +152,10 @@
|
|||||||
"Sending": "전송하기",
|
"Sending": "전송하기",
|
||||||
"Submit and complete": "제출하고 완료하십시오"
|
"Submit and complete": "제출하고 완료하십시오"
|
||||||
},
|
},
|
||||||
|
"enforcer": {
|
||||||
|
"Edit Enforcer": "Edit Enforcer",
|
||||||
|
"New Enforcer": "New Enforcer"
|
||||||
|
},
|
||||||
"forget": {
|
"forget": {
|
||||||
"Account": "계정",
|
"Account": "계정",
|
||||||
"Change Password": "비밀번호 변경",
|
"Change Password": "비밀번호 변경",
|
||||||
@ -215,6 +219,7 @@
|
|||||||
"Enable": "Enable",
|
"Enable": "Enable",
|
||||||
"Enabled": "Enabled",
|
"Enabled": "Enabled",
|
||||||
"Enabled successfully": "Enabled successfully",
|
"Enabled successfully": "Enabled successfully",
|
||||||
|
"Enforcers": "Enforcers",
|
||||||
"Failed to add": "추가하지 못했습니다",
|
"Failed to add": "추가하지 못했습니다",
|
||||||
"Failed to connect to server": "서버에 연결하지 못했습니다",
|
"Failed to connect to server": "서버에 연결하지 못했습니다",
|
||||||
"Failed to delete": "삭제에 실패했습니다",
|
"Failed to delete": "삭제에 실패했습니다",
|
||||||
|
@ -152,6 +152,10 @@
|
|||||||
"Sending": "Enviando",
|
"Sending": "Enviando",
|
||||||
"Submit and complete": "Enviar e concluir"
|
"Submit and complete": "Enviar e concluir"
|
||||||
},
|
},
|
||||||
|
"enforcer": {
|
||||||
|
"Edit Enforcer": "Edit Enforcer",
|
||||||
|
"New Enforcer": "New Enforcer"
|
||||||
|
},
|
||||||
"forget": {
|
"forget": {
|
||||||
"Account": "Conta",
|
"Account": "Conta",
|
||||||
"Change Password": "Alterar Senha",
|
"Change Password": "Alterar Senha",
|
||||||
@ -215,6 +219,7 @@
|
|||||||
"Enable": "Habilitar",
|
"Enable": "Habilitar",
|
||||||
"Enabled": "Habilitado",
|
"Enabled": "Habilitado",
|
||||||
"Enabled successfully": "Habilitado com sucesso",
|
"Enabled successfully": "Habilitado com sucesso",
|
||||||
|
"Enforcers": "Enforcers",
|
||||||
"Failed to add": "Falha ao adicionar",
|
"Failed to add": "Falha ao adicionar",
|
||||||
"Failed to connect to server": "Falha ao conectar ao servidor",
|
"Failed to connect to server": "Falha ao conectar ao servidor",
|
||||||
"Failed to delete": "Falha ao excluir",
|
"Failed to delete": "Falha ao excluir",
|
||||||
|
@ -152,6 +152,10 @@
|
|||||||
"Sending": "Отправка",
|
"Sending": "Отправка",
|
||||||
"Submit and complete": "Отправить и завершить"
|
"Submit and complete": "Отправить и завершить"
|
||||||
},
|
},
|
||||||
|
"enforcer": {
|
||||||
|
"Edit Enforcer": "Edit Enforcer",
|
||||||
|
"New Enforcer": "New Enforcer"
|
||||||
|
},
|
||||||
"forget": {
|
"forget": {
|
||||||
"Account": "Счет",
|
"Account": "Счет",
|
||||||
"Change Password": "Изменить пароль",
|
"Change Password": "Изменить пароль",
|
||||||
@ -215,6 +219,7 @@
|
|||||||
"Enable": "Enable",
|
"Enable": "Enable",
|
||||||
"Enabled": "Enabled",
|
"Enabled": "Enabled",
|
||||||
"Enabled successfully": "Enabled successfully",
|
"Enabled successfully": "Enabled successfully",
|
||||||
|
"Enforcers": "Enforcers",
|
||||||
"Failed to add": "Не удалось добавить",
|
"Failed to add": "Не удалось добавить",
|
||||||
"Failed to connect to server": "Не удалось подключиться к серверу",
|
"Failed to connect to server": "Не удалось подключиться к серверу",
|
||||||
"Failed to delete": "Не удалось удалить",
|
"Failed to delete": "Не удалось удалить",
|
||||||
|
@ -152,6 +152,10 @@
|
|||||||
"Sending": "Gửi",
|
"Sending": "Gửi",
|
||||||
"Submit and complete": "Nộp và hoàn thành"
|
"Submit and complete": "Nộp và hoàn thành"
|
||||||
},
|
},
|
||||||
|
"enforcer": {
|
||||||
|
"Edit Enforcer": "Edit Enforcer",
|
||||||
|
"New Enforcer": "New Enforcer"
|
||||||
|
},
|
||||||
"forget": {
|
"forget": {
|
||||||
"Account": "Tài khoản",
|
"Account": "Tài khoản",
|
||||||
"Change Password": "Đổi mật khẩu",
|
"Change Password": "Đổi mật khẩu",
|
||||||
@ -215,6 +219,7 @@
|
|||||||
"Enable": "Enable",
|
"Enable": "Enable",
|
||||||
"Enabled": "Enabled",
|
"Enabled": "Enabled",
|
||||||
"Enabled successfully": "Enabled successfully",
|
"Enabled successfully": "Enabled successfully",
|
||||||
|
"Enforcers": "Enforcers",
|
||||||
"Failed to add": "Không thể thêm được",
|
"Failed to add": "Không thể thêm được",
|
||||||
"Failed to connect to server": "Không thể kết nối đến máy chủ",
|
"Failed to connect to server": "Không thể kết nối đến máy chủ",
|
||||||
"Failed to delete": "Không thể xoá",
|
"Failed to delete": "Không thể xoá",
|
||||||
|
@ -152,6 +152,10 @@
|
|||||||
"Sending": "发送中",
|
"Sending": "发送中",
|
||||||
"Submit and complete": "完成提交"
|
"Submit and complete": "完成提交"
|
||||||
},
|
},
|
||||||
|
"enforcer": {
|
||||||
|
"Edit Enforcer": "Edit Enforcer",
|
||||||
|
"New Enforcer": "New Enforcer"
|
||||||
|
},
|
||||||
"forget": {
|
"forget": {
|
||||||
"Account": "账号",
|
"Account": "账号",
|
||||||
"Change Password": "修改密码",
|
"Change Password": "修改密码",
|
||||||
@ -215,6 +219,7 @@
|
|||||||
"Enable": "启用",
|
"Enable": "启用",
|
||||||
"Enabled": "已开启",
|
"Enabled": "已开启",
|
||||||
"Enabled successfully": "启用成功",
|
"Enabled successfully": "启用成功",
|
||||||
|
"Enforcers": "Enforcers",
|
||||||
"Failed to add": "添加失败",
|
"Failed to add": "添加失败",
|
||||||
"Failed to connect to server": "连接服务器失败",
|
"Failed to connect to server": "连接服务器失败",
|
||||||
"Failed to delete": "删除失败",
|
"Failed to delete": "删除失败",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user