mirror of
https://github.com/halejohn/Cloudreve.git
synced 2026-01-26 09:34:57 +08:00
Feat: vas for group / storage pack
This commit is contained in:
86
pkg/payment/order.go
Normal file
86
pkg/payment/order.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
model "github.com/HFO4/cloudreve/models"
|
||||
"github.com/HFO4/cloudreve/pkg/serializer"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrUnknownPaymentMethod 未知支付方式
|
||||
ErrUnknownPaymentMethod = serializer.NewError(serializer.CodeNotFound, "未知支付方式", nil)
|
||||
// ErrUnsupportedPaymentMethod 未知支付方式
|
||||
ErrUnsupportedPaymentMethod = serializer.NewError(serializer.CodeNotFound, "此订单不支持此支付方式", nil)
|
||||
// ErrInsertOrder 无法插入订单记录
|
||||
ErrInsertOrder = serializer.NewError(serializer.CodeDBError, "无法插入订单记录", nil)
|
||||
// ErrScoreNotEnough 积分不足
|
||||
ErrScoreNotEnough = serializer.NewError(serializer.CodeNoPermissionErr, "积分不足", nil)
|
||||
// ErrCreateStoragePack 无法创建容量包
|
||||
ErrCreateStoragePack = serializer.NewError(serializer.CodeNoPermissionErr, "无法创建容量包", nil)
|
||||
// ErrGroupConflict 用户组冲突
|
||||
ErrGroupConflict = serializer.NewError(serializer.CodeNoPermissionErr, "当前用户组仍未过期,请前往个人设置手动解约后继续", nil)
|
||||
// ErrGroupInvalid 用户组冲突
|
||||
ErrGroupInvalid = serializer.NewError(serializer.CodeNoPermissionErr, "用户组不可用", nil)
|
||||
// ErrUpgradeGroup 用户组冲突
|
||||
ErrUpgradeGroup = serializer.NewError(serializer.CodeDBError, "无法升级用户组", nil)
|
||||
)
|
||||
|
||||
// Pay 支付处理接口
|
||||
type Pay interface {
|
||||
Create(order *model.Order, pack *serializer.PackProduct, group *serializer.GroupProducts, user *model.User) (*OrderCreateRes, error)
|
||||
}
|
||||
|
||||
// OrderCreateRes 订单创建结果
|
||||
type OrderCreateRes struct {
|
||||
Payment bool `json:"payment"` // 是否需要支付
|
||||
}
|
||||
|
||||
// NewPaymentInstance 获取新的支付实例
|
||||
func NewPaymentInstance(method string) (Pay, error) {
|
||||
if method == "score" {
|
||||
return &ScorePayment{}, nil
|
||||
}
|
||||
|
||||
return nil, ErrUnknownPaymentMethod
|
||||
}
|
||||
|
||||
// NewOrder 创建新订单
|
||||
func NewOrder(pack *serializer.PackProduct, group *serializer.GroupProducts, num int, method string, user *model.User) (*OrderCreateRes, error) {
|
||||
// 获取支付实例
|
||||
pay, err := NewPaymentInstance(method)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
orderType int
|
||||
productID int64
|
||||
title string
|
||||
price int
|
||||
)
|
||||
if pack == nil {
|
||||
orderType = model.GroupOrderType
|
||||
productID = group.ID
|
||||
title = group.Name
|
||||
price = group.Price
|
||||
} else {
|
||||
orderType = model.PackOrderType
|
||||
productID = pack.ID
|
||||
title = pack.Name
|
||||
price = pack.Price
|
||||
}
|
||||
|
||||
// 创建订单记录
|
||||
order := &model.Order{
|
||||
UserID: user.ID,
|
||||
Type: orderType,
|
||||
Method: method,
|
||||
ProductID: productID,
|
||||
Num: num,
|
||||
Name: fmt.Sprintf("%s - %s", model.GetSettingByName("siteName"), title),
|
||||
Price: price,
|
||||
Status: model.OrderUnpaid,
|
||||
}
|
||||
|
||||
return pay.Create(order, pack, group, user)
|
||||
}
|
||||
64
pkg/payment/purchase.go
Normal file
64
pkg/payment/purchase.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
model "github.com/HFO4/cloudreve/models"
|
||||
"github.com/HFO4/cloudreve/pkg/serializer"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GivePack 创建容量包
|
||||
func GivePack(user *model.User, packInfo *serializer.PackProduct, num int) error {
|
||||
timeNow := time.Now()
|
||||
expires := timeNow.Add(time.Duration(packInfo.Time*int64(num)) * time.Second)
|
||||
pack := model.StoragePack{
|
||||
Name: packInfo.Name,
|
||||
UserID: user.ID,
|
||||
ActiveTime: &timeNow,
|
||||
ExpiredTime: &expires,
|
||||
Size: packInfo.Size,
|
||||
}
|
||||
if _, err := pack.Create(); err != nil {
|
||||
return ErrCreateStoragePack.WithError(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkGroupUpgrade(user *model.User, groupInfo *serializer.GroupProducts) error {
|
||||
// 检查用户是否已有未过期用户
|
||||
if user.PreviousGroupID != 0 {
|
||||
return ErrGroupConflict
|
||||
}
|
||||
|
||||
// 用户组不能相同
|
||||
if user.GroupID == groupInfo.GroupID {
|
||||
return ErrGroupInvalid
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GiveGroup 升级用户组
|
||||
func GiveGroup(user *model.User, groupInfo *serializer.GroupProducts, num int) error {
|
||||
if err := checkGroupUpgrade(user, groupInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
timeNow := time.Now()
|
||||
expires := timeNow.Add(time.Duration(groupInfo.Time*int64(num)) * time.Second)
|
||||
|
||||
if err := user.UpgradeGroup(groupInfo.GroupID, &expires); err != nil {
|
||||
return ErrUpgradeGroup.WithError(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GiveProduct “发货”
|
||||
func GiveProduct(user *model.User, pack *serializer.PackProduct, group *serializer.GroupProducts, num int) error {
|
||||
if pack != nil {
|
||||
return GivePack(user, pack, num)
|
||||
} else if group != nil {
|
||||
return GiveGroup(user, group, num)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
44
pkg/payment/score.go
Normal file
44
pkg/payment/score.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
model "github.com/HFO4/cloudreve/models"
|
||||
"github.com/HFO4/cloudreve/pkg/serializer"
|
||||
)
|
||||
|
||||
// ScorePayment 积分支付处理
|
||||
type ScorePayment struct {
|
||||
}
|
||||
|
||||
// Create 创建新订单
|
||||
func (pay *ScorePayment) Create(order *model.Order, pack *serializer.PackProduct, group *serializer.GroupProducts, user *model.User) (*OrderCreateRes, error) {
|
||||
if pack != nil {
|
||||
order.Price = pack.Score
|
||||
} else {
|
||||
order.Price = group.Score
|
||||
}
|
||||
|
||||
// 检查此订单是否可用积分支付
|
||||
if order.Price == 0 {
|
||||
return nil, ErrUnsupportedPaymentMethod
|
||||
}
|
||||
|
||||
// 扣除用户积分
|
||||
if !user.PayScore(order.Price * order.Num) {
|
||||
return nil, ErrScoreNotEnough
|
||||
}
|
||||
|
||||
// 商品“发货”
|
||||
if err := GiveProduct(user, pack, group, order.Num); err != nil {
|
||||
user.AddScore(order.Price * order.Num)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 创建订单记录
|
||||
if _, err := order.Create(); err != nil {
|
||||
return nil, ErrInsertOrder.WithError(err)
|
||||
}
|
||||
|
||||
return &OrderCreateRes{
|
||||
Payment: false,
|
||||
}, nil
|
||||
}
|
||||
84
pkg/serializer/vas.go
Normal file
84
pkg/serializer/vas.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package serializer
|
||||
|
||||
import (
|
||||
model "github.com/HFO4/cloudreve/models"
|
||||
)
|
||||
|
||||
type quota struct {
|
||||
Base uint64 `json:"base"`
|
||||
Pack uint64 `json:"pack"`
|
||||
Used uint64 `json:"used"`
|
||||
Total uint64 `json:"total"`
|
||||
Packs []storagePacks `json:"packs"`
|
||||
}
|
||||
|
||||
type storagePacks struct {
|
||||
Name string `json:"name"`
|
||||
Size uint64 `json:"size"`
|
||||
ActivateDate string `json:"activate_date"`
|
||||
Expiration int `json:"expiration"`
|
||||
ExpirationDate string `json:"expiration_date"`
|
||||
}
|
||||
|
||||
// BuildUserQuotaResponse 序列化用户存储配额概况响应
|
||||
func BuildUserQuotaResponse(user *model.User, packs []model.StoragePack) Response {
|
||||
packSize := user.GetAvailablePackSize()
|
||||
res := quota{
|
||||
Base: user.Group.MaxStorage,
|
||||
Pack: packSize,
|
||||
Used: user.Storage,
|
||||
Total: packSize + user.Group.MaxStorage,
|
||||
Packs: make([]storagePacks, 0, len(packs)),
|
||||
}
|
||||
for _, pack := range packs {
|
||||
res.Packs = append(res.Packs, storagePacks{
|
||||
Name: pack.Name,
|
||||
Size: pack.Size,
|
||||
ActivateDate: pack.ActiveTime.Format("2006-01-02 15:04:05"),
|
||||
Expiration: int(pack.ExpiredTime.Sub(*pack.ActiveTime).Seconds()),
|
||||
ExpirationDate: pack.ExpiredTime.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
|
||||
return Response{
|
||||
Data: res,
|
||||
}
|
||||
}
|
||||
|
||||
// PackProduct 容量包商品
|
||||
type PackProduct struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Size uint64 `json:"size"`
|
||||
Time int64 `json:"time"`
|
||||
Price int `json:"price"`
|
||||
Score int `json:"score"`
|
||||
}
|
||||
|
||||
// GroupProducts 用户组商品
|
||||
type GroupProducts struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
GroupID uint `json:"group_id"`
|
||||
Time int64 `json:"time"`
|
||||
Price int `json:"price"`
|
||||
Score int `json:"score"`
|
||||
Des []string `json:"des"`
|
||||
Highlight bool `json:"highlight"`
|
||||
}
|
||||
|
||||
// BuildProductResponse 构建增值服务商品响应
|
||||
func BuildProductResponse(groups []GroupProducts, packs []PackProduct, alipay, payjs bool) Response {
|
||||
// 隐藏响应中的用户组ID
|
||||
for i := 0; i < len(groups); i++ {
|
||||
groups[i].GroupID = 0
|
||||
}
|
||||
return Response{
|
||||
Data: map[string]interface{}{
|
||||
"packs": packs,
|
||||
"groups": groups,
|
||||
"alipay": alipay,
|
||||
"payjs": payjs,
|
||||
},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user