mirror of
https://github.com/labring/sealos.git
synced 2026-08-30 17:58:09 +08:00
ea8e5cf0a9
* initialize the data structure * Initialize the lifecycle management of workspace subscriptions * fix index * add workspace subscription debt * optimize parse period & init workspace subscription & fix subscription create bug * remove quota controller * add user notify framework: content_generator:content generation service:event notification service providers:vms/sms/email ... provider implementation types: core structure type definition * optimize struct & adjust the database to obtain data * Implement the initialization of subscriptions and the implementation of subscription traffic packages * service implement the database layer * auto add column payment.stripe * add stripe pay interface * add workspace subscription service * add the usercr tag for subscription based spaces, Add delete workspace subscription operator & Add api interfaces related to obtaining workspace costs * optimize interface * overall adjustment and repair * optimize traffic early warning notifications * optimize traffic early warning notifications * optimize * optimize & add deletion account api * optimize log * add get payment status api && support workspace subscription AI quota package * optimize * Fixed the issue where traffic was not distributed after renewing the subscription package * fix * fix workspace subscription transaction process add ai quota package * fix ci lint * fix controller/account ci lint * fix controller/pkg ci lint * fix controller/account ci lint * fix controller/pkg ci lint * add admin add workspace subscription * fix upgrade workspace subscription * add get workspace subscription plans api * add get workspace subscription plans api * fix ci lint * fix ci lint * fix ci lint
158 lines
4.5 KiB
Go
158 lines
4.5 KiB
Go
// Copyright © 2022 sealos.
|
|
//
|
|
// 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 pay
|
|
|
|
import (
|
|
"context"
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/wechatpay-apiv3/wechatpay-go/core"
|
|
"github.com/wechatpay-apiv3/wechatpay-go/core/option"
|
|
"github.com/wechatpay-apiv3/wechatpay-go/services/payments"
|
|
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/native"
|
|
"github.com/wechatpay-apiv3/wechatpay-go/utils"
|
|
)
|
|
|
|
type WechatPayment struct{}
|
|
|
|
// ENV keys
|
|
const (
|
|
WechatPrivateKey = "WechatPrivateKey"
|
|
MchID = "MchID"
|
|
MchCertificateSerialNumber = "MchCertificateSerialNumber"
|
|
MchAPIv3Key = "MchAPIv3Key"
|
|
AppID = "AppID"
|
|
NotifyCallbackURL = "NotifyCallbackURL"
|
|
|
|
StatusSuccess = "SUCCESS"
|
|
StatusProcessing = "PROCESSING"
|
|
StatusNotPay = "NOTPAY"
|
|
StatusFail = "FAILED"
|
|
DefaultCallbackURL = "https://sealos.io/payment/wechat/callback"
|
|
)
|
|
|
|
func NewClient(ctx context.Context, opts ...core.ClientOption) (*core.Client, error) {
|
|
mchID := os.Getenv(MchID) // 商户号
|
|
mchCertificateSerialNumber := os.Getenv(MchCertificateSerialNumber) // 商户证书序列号
|
|
mchAPIv3Key := os.Getenv(MchAPIv3Key) // 商户APIv3密钥
|
|
mchPrivateKey, err := utils.LoadPrivateKey(os.Getenv(WechatPrivateKey))
|
|
if err != nil {
|
|
log.Print("private key is: ", os.Getenv(WechatPrivateKey))
|
|
return nil, fmt.Errorf("load merchant private key error: %w", err)
|
|
}
|
|
opts = append(
|
|
opts,
|
|
option.WithWechatPayAutoAuthCipher(
|
|
mchID,
|
|
mchCertificateSerialNumber,
|
|
mchPrivateKey,
|
|
mchAPIv3Key,
|
|
),
|
|
)
|
|
return core.NewClient(ctx, opts...)
|
|
}
|
|
|
|
func QueryOrder(orderID string) (*payments.Transaction, error) {
|
|
ctx := context.Background()
|
|
client, err := NewClient(context.Background())
|
|
if err != nil {
|
|
return nil, fmt.Errorf("new wechat pay client err:%w", err)
|
|
}
|
|
svc := native.NativeApiService{Client: client}
|
|
resp, _, err := svc.QueryOrderByOutTradeNo(ctx,
|
|
native.QueryOrderByOutTradeNoRequest{
|
|
Mchid: core.String(os.Getenv(MchID)),
|
|
OutTradeNo: core.String(orderID),
|
|
},
|
|
)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("call QueryOrder err:%w", err)
|
|
}
|
|
return resp, nil
|
|
}
|
|
|
|
// 1 ¥ = amount 100
|
|
func WechatPay(amount int64, user, tradeNO, describe, callback string) (string, error) {
|
|
ctx := context.Background()
|
|
client, err := NewClient(context.Background())
|
|
if err != nil {
|
|
return "", fmt.Errorf("new wechat pay client err:%w", err)
|
|
}
|
|
|
|
if tradeNO == "" {
|
|
tradeNO = GetRandomString(32)
|
|
}
|
|
if tradeNO == "" {
|
|
return "", errors.New("generate tradeNO failed")
|
|
}
|
|
if describe == "" {
|
|
describe = "sealos cloud recharge"
|
|
}
|
|
if callback == "" {
|
|
callback = DefaultCallbackURL
|
|
}
|
|
svc := native.NativeApiService{Client: client}
|
|
resp, _, err := svc.Prepay(ctx,
|
|
native.PrepayRequest{
|
|
Appid: core.String(os.Getenv(AppID)),
|
|
Mchid: core.String(os.Getenv(MchID)),
|
|
Description: core.String(describe),
|
|
OutTradeNo: core.String(tradeNO),
|
|
TimeExpire: core.Time(time.Now()),
|
|
Attach: core.String(user),
|
|
NotifyUrl: core.String(callback),
|
|
GoodsTag: core.String("sealos recharge"),
|
|
SupportFapiao: core.Bool(false),
|
|
Amount: &native.Amount{
|
|
Currency: core.String("CNY"),
|
|
Total: core.Int64(amount),
|
|
},
|
|
Detail: &native.Detail{
|
|
CostPrice: core.Int64(608800),
|
|
GoodsDetail: []native.GoodsDetail{
|
|
{
|
|
GoodsName: core.String("sealos cloud recharge"),
|
|
MerchantGoodsId: core.String("ABC"),
|
|
Quantity: core.Int64(1),
|
|
UnitPrice: core.Int64(828800),
|
|
WechatpayGoodsId: core.String("1001"),
|
|
},
|
|
},
|
|
},
|
|
SettleInfo: &native.SettleInfo{
|
|
ProfitSharing: core.Bool(false),
|
|
},
|
|
},
|
|
)
|
|
if err != nil {
|
|
return "", fmt.Errorf("call Prepay err:%w", err)
|
|
}
|
|
return *resp.CodeUrl, nil
|
|
}
|
|
|
|
func GetRandomString(n int) string {
|
|
randBytes := make([]byte, n/2)
|
|
if _, err := rand.Read(randBytes); err != nil {
|
|
return ""
|
|
}
|
|
return hex.EncodeToString(randBytes)
|
|
}
|