This commit is contained in:
unknown
2026-02-04 20:27:13 +08:00
commit 3b042d1dad
9410 changed files with 1488147 additions and 0 deletions

View File

@@ -0,0 +1,257 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package accounts
import (
"context"
"errors"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/accounts"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
)
// OrderMethodService 订单支付方式相关服务
type OrderMethodService struct {
services.BaseService
}
// CreateOrderMethod 创建支付方式
func (this *OrderMethodService) CreateOrderMethod(ctx context.Context, req *pb.CreateOrderMethodRequest) (*pb.CreateOrderMethodResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
// 检查代号是否相同
exists, err := accounts.SharedOrderMethodDAO.ExistOrderMethodWithCode(tx, req.Code, 0)
if err != nil {
return nil, err
}
if exists {
return nil, errors.New("pay method code already exists")
}
var params any
if len(req.ParentCode) > 0 {
params, err = userconfigs.DecodePayMethodParams(req.ParentCode, req.ParamsJSON)
if err != nil {
return nil, errors.New("invalid params: " + err.Error())
}
}
methodId, err := accounts.SharedOrderMethodDAO.CreateMethod(tx, req.Name, req.Code, req.Url, req.Description, req.ParentCode, params, req.ClientType, req.QrcodeTitle)
if err != nil {
return nil, err
}
return &pb.CreateOrderMethodResponse{
OrderMethodId: methodId,
}, nil
}
// UpdateOrderMethod 修改支付方式
func (this *OrderMethodService) UpdateOrderMethod(ctx context.Context, req *pb.UpdateOrderMethodRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
// 检查代号是否相同
exists, err := accounts.SharedOrderMethodDAO.ExistOrderMethodWithCode(tx, req.Code, req.OrderMethodId)
if err != nil {
return nil, err
}
if exists {
return nil, errors.New("pay method code already exists")
}
method, err := accounts.SharedOrderMethodDAO.FindEnabledBasicOrderMethod(tx, req.OrderMethodId)
if err != nil {
return nil, err
}
if method == nil {
return nil, errors.New("could not find method")
}
var params any
if len(method.ParentCode) > 0 {
params, err = userconfigs.DecodePayMethodParams(method.ParentCode, req.ParamsJSON)
if err != nil {
return nil, errors.New("invalid params: " + err.Error())
}
}
err = accounts.SharedOrderMethodDAO.UpdateMethod(tx, req.OrderMethodId, req.Name, req.Code, req.Url, req.Description, params, req.ClientType, req.QrcodeTitle, req.IsOn)
if err != nil {
return nil, err
}
return this.Success()
}
// DeleteOrderMethod 删除支付方式
func (this *OrderMethodService) DeleteOrderMethod(ctx context.Context, req *pb.DeleteOrderMethodRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
err = accounts.SharedOrderMethodDAO.DisableOrderMethod(tx, req.OrderMethodId)
if err != nil {
return nil, err
}
return this.Success()
}
// FindEnabledOrderMethod 查找单个支付方式
func (this *OrderMethodService) FindEnabledOrderMethod(ctx context.Context, req *pb.FindEnabledOrderMethodRequest) (*pb.FindEnabledOrderMethodResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
method, err := accounts.SharedOrderMethodDAO.FindEnabledOrderMethod(tx, req.OrderMethodId)
if err != nil {
return nil, err
}
if method == nil {
return &pb.FindEnabledOrderMethodResponse{
OrderMethod: nil,
}, nil
}
return &pb.FindEnabledOrderMethodResponse{
OrderMethod: &pb.OrderMethod{
Id: int64(method.Id),
Name: method.Name,
Code: method.Code,
Description: method.Description,
Url: method.Url,
Secret: method.Secret,
IsOn: method.IsOn,
ParentCode: method.ParentCode,
Params: method.Params, // 注意参数不能通过接口泄露给平台用户
ClientType: method.ClientType,
QrcodeTitle: method.QrcodeTitle,
},
}, nil
}
// FindEnabledOrderMethodWithCode 根据代号查找支付方式
func (this *OrderMethodService) FindEnabledOrderMethodWithCode(ctx context.Context, req *pb.FindEnabledOrderMethodWithCodeRequest) (*pb.FindEnabledOrderMethodWithCodeResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
method, err := accounts.SharedOrderMethodDAO.FindEnabledOrderMethodWithCode(tx, req.Code)
if err != nil {
return nil, err
}
if method == nil {
return &pb.FindEnabledOrderMethodWithCodeResponse{
OrderMethod: nil,
}, nil
}
// 保护数据
if userId > 0 {
method.Secret = ""
}
return &pb.FindEnabledOrderMethodWithCodeResponse{
OrderMethod: &pb.OrderMethod{
Id: int64(method.Id),
Name: method.Name,
Code: method.Code,
ParentCode: method.ParentCode,
Description: method.Description,
Url: method.Url,
Secret: method.Secret,
IsOn: method.IsOn,
ClientType: method.ClientType,
QrcodeTitle: method.QrcodeTitle,
},
}, nil
}
// FindAllEnabledOrderMethods 查找所有支付方式
func (this *OrderMethodService) FindAllEnabledOrderMethods(ctx context.Context, req *pb.FindAllEnabledOrderMethodsRequest) (*pb.FindAllEnabledOrderMethodsResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
methods, err := accounts.SharedOrderMethodDAO.FindAllEnabledMethodOrders(tx)
if err != nil {
return nil, err
}
var pbMethods = []*pb.OrderMethod{}
for _, method := range methods {
// 防止secret泄露
if userId > 0 {
method.Secret = ""
}
pbMethods = append(pbMethods, &pb.OrderMethod{
Id: int64(method.Id),
Name: method.Name,
Code: method.Code,
Description: method.Description,
Url: method.Url,
Secret: method.Secret,
IsOn: method.IsOn,
ParentCode: method.ParentCode, // 不要返回params以防止泄露
ClientType: method.ClientType,
})
}
return &pb.FindAllEnabledOrderMethodsResponse{
OrderMethods: pbMethods,
}, nil
}
// FindAllAvailableOrderMethods 查找所有已启用的支付方式
func (this *OrderMethodService) FindAllAvailableOrderMethods(ctx context.Context, req *pb.FindAllAvailableOrderMethodsRequest) (*pb.FindAllAvailableOrderMethodsResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
methods, err := accounts.SharedOrderMethodDAO.FindAllEnabledAndOnMethodOrders(tx)
if err != nil {
return nil, err
}
var pbMethods = []*pb.OrderMethod{}
for _, method := range methods {
// 防止secret泄露
if userId > 0 {
method.Secret = ""
}
pbMethods = append(pbMethods, &pb.OrderMethod{
Id: int64(method.Id),
Name: method.Name,
Code: method.Code,
Description: method.Description,
Url: method.Url,
Secret: method.Secret,
IsOn: method.IsOn,
ParentCode: method.ParentCode, // 不返回params防止泄露
ClientType: method.ClientType,
})
}
return &pb.FindAllAvailableOrderMethodsResponse{
OrderMethods: pbMethods,
}, nil
}

