mirror of
https://github.com/yangjian102621/geekai.git
synced 2025-09-18 01:06:39 +08:00
opt: verify the order in notify callback
This commit is contained in:
parent
66c7717f04
commit
3ad8065e20
@ -8,6 +8,7 @@
|
|||||||
* 功能新增:新增网站公告,可以在管理后台自定义配置
|
* 功能新增:新增网站公告,可以在管理后台自定义配置
|
||||||
* 功能新增:新增阿里通义千问大模型支持
|
* 功能新增:新增阿里通义千问大模型支持
|
||||||
* Bug修复:修复 MJ 放大任务失败时候 img_call 会增加的 Bug
|
* Bug修复:修复 MJ 放大任务失败时候 img_call 会增加的 Bug
|
||||||
|
* 功能优化:新增虎皮椒和PayJS订单状态校验功能,增加安全性
|
||||||
|
|
||||||
|
|
||||||
## v3.2.5
|
## v3.2.5
|
||||||
|
@ -38,16 +38,6 @@ type SmtpConfig struct {
|
|||||||
Password string // 发件人邮箱密码
|
Password string // 发件人邮箱密码
|
||||||
}
|
}
|
||||||
|
|
||||||
// JPayConfig PayJs 支付配置
|
|
||||||
type JPayConfig struct {
|
|
||||||
Enabled bool
|
|
||||||
Name string // 支付名称,默认 wechat
|
|
||||||
AppId string // 商户 ID
|
|
||||||
PrivateKey string // 私钥
|
|
||||||
ApiURL string // API 网关
|
|
||||||
NotifyURL string // 异步回调地址
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChatPlusApiConfig struct {
|
type ChatPlusApiConfig struct {
|
||||||
ApiURL string
|
ApiURL string
|
||||||
AppId string
|
AppId string
|
||||||
@ -105,10 +95,20 @@ type HuPiPayConfig struct { //虎皮椒第四方支付配置
|
|||||||
Name string // 支付名称,如:wechat/alipay
|
Name string // 支付名称,如:wechat/alipay
|
||||||
AppId string // App ID
|
AppId string // App ID
|
||||||
AppSecret string // app 密钥
|
AppSecret string // app 密钥
|
||||||
PayURL string // 支付网关
|
ApiURL string // 支付网关
|
||||||
NotifyURL string // 异步通知回调
|
NotifyURL string // 异步通知回调
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JPayConfig PayJs 支付配置
|
||||||
|
type JPayConfig struct {
|
||||||
|
Enabled bool
|
||||||
|
Name string // 支付名称,默认 wechat
|
||||||
|
AppId string // 商户 ID
|
||||||
|
PrivateKey string // 私钥
|
||||||
|
ApiURL string // API 网关
|
||||||
|
NotifyURL string // 异步回调地址
|
||||||
|
}
|
||||||
|
|
||||||
type XXLConfig struct { // XXL 任务调度配置
|
type XXLConfig struct { // XXL 任务调度配置
|
||||||
Enabled bool
|
Enabled bool
|
||||||
ServerAddr string
|
ServerAddr string
|
||||||
|
@ -101,30 +101,12 @@ func (h *PaymentHandler) DoPay(c *gin.Context) {
|
|||||||
NotifyURL: h.App.Config.HuPiPayConfig.NotifyURL,
|
NotifyURL: h.App.Config.HuPiPayConfig.NotifyURL,
|
||||||
WapName: "极客学长",
|
WapName: "极客学长",
|
||||||
}
|
}
|
||||||
res, err := h.huPiPayService.Pay(params)
|
r, err := h.huPiPayService.Pay(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.ERROR(c, "error with generate pay url: "+err.Error())
|
resp.ERROR(c, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var r struct {
|
|
||||||
Openid interface{} `json:"openid"`
|
|
||||||
UrlQrcode string `json:"url_qrcode"`
|
|
||||||
URL string `json:"url"`
|
|
||||||
ErrCode int `json:"errcode"`
|
|
||||||
ErrMsg string `json:"errmsg,omitempty"`
|
|
||||||
}
|
|
||||||
err = utils.JsonDecode(res, &r)
|
|
||||||
if err != nil {
|
|
||||||
logger.Debugf(res)
|
|
||||||
resp.ERROR(c, "error with decode payment result: "+err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.ErrCode != 0 {
|
|
||||||
resp.ERROR(c, "error with generate pay url: "+r.ErrMsg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.Redirect(302, r.URL)
|
c.Redirect(302, r.URL)
|
||||||
}
|
}
|
||||||
resp.ERROR(c, "Invalid operations")
|
resp.ERROR(c, "Invalid operations")
|
||||||
@ -288,7 +270,7 @@ func (h *PaymentHandler) PayQrcode(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 异步通知回调公共逻辑
|
// 异步通知回调公共逻辑
|
||||||
func (h *PaymentHandler) notify(orderNo string) error {
|
func (h *PaymentHandler) notify(orderNo string, tradeNo string) error {
|
||||||
var order model.Order
|
var order model.Order
|
||||||
res := h.db.Where("order_no = ?", orderNo).First(&order)
|
res := h.db.Where("order_no = ?", orderNo).First(&order)
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
@ -353,6 +335,7 @@ func (h *PaymentHandler) notify(orderNo string) error {
|
|||||||
// 更新订单状态
|
// 更新订单状态
|
||||||
order.PayTime = time.Now().Unix()
|
order.PayTime = time.Now().Unix()
|
||||||
order.Status = types.OrderPaidSuccess
|
order.Status = types.OrderPaidSuccess
|
||||||
|
order.TradeNo = tradeNo
|
||||||
res = h.db.Updates(&order)
|
res = h.db.Updates(&order)
|
||||||
if res.Error != nil {
|
if res.Error != nil {
|
||||||
err := fmt.Errorf("error with update order info: %v", res.Error)
|
err := fmt.Errorf("error with update order info: %v", res.Error)
|
||||||
@ -390,9 +373,14 @@ func (h *PaymentHandler) HuPiPayNotify(c *gin.Context) {
|
|||||||
|
|
||||||
orderNo := c.Request.Form.Get("trade_order_id")
|
orderNo := c.Request.Form.Get("trade_order_id")
|
||||||
logger.Infof("收到订单支付回调,订单 NO:%s", orderNo)
|
logger.Infof("收到订单支付回调,订单 NO:%s", orderNo)
|
||||||
// TODO 是否要保存订单交易流水号
|
|
||||||
|
|
||||||
err = h.notify(orderNo)
|
tradeNo := c.Request.Form.Get("transaction_id")
|
||||||
|
if err = h.huPiPayService.Check(tradeNo); err != nil {
|
||||||
|
logger.Error("订单校验失败:", err)
|
||||||
|
c.String(http.StatusOK, "fail")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = h.notify(orderNo, tradeNo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusOK, "fail")
|
c.String(http.StatusOK, "fail")
|
||||||
return
|
return
|
||||||
@ -409,16 +397,17 @@ func (h *PaymentHandler) AlipayNotify(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:这里最好用支付宝的公钥签名签证一下交易真假
|
// TODO:验证交易签名
|
||||||
//res := h.alipayService.TradeVerify(c.Request.Form)
|
res := h.alipayService.TradeVerify(c.Request.Form)
|
||||||
r := h.alipayService.TradeQuery(c.Request.Form.Get("out_trade_no"))
|
logger.Infof("验证支付结果:%+v", res)
|
||||||
logger.Infof("验证支付结果:%+v", r)
|
if !res.Success() {
|
||||||
if !r.Success() {
|
logger.Error("订单校验失败:", res.Message)
|
||||||
c.String(http.StatusOK, "fail")
|
c.String(http.StatusOK, "fail")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.notify(r.OutTradeNo)
|
tradeNo := c.Request.Form.Get("trade_no")
|
||||||
|
err = h.notify(res.OutTradeNo, tradeNo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusOK, "fail")
|
c.String(http.StatusOK, "fail")
|
||||||
return
|
return
|
||||||
@ -443,7 +432,16 @@ func (h *PaymentHandler) PayJsNotify(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.notify(orderNo)
|
// 校验订单支付状态
|
||||||
|
tradeNo := c.Request.Form.Get("payjs_order_id")
|
||||||
|
err = h.js.Check(tradeNo)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("订单校验失败:", err)
|
||||||
|
c.String(http.StatusOK, "fail")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = h.notify(orderNo, tradeNo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.String(http.StatusOK, "fail")
|
c.String(http.StatusOK, "fail")
|
||||||
return
|
return
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"chatplus/core/types"
|
"chatplus/core/types"
|
||||||
"chatplus/utils"
|
"chatplus/utils"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -17,14 +18,14 @@ import (
|
|||||||
type HuPiPayService struct {
|
type HuPiPayService struct {
|
||||||
appId string
|
appId string
|
||||||
appSecret string
|
appSecret string
|
||||||
host string
|
apiURL string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHuPiPay(config *types.AppConfig) *HuPiPayService {
|
func NewHuPiPay(config *types.AppConfig) *HuPiPayService {
|
||||||
return &HuPiPayService{
|
return &HuPiPayService{
|
||||||
appId: config.HuPiPayConfig.AppId,
|
appId: config.HuPiPayConfig.AppId,
|
||||||
appSecret: config.HuPiPayConfig.AppSecret,
|
appSecret: config.HuPiPayConfig.AppSecret,
|
||||||
host: config.HuPiPayConfig.PayURL,
|
apiURL: config.HuPiPayConfig.ApiURL,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,8 +43,16 @@ type HuPiPayReq struct {
|
|||||||
NonceStr string `json:"nonce_str"`
|
NonceStr string `json:"nonce_str"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type HuPiResp struct {
|
||||||
|
Openid interface{} `json:"openid"`
|
||||||
|
UrlQrcode string `json:"url_qrcode"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
ErrCode int `json:"errcode"`
|
||||||
|
ErrMsg string `json:"errmsg,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// Pay 执行支付请求操作
|
// Pay 执行支付请求操作
|
||||||
func (s *HuPiPayService) Pay(params HuPiPayReq) (string, error) {
|
func (s *HuPiPayService) Pay(params HuPiPayReq) (HuPiResp, error) {
|
||||||
data := url.Values{}
|
data := url.Values{}
|
||||||
simple := strconv.FormatInt(time.Now().Unix(), 10)
|
simple := strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
params.AppId = s.appId
|
params.AppId = s.appId
|
||||||
@ -58,21 +67,34 @@ func (s *HuPiPayService) Pay(params HuPiPayReq) (string, error) {
|
|||||||
encode = utils.JsonEncode(params)
|
encode = utils.JsonEncode(params)
|
||||||
m = make(map[string]string)
|
m = make(map[string]string)
|
||||||
_ = utils.JsonDecode(encode, &m)
|
_ = utils.JsonDecode(encode, &m)
|
||||||
data.Add("hash", s.Sign(m))
|
data.Add("hash", s.sign(m))
|
||||||
resp, err := http.PostForm(s.host, data)
|
apiURL := fmt.Sprintf("%s/payment/do.html", s.apiURL)
|
||||||
|
logger.Info(apiURL)
|
||||||
|
resp, err := http.PostForm(apiURL, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "error", err
|
return HuPiResp{}, fmt.Errorf("error with requst api: %v", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
all, err := io.ReadAll(resp.Body)
|
all, err := io.ReadAll(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "error", err
|
return HuPiResp{}, fmt.Errorf("error with reading response: %v", err)
|
||||||
}
|
}
|
||||||
return string(all), err
|
|
||||||
|
var res HuPiResp
|
||||||
|
err = utils.JsonDecode(string(all), &res)
|
||||||
|
if err != nil {
|
||||||
|
return HuPiResp{}, fmt.Errorf("error with decode payment result: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.ErrCode != 0 {
|
||||||
|
return HuPiResp{}, fmt.Errorf("error with generate pay url: %s", res.ErrMsg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sign 签名方法
|
// Sign 签名方法
|
||||||
func (s *HuPiPayService) Sign(params map[string]string) string {
|
func (s *HuPiPayService) sign(params map[string]string) string {
|
||||||
var data string
|
var data string
|
||||||
keys := make([]string, 0, 0)
|
keys := make([]string, 0, 0)
|
||||||
for key := range params {
|
for key := range params {
|
||||||
@ -90,3 +112,50 @@ func (s *HuPiPayService) Sign(params map[string]string) string {
|
|||||||
sign := fmt.Sprintf("%x", m.Sum(nil))
|
sign := fmt.Sprintf("%x", m.Sum(nil))
|
||||||
return sign
|
return sign
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check 校验订单状态
|
||||||
|
func (s *HuPiPayService) Check(tradeNo string) error {
|
||||||
|
data := url.Values{}
|
||||||
|
data.Add("appid", s.appId)
|
||||||
|
data.Add("open_order_id", tradeNo)
|
||||||
|
stamp := strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
|
data.Add("time", stamp)
|
||||||
|
data.Add("nonce_str", stamp)
|
||||||
|
// 生成签名
|
||||||
|
encode := utils.JsonEncode(data)
|
||||||
|
m := make(map[string]string)
|
||||||
|
err := utils.JsonDecode(encode, &m)
|
||||||
|
data.Add("sign", s.sign(m))
|
||||||
|
|
||||||
|
apiURL := fmt.Sprintf("%s/payment/query.html", s.apiURL)
|
||||||
|
resp, err := http.PostForm(apiURL, data)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error with http reqeust: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error with reading response: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var r struct {
|
||||||
|
ErrCode int `json:"errcode"`
|
||||||
|
Data struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
OpenOrderId string `json:"open_order_id"`
|
||||||
|
} `json:"data,omitempty"`
|
||||||
|
ErrMsg string `json:"errmsg"`
|
||||||
|
Hash string `json:"hash"`
|
||||||
|
}
|
||||||
|
err = utils.JsonDecode(string(body), &r)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error with decode response: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.ErrCode == 0 && r.Data.Status == "OD" {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return errors.New("order not paid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"chatplus/utils"
|
"chatplus/utils"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@ -55,10 +56,11 @@ func (js *PayJS) Pay(param JPayReq) JPayReps {
|
|||||||
}
|
}
|
||||||
p.Add("mchid", js.config.AppId)
|
p.Add("mchid", js.config.AppId)
|
||||||
|
|
||||||
p.Add("sign", sign(p, js.config.PrivateKey))
|
p.Add("sign", js.sign(p))
|
||||||
|
|
||||||
cli := http.Client{}
|
cli := http.Client{}
|
||||||
r, err := cli.PostForm(js.config.ApiURL, p)
|
apiURL := fmt.Sprintf("%s/api/native", js.config.ApiURL)
|
||||||
|
r, err := cli.PostForm(apiURL, p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return JPayReps{ReturnMsg: err.Error()}
|
return JPayReps{ReturnMsg: err.Error()}
|
||||||
}
|
}
|
||||||
@ -76,7 +78,7 @@ func (js *PayJS) Pay(param JPayReq) JPayReps {
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
func sign(params url.Values, priKey string) string {
|
func (js *PayJS) sign(params url.Values) string {
|
||||||
params.Del(`sign`)
|
params.Del(`sign`)
|
||||||
var keys = make([]string, 0, 0)
|
var keys = make([]string, 0, 0)
|
||||||
for key := range params {
|
for key := range params {
|
||||||
@ -94,9 +96,45 @@ func sign(params url.Values, priKey string) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var src = strings.Join(pList, "&")
|
var src = strings.Join(pList, "&")
|
||||||
src += "&key=" + priKey
|
src += "&key=" + js.config.PrivateKey
|
||||||
|
|
||||||
md5bs := md5.Sum([]byte(src))
|
md5bs := md5.Sum([]byte(src))
|
||||||
md5res := hex.EncodeToString(md5bs[:])
|
md5res := hex.EncodeToString(md5bs[:])
|
||||||
return strings.ToUpper(md5res)
|
return strings.ToUpper(md5res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check 查询订单支付状态
|
||||||
|
// @param tradeNo 支付平台交易 ID
|
||||||
|
func (js *PayJS) Check(tradeNo string) error {
|
||||||
|
apiURL := fmt.Sprintf("%s/api/check", js.config.ApiURL)
|
||||||
|
params := url.Values{}
|
||||||
|
params.Add("payjs_order_id", tradeNo)
|
||||||
|
params.Add("sign", js.sign(params))
|
||||||
|
data := strings.NewReader(params.Encode())
|
||||||
|
resp, err := http.Post(apiURL, "application/x-www-form-urlencoded", data)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error with http reqeust: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error with reading response: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var r struct {
|
||||||
|
ReturnCode int `json:"return_code"`
|
||||||
|
Status int `json:"status"`
|
||||||
|
}
|
||||||
|
err = utils.JsonDecode(string(body), &r)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error with decode response: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.ReturnCode == 1 && r.Status == 1 {
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
return errors.New("order not paid")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -12,6 +12,7 @@ type Order struct {
|
|||||||
ProductId uint
|
ProductId uint
|
||||||
Username string
|
Username string
|
||||||
OrderNo string
|
OrderNo string
|
||||||
|
TradeNo string
|
||||||
Subject string
|
Subject string
|
||||||
Amount float64
|
Amount float64
|
||||||
Status types.OrderStatus
|
Status types.OrderStatus
|
||||||
|
@ -10,6 +10,7 @@ type Order struct {
|
|||||||
ProductId uint `json:"product_id"`
|
ProductId uint `json:"product_id"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
OrderNo string `json:"order_no"`
|
OrderNo string `json:"order_no"`
|
||||||
|
TradeNo string `json:"trade_no"`
|
||||||
Subject string `json:"subject"`
|
Subject string `json:"subject"`
|
||||||
Amount float64 `json:"amount"`
|
Amount float64 `json:"amount"`
|
||||||
Status types.OrderStatus `json:"status"`
|
Status types.OrderStatus `json:"status"`
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
ALTER TABLE `chatgpt_mj_jobs` ADD `publish` TINYINT(1) NOT NULL COMMENT '是否发布' AFTER `use_proxy`;
|
ALTER TABLE `chatgpt_mj_jobs` ADD `publish` TINYINT(1) NOT NULL COMMENT '是否发布' AFTER `use_proxy`;
|
||||||
ALTER TABLE `chatgpt_sd_jobs` ADD `publish` TINYINT(1) NOT NULL COMMENT '是否发布' AFTER `progress`;
|
ALTER TABLE `chatgpt_sd_jobs` ADD `publish` TINYINT(1) NOT NULL COMMENT '是否发布' AFTER `progress`;
|
||||||
|
|
||||||
|
ALTER TABLE `chatgpt_orders` ADD `trade_no` VARCHAR(60) NOT NULL COMMENT '支付平台交易流水号' AFTER `order_no`;
|
@ -101,7 +101,7 @@ WeChatBot = false
|
|||||||
Name = "wechat"
|
Name = "wechat"
|
||||||
AppId = ""
|
AppId = ""
|
||||||
AppSecret = ""
|
AppSecret = ""
|
||||||
PayURL = "https://api.xunhupay.com/payment/do.html"
|
ApiURL = "https://api.xunhupay.com"
|
||||||
NotifyURL = "https://ai.r9it.com/api/payment/hupipay/notify"
|
NotifyURL = "https://ai.r9it.com/api/payment/hupipay/notify"
|
||||||
|
|
||||||
[SmtpConfig] # 注意,阿里云服务器禁用了25号端口,所以如果需要使用邮件功能,请别用阿里云服务器
|
[SmtpConfig] # 注意,阿里云服务器禁用了25号端口,所以如果需要使用邮件功能,请别用阿里云服务器
|
||||||
@ -116,5 +116,5 @@ WeChatBot = false
|
|||||||
Name = "wechat" # 请不要改动
|
Name = "wechat" # 请不要改动
|
||||||
AppId = "" # 商户 ID
|
AppId = "" # 商户 ID
|
||||||
PrivateKey = "" # 秘钥
|
PrivateKey = "" # 秘钥
|
||||||
ApiURL = "https://payjs.cn/api/native"
|
ApiURL = "https://payjs.cn"
|
||||||
NotifyURL = "https://ai.r9it.com/api/payment/payjs/notify" # 异步回调地址,域名改成你自己的
|
NotifyURL = "https://ai.r9it.com/api/payment/payjs/notify" # 异步回调地址,域名改成你自己的
|
Loading…
Reference in New Issue
Block a user