View File

@@ -0,0 +1,195 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build plus
package accounts
import (
"context"
"encoding/json"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/accounts"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/dbs"
"github.com/iwind/TeaGo/maps"
)
// UserAccountService 用户账户相关服务
type UserAccountService struct {
services.BaseService
}
// CountUserAccounts 计算账户数量
func (this *UserAccountService) CountUserAccounts(ctx context.Context, req *pb.CountUserAccountsRequest) (*pb.RPCCountResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
count, err := accounts.SharedUserAccountDAO.CountAllAccounts(tx, req.Keyword)
if err != nil {
return nil, err
}
return this.SuccessCount(count)
}
// ListUserAccounts 列出单页账户
func (this *UserAccountService) ListUserAccounts(ctx context.Context, req *pb.ListUserAccountsRequest) (*pb.ListUserAccountsResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
userAccounts, err := accounts.SharedUserAccountDAO.ListAccounts(tx, req.Keyword, req.Offset, req.Size)
if err != nil {
return nil, err
}
var pbAccounts = []*pb.UserAccount{}
for _, account := range userAccounts {
// 用户
user, err := models.SharedUserDAO.FindEnabledUser(tx, int64(account.UserId), nil)
if err != nil {
return nil, err
}
var pbUser = &pb.User{}
if user != nil {
pbUser = &pb.User{
Id: int64(user.Id),
Username: user.Username,
Fullname: user.Fullname,
}
}
pbAccounts = append(pbAccounts, &pb.UserAccount{
Id: int64(account.Id),
UserId: int64(account.UserId),
Total: account.Total,
TotalFrozen: account.TotalFrozen,
User: pbUser,
})
}
return &pb.ListUserAccountsResponse{UserAccounts: pbAccounts}, nil
}
// FindEnabledUserAccountWithUserId 根据用户ID查找单个账户
func (this *UserAccountService) FindEnabledUserAccountWithUserId(ctx context.Context, req *pb.FindEnabledUserAccountWithUserIdRequest) (*pb.FindEnabledUserAccountWithUserIdResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
if userId > 0 {
req.UserId = userId
}
var tx = this.NullTx()
account, err := accounts.SharedUserAccountDAO.FindUserAccountWithUserId(tx, req.UserId)
if err != nil {
return nil, err
}
if account == nil {
return &pb.FindEnabledUserAccountWithUserIdResponse{UserAccount: nil}, nil
}
// 用户
user, err := models.SharedUserDAO.FindEnabledUser(tx, int64(account.UserId), nil)
if err != nil {
return nil, err
}
var pbUser = &pb.User{}
if user != nil {
pbUser = &pb.User{
Id: int64(user.Id),
Username: user.Username,
Fullname: user.Fullname,
}
}
return &pb.FindEnabledUserAccountWithUserIdResponse{
UserAccount: &pb.UserAccount{
Id: int64(account.Id),
UserId: int64(account.UserId),
Total: account.Total,
TotalFrozen: account.TotalFrozen,
User: pbUser,
},
}, nil
}
// FindEnabledUserAccount 查找单个账户
func (this *UserAccountService) FindEnabledUserAccount(ctx context.Context, req *pb.FindEnabledUserAccountRequest) (*pb.FindEnabledUserAccountResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
if userId > 0 {
err = accounts.SharedUserAccountDAO.CheckUserAccount(tx, userId, req.UserAccountId)
if err != nil {
return nil, err
}
}
account, err := accounts.SharedUserAccountDAO.FindUserAccountWithAccountId(tx, req.UserAccountId)
if err != nil {
return nil, err
}
if account == nil {
return &pb.FindEnabledUserAccountResponse{UserAccount: nil}, nil
}
// 用户
user, err := models.SharedUserDAO.FindEnabledUser(tx, int64(account.UserId), nil)
if err != nil {
return nil, err
}
var pbUser = &pb.User{}
if user != nil {
pbUser = &pb.User{
Id: int64(user.Id),
Username: user.Username,
Fullname: user.Fullname,
}
}
return &pb.FindEnabledUserAccountResponse{
UserAccount: &pb.UserAccount{
Id: int64(account.Id),
UserId: int64(account.UserId),
Total: account.Total,
TotalFrozen: account.TotalFrozen,
User: pbUser,
},
}, nil
}
// UpdateUserAccount 修改用户账户
func (this *UserAccountService) UpdateUserAccount(ctx context.Context, req *pb.UpdateUserAccountRequest) (*pb.RPCSuccess, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var params = maps.Map{}
if len(req.ParamsJSON) > 0 {
err = json.Unmarshal(req.ParamsJSON, &params)
if err != nil {
return nil, err
}
}
err = this.RunTx(func(tx *dbs.Tx) error {
err := accounts.SharedUserAccountDAO.UpdateUserAccount(tx, req.UserAccountId, req.Delta, req.EventType, req.Description, params)
if err != nil {
return err
}
return nil
})
if err != nil {
return nil, err
}
return this.Success()
}

View File

@@ -0,0 +1,132 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build plus
package accounts
import (
"context"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/accounts"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/lists"
"strings"
)
// UserAccountDailyStatService 用户账户统计服务
type UserAccountDailyStatService struct {
services.BaseService
}
// ListUserAccountDailyStats 列出按天统计
func (this *UserAccountDailyStatService) ListUserAccountDailyStats(ctx context.Context, req *pb.ListUserAccountDailyStatsRequest) (*pb.ListUserAccountDailyStatsResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var dayFrom = req.DayFrom
var dayTo = req.DayTo
dayFrom = strings.ReplaceAll(dayFrom, "-", "")
dayTo = strings.ReplaceAll(dayTo, "-", "")
days, err := utils.RangeDays(dayFrom, dayTo)
if err != nil {
return nil, err
}
if len(days) == 0 {
return &pb.ListUserAccountDailyStatsResponse{Stats: nil}, nil
}
var tx = this.NullTx()
stats, err := accounts.SharedUserAccountDailyStatDAO.FindDailyStats(tx, dayFrom, dayTo)
if err != nil {
return nil, err
}
var statMap = map[string]*accounts.UserAccountDailyStat{} // day => Stat
for _, stat := range stats {
statMap[stat.Day] = stat
}
var pbStats = []*pb.ListUserAccountDailyStatsResponse_Stat{}
for _, day := range days {
stat, ok := statMap[day]
if ok {
pbStats = append(pbStats, &pb.ListUserAccountDailyStatsResponse_Stat{
Day: day,
Income: float32(stat.Income),
Expense: float32(stat.Expense),
})
} else {
pbStats = append(pbStats, &pb.ListUserAccountDailyStatsResponse_Stat{
Day: day,
Income: 0,
Expense: 0,
})
}
}
// 反向排序
lists.Reverse(pbStats)
return &pb.ListUserAccountDailyStatsResponse{Stats: pbStats}, nil
}
// ListUserAccountMonthlyStats 列出按月统计
func (this *UserAccountDailyStatService) ListUserAccountMonthlyStats(ctx context.Context, req *pb.ListUserAccountMonthlyStatsRequest) (*pb.ListUserAccountMonthlyStatsResponse, error) {
_, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var dayFrom = req.DayFrom
var dayTo = req.DayTo
dayFrom = strings.ReplaceAll(dayFrom, "-", "")
dayTo = strings.ReplaceAll(dayTo, "-", "")
months, err := utils.RangeMonths(dayFrom, dayTo)
if err != nil {
return nil, err
}
if len(months) == 0 {
return &pb.ListUserAccountMonthlyStatsResponse{Stats: nil}, nil
}
var tx = this.NullTx()
stats, err := accounts.SharedUserAccountDailyStatDAO.FindMonthlyStats(tx, dayFrom, dayTo)
if err != nil {
return nil, err
}
var statMap = map[string]*accounts.UserAccountDailyStat{} // month => Stat
for _, stat := range stats {
statMap[stat.Month] = stat
}
var pbStats = []*pb.ListUserAccountMonthlyStatsResponse_Stat{}
for _, month := range months {
stat, ok := statMap[month]
if ok {
pbStats = append(pbStats, &pb.ListUserAccountMonthlyStatsResponse_Stat{
Month: month,
Income: float32(stat.Income),
Expense: float32(stat.Expense),
})
} else {
pbStats = append(pbStats, &pb.ListUserAccountMonthlyStatsResponse_Stat{
Month: month,
Income: 0,
Expense: 0,
})
}
}
// 反向排序
lists.Reverse(pbStats)
return &pb.ListUserAccountMonthlyStatsResponse{Stats: pbStats}, nil
}

View File

@@ -0,0 +1,81 @@
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build plus
package accounts
import (
"context"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/accounts"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
)
// UserAccountLogService 用户账户日志服务
type UserAccountLogService struct {
services.BaseService
}
// CountUserAccountLogs 计算日志数量
func (this *UserAccountLogService) CountUserAccountLogs(ctx context.Context, req *pb.CountUserAccountLogsRequest) (*pb.RPCCountResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
count, err := accounts.SharedUserAccountLogDAO.CountAccountLogs(tx, userId, req.UserAccountId, req.Keyword, req.EventType)
if err != nil {
return nil, err
}
return this.SuccessCount(count)
}
// ListUserAccountLogs 列出单页日志
func (this *UserAccountLogService) ListUserAccountLogs(ctx context.Context, req *pb.ListUserAccountLogsRequest) (*pb.ListUserAccountLogsResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
accountLogs, err := accounts.SharedUserAccountLogDAO.ListAccountLogs(tx, userId, req.UserAccountId, req.Keyword, req.EventType, req.Offset, req.Size)
if err != nil {
return nil, err
}
var pbLogs = []*pb.UserAccountLog{}
var cacheMap = utils.NewCacheMap()
for _, log := range accountLogs {
// 用户
var pbUser = &pb.User{Id: int64(log.UserId)}
user, err := models.SharedUserDAO.FindEnabledUser(tx, int64(log.UserId), cacheMap)
if err != nil {
return nil, err
}
if user != nil {
pbUser = &pb.User{Id: int64(user.Id), Fullname: user.Fullname, Username: user.Username}
}
// 账户
var pbAccount = &pb.UserAccount{Id: int64(log.AccountId)}
pbLogs = append(pbLogs, &pb.UserAccountLog{
Id: int64(log.Id),
UserId: int64(log.UserId),
UserAccountId: int64(log.AccountId),
Delta: log.Delta,
DeltaFrozen: log.DeltaFrozen,
Total: log.Total,
TotalFrozen: log.TotalFrozen,
EventType: log.EventType,
Description: log.Description,
CreatedAt: int64(log.CreatedAt),
ParamsJSON: log.Params,
User: pbUser,
UserAccount: pbAccount,
})
}
return &pb.ListUserAccountLogsResponse{UserAccountLogs: pbLogs}, nil
}

View File

@@ -0,0 +1,342 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
//go:build plus
package accounts
import (
"context"
"encoding/json"
"errors"
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
"github.com/TeaOSLab/EdgeAPI/internal/db/models/accounts"
"github.com/TeaOSLab/EdgeAPI/internal/payments"
"github.com/TeaOSLab/EdgeAPI/internal/rpc/services"
"github.com/TeaOSLab/EdgeAPI/internal/utils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/iwind/TeaGo/dbs"
"net/url"
)
// UserOrderService 用户订单相关服务
type UserOrderService struct {
services.BaseService
}
// CreateUserOrder 创建订单
func (this *UserOrderService) CreateUserOrder(ctx context.Context, req *pb.CreateUserOrderRequest) (*pb.CreateUserOrderResponse, error) {
userId, err := this.ValidateUserNode(ctx, false)
if err != nil {
return nil, err
}
if !userconfigs.IsValidOrderType(req.Type) {
return nil, errors.New("invalid order type '" + req.Type + "'")
}
var tx = this.NullTx()
method, err := accounts.SharedOrderMethodDAO.FindEnabledOrderMethodWithCode(tx, req.OrderMethodCode)
if err != nil {
return nil, err
}
if method == nil {
return nil, errors.New("can not find order method with code '" + req.OrderMethodCode + "'")
}
if !method.IsOn {
return nil, errors.New("method is not enabled")
}
var methodId = int64(method.Id)
if req.Amount <= 0 {
return nil, errors.New("'amount' should be greater than 0")
}
var orderCode = ""
err = this.RunTx(func(tx *dbs.Tx) error {
_, code, err := accounts.SharedUserOrderDAO.CreateOrder(tx, 0, userId, req.Type, methodId, req.Amount, req.ParamsJSON)
if err != nil {
return err
}
orderCode = code
return nil
})
if err != nil {
return nil, err
}
order, err := accounts.SharedUserOrderDAO.FindUserOrderWithCode(tx, orderCode)
if err != nil {
return nil, err
}
if order == nil {
return nil, errors.New("can not find order with generated code '" + orderCode + "'")
}
payURL, err := payments.GeneratePayURL(order, method)
if err != nil {
return nil, errors.New("generate pay url failed: " + err.Error())
}
return &pb.CreateUserOrderResponse{
Code: orderCode,
PayURL: payURL,
}, nil
}
// FindEnabledUserOrder 查看订单
func (this *UserOrderService) FindEnabledUserOrder(ctx context.Context, req *pb.FindEnabledUserOrderRequest) (*pb.FindEnabledUserOrderResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
order, err := accounts.SharedUserOrderDAO.FindUserOrderWithCode(tx, req.Code)
if err != nil {
return nil, err
}
if order == nil {
return &pb.FindEnabledUserOrderResponse{UserOrder: nil}, nil
}
// 检查用户权限
if userId > 0 {
if int64(order.UserId) != userId {
return &pb.FindEnabledUserOrderResponse{UserOrder: nil}, nil
}
}
// 用户
var cacheMap = utils.NewCacheMap()
user, err := models.SharedUserDAO.FindEnabledUser(tx, int64(order.UserId), cacheMap)
if err != nil {
return nil, err
}
var pbUser *pb.User
if user != nil {
pbUser = &pb.User{
Id: int64(user.Id),
Username: user.Username,
Fullname: user.Fullname,
}
}
// 支付方式
method, err := accounts.SharedOrderMethodDAO.FindEnabledOrderMethod(tx, int64(order.MethodId))
if err != nil {
return nil, err
}
var pbMethod *pb.OrderMethod
if method != nil {
pbMethod = &pb.OrderMethod{
Id: int64(method.Id),
Name: method.Name,
Code: method.Code,
IsOn: method.IsOn,
ParentCode: method.ParentCode,
ClientType: method.ClientType,
QrcodeTitle: method.QrcodeTitle,
}
}
// 支付URL
payURL, err := payments.GeneratePayURL(order, method)
if err != nil {
return nil, err
}
return &pb.FindEnabledUserOrderResponse{UserOrder: &pb.UserOrder{
UserId: int64(order.UserId),
Code: order.Code,
Type: order.Type,
OrderMethodId: int64(order.MethodId),
Status: order.Status,
Amount: float32(order.Amount),
ParamsJSON: order.Params,
CreatedAt: int64(order.CreatedAt),
CancelledAt: int64(order.CancelledAt),
FinishedAt: int64(order.FinishedAt),
IsExpired: order.IsExpired(),
User: pbUser,
OrderMethod: pbMethod,
CanPay: !order.IsExpired() && order.Status == userconfigs.OrderStatusNone,
PayURL: payURL,
}}, nil
}
// CancelUserOrder 取消订单
func (this *UserOrderService) CancelUserOrder(ctx context.Context, req *pb.CancelUserOrderRequest) (*pb.RPCSuccess, error) {
adminId, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
var tx = this.NullTx()
order, err := accounts.SharedUserOrderDAO.FindUserOrderWithCode(tx, req.Code)
if err != nil {
return nil, err
}
if order == nil {
return nil, errors.New("can not find order")
}
if userId > 0 {
if int64(order.UserId) != userId {
return nil, errors.New("can not find order")
}
}
err = this.RunTx(func(tx *dbs.Tx) error {
return accounts.SharedUserOrderDAO.CancelOrder(tx, adminId, userId, int64(order.Id))
})
if err != nil {
return nil, err
}
return this.Success()
}
// FinishUserOrder 完成订单
func (this *UserOrderService) FinishUserOrder(ctx context.Context, req *pb.FinishUserOrderRequest) (*pb.RPCSuccess, error) {
adminId, err := this.ValidateAdmin(ctx)
if err != nil {
return nil, err
}
var tx = this.NullTx()
order, err := accounts.SharedUserOrderDAO.FindUserOrderWithCode(tx, req.Code)
if err != nil {
return nil, err
}
if order == nil {
return nil, errors.New("can not find order")
}
err = this.RunTx(func(tx *dbs.Tx) error {
return accounts.SharedUserOrderDAO.FinishOrder(tx, adminId, 0, int64(order.Id))
})
if err != nil {
return nil, err
}
return this.Success()
}
// CountEnabledUserOrders 计算订单数量
func (this *UserOrderService) CountEnabledUserOrders(ctx context.Context, req *pb.CountEnabledUserOrdersRequest) (*pb.RPCCountResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
if userId > 0 {
req.UserId = userId
}
var tx = this.NullTx()
count, err := accounts.SharedUserOrderDAO.CountEnabledUserOrders(tx, req.UserId, req.Status, req.Keyword)
if err != nil {
return nil, err
}
return this.SuccessCount(count)
}
// ListEnabledUserOrders 列出单页订单
func (this *UserOrderService) ListEnabledUserOrders(ctx context.Context, req *pb.ListEnabledUserOrdersRequest) (*pb.ListEnabledUserOrdersResponse, error) {
_, userId, err := this.ValidateAdminAndUser(ctx, true)
if err != nil {
return nil, err
}
if userId > 0 {
req.UserId = userId
}
var tx = this.NullTx()
orders, err := accounts.SharedUserOrderDAO.ListEnabledUserOrders(tx, req.UserId, req.Status, req.Keyword, req.Offset, req.Size)
if err != nil {
return nil, err
}
var pbOrders = []*pb.UserOrder{}
var cacheMap = utils.NewCacheMap()
for _, order := range orders {
// 用户
user, err := models.SharedUserDAO.FindEnabledUser(tx, int64(order.UserId), cacheMap)
if err != nil {
return nil, err
}
var pbUser *pb.User
if user != nil {
pbUser = &pb.User{
Id: int64(user.Id),
Username: user.Username,
Fullname: user.Fullname,
}
}
// 支付方式
method, err := accounts.SharedOrderMethodDAO.FindEnabledOrderMethod(tx, int64(order.MethodId))
if err != nil {
return nil, err
}
var pbMethod *pb.OrderMethod
if method != nil {
pbMethod = &pb.OrderMethod{
Id: int64(method.Id),
Name: method.Name,
Code: method.Code,
IsOn: method.IsOn,
}
}
pbOrders = append(pbOrders, &pb.UserOrder{
UserId: int64(order.UserId),
Code: order.Code,
Type: order.Type,
OrderMethodId: int64(order.MethodId),
Status: order.Status,
Amount: float32(order.Amount),
ParamsJSON: order.Params,
CreatedAt: int64(order.CreatedAt),
CancelledAt: int64(order.CancelledAt),
FinishedAt: int64(order.FinishedAt),
IsExpired: order.IsExpired(),
User: pbUser,
OrderMethod: pbMethod,
})
}
return &pb.ListEnabledUserOrdersResponse{
UserOrders: pbOrders,
}, nil
}
// NotifyUserOrderPayment 订单支付通知
func (this *UserOrderService) NotifyUserOrderPayment(ctx context.Context, req *pb.NotifyUserOrderPaymentRequest) (*pb.RPCSuccess, error) {
userId, err := this.ValidateUserNode(ctx, false)
if err != nil {
return nil, err
}
var formValues = url.Values{}
err = json.Unmarshal(req.FormData, &formValues)
if err != nil {
return nil, errors.New("decode form values failed: " + err.Error())
}
err = this.RunTx(func(tx *dbs.Tx) error {
// 校验检查订单
orderId, err := payments.Verify(req.PayMethod, formValues)
if err != nil {
return err
}
return accounts.SharedUserOrderDAO.FinishOrder(tx, 0, userId, orderId)
})
if err != nil {
return nil, err
}
return this.Success()
}