Initial commit (code only without large binaries)
This commit is contained in:
33
EdgeAPI/internal/db/models/accounts/order_method_dao.go
Normal file
33
EdgeAPI/internal/db/models/accounts/order_method_dao.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
)
|
||||
|
||||
const (
|
||||
OrderMethodStateEnabled = 1 // 已启用
|
||||
OrderMethodStateDisabled = 0 // 已禁用
|
||||
)
|
||||
|
||||
type OrderMethodDAO dbs.DAO
|
||||
|
||||
func NewOrderMethodDAO() *OrderMethodDAO {
|
||||
return dbs.NewDAO(&OrderMethodDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeOrderMethods",
|
||||
Model: new(OrderMethod),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*OrderMethodDAO)
|
||||
}
|
||||
|
||||
var SharedOrderMethodDAO *OrderMethodDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedOrderMethodDAO = NewOrderMethodDAO()
|
||||
})
|
||||
}
|
||||
180
EdgeAPI/internal/db/models/accounts/order_method_dao_plus.go
Normal file
180
EdgeAPI/internal/db/models/accounts/order_method_dao_plus.go
Normal file
@@ -0,0 +1,180 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
)
|
||||
|
||||
// EnableOrderMethod 启用条目
|
||||
func (this *OrderMethodDAO) EnableOrderMethod(tx *dbs.Tx, id uint32) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Set("state", OrderMethodStateEnabled).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// DisableOrderMethod 禁用条目
|
||||
func (this *OrderMethodDAO) DisableOrderMethod(tx *dbs.Tx, id int64) error {
|
||||
_, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Set("state", OrderMethodStateDisabled).
|
||||
Update()
|
||||
return err
|
||||
}
|
||||
|
||||
// FindEnabledOrderMethod 查找支付方式
|
||||
func (this *OrderMethodDAO) FindEnabledOrderMethod(tx *dbs.Tx, id int64) (*OrderMethod, error) {
|
||||
result, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Attr("state", OrderMethodStateEnabled).
|
||||
Find()
|
||||
if result == nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(*OrderMethod), err
|
||||
}
|
||||
|
||||
// FindEnabledBasicOrderMethod 查找支付方式基本信息
|
||||
func (this *OrderMethodDAO) FindEnabledBasicOrderMethod(tx *dbs.Tx, id int64) (*OrderMethod, error) {
|
||||
result, err := this.Query(tx).
|
||||
Pk(id).
|
||||
Result("id", "code", "url", "isOn", "secret", "parentCode", "clientType").
|
||||
Attr("state", OrderMethodStateEnabled).
|
||||
Find()
|
||||
if err != nil || result == nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(*OrderMethod), err
|
||||
}
|
||||
|
||||
// FindEnabledOrderMethodWithCode 根据代号查找支付方式
|
||||
func (this *OrderMethodDAO) FindEnabledOrderMethodWithCode(tx *dbs.Tx, code string) (*OrderMethod, error) {
|
||||
result, err := this.Query(tx).
|
||||
Attr("code", code).
|
||||
Attr("state", OrderMethodStateEnabled).
|
||||
Find()
|
||||
if result == nil {
|
||||
return nil, err
|
||||
}
|
||||
return result.(*OrderMethod), err
|
||||
}
|
||||
|
||||
// ExistOrderMethodWithCode 根据代号检查支付方式是否存在
|
||||
func (this *OrderMethodDAO) ExistOrderMethodWithCode(tx *dbs.Tx, code string, excludingMethodId int64) (bool, error) {
|
||||
var query = this.Query(tx)
|
||||
if excludingMethodId > 0 {
|
||||
query.Neq("id", excludingMethodId)
|
||||
}
|
||||
return query.
|
||||
Attr("code", code).
|
||||
Attr("state", OrderMethodStateEnabled).
|
||||
Exist()
|
||||
}
|
||||
|
||||
// FindOrderMethodName 根据主键查找名称
|
||||
func (this *OrderMethodDAO) FindOrderMethodName(tx *dbs.Tx, id int64) (string, error) {
|
||||
return this.Query(tx).
|
||||
Pk(id).
|
||||
Result("name").
|
||||
FindStringCol("")
|
||||
}
|
||||
|
||||
// CreateMethod 创建支付方式
|
||||
func (this *OrderMethodDAO) CreateMethod(tx *dbs.Tx, name string, code string, url string, description string, parentCode string, params any, clientType userconfigs.PayClientType, qrcodeTitle string) (int64, error) {
|
||||
var op = NewOrderMethodOperator()
|
||||
op.Name = name
|
||||
op.Code = code
|
||||
|
||||
op.Url = url
|
||||
|
||||
op.ParentCode = parentCode
|
||||
if params != nil {
|
||||
paramsJSON, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
op.Params = paramsJSON
|
||||
}
|
||||
|
||||
op.Description = description
|
||||
op.Secret = utils.Sha1RandomString()
|
||||
op.ClientType = clientType
|
||||
op.QrcodeTitle = qrcodeTitle
|
||||
op.IsOn = true
|
||||
op.State = OrderMethodStateEnabled
|
||||
return this.SaveInt64(tx, op)
|
||||
}
|
||||
|
||||
// UpdateMethod 修改支付方式
|
||||
// 切记不允许修改parentCode
|
||||
func (this *OrderMethodDAO) UpdateMethod(tx *dbs.Tx, methodId int64, name string, code string, url string, description string, params any, clientType userconfigs.PayClientType, qrcodeTitle string, isOn bool) error {
|
||||
if methodId <= 0 {
|
||||
return errors.New("invalid methodId")
|
||||
}
|
||||
|
||||
var op = NewOrderMethodOperator()
|
||||
op.Id = methodId
|
||||
op.Name = name
|
||||
op.Code = code
|
||||
op.Url = url
|
||||
op.Description = description
|
||||
|
||||
if params != nil {
|
||||
paramsJSON, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
op.Params = paramsJSON
|
||||
}
|
||||
|
||||
op.ClientType = clientType
|
||||
op.QrcodeTitle = qrcodeTitle
|
||||
|
||||
op.IsOn = isOn
|
||||
return this.Save(tx, op)
|
||||
}
|
||||
|
||||
// UpdateMethodOrders 修改排序
|
||||
func (this *OrderMethodDAO) UpdateMethodOrders(tx *dbs.Tx, methodIds []int64) error {
|
||||
var maxOrder = len(methodIds)
|
||||
for index, methodId := range methodIds {
|
||||
err := this.Query(tx).
|
||||
Pk(methodId).
|
||||
Set("order", maxOrder-index).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindAllEnabledMethodOrders 查找所有支付方式
|
||||
func (this *OrderMethodDAO) FindAllEnabledMethodOrders(tx *dbs.Tx) (result []*OrderMethod, err error) {
|
||||
_, err = this.Query(tx).
|
||||
State(OrderMethodStateEnabled).
|
||||
Desc("order").
|
||||
AscPk().
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// FindAllEnabledAndOnMethodOrders 查找所有已启用的支付方式
|
||||
func (this *OrderMethodDAO) FindAllEnabledAndOnMethodOrders(tx *dbs.Tx) (result []*OrderMethod, err error) {
|
||||
_, err = this.Query(tx).
|
||||
State(OrderMethodStateEnabled).
|
||||
Attr("isOn", true).
|
||||
Desc("order").
|
||||
AscPk().
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package accounts_test
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
)
|
||||
40
EdgeAPI/internal/db/models/accounts/order_method_model.go
Normal file
40
EdgeAPI/internal/db/models/accounts/order_method_model.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package accounts
|
||||
|
||||
import "github.com/iwind/TeaGo/dbs"
|
||||
|
||||
// OrderMethod 订单支付方式
|
||||
type OrderMethod struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
Name string `field:"name"` // 名称
|
||||
IsOn bool `field:"isOn"` // 是否启用
|
||||
Description string `field:"description"` // 描述
|
||||
ParentCode string `field:"parentCode"` // 内置的父级代号
|
||||
Code string `field:"code"` // 代号
|
||||
Url string `field:"url"` // URL
|
||||
Secret string `field:"secret"` // 密钥
|
||||
Params dbs.JSON `field:"params"` // 参数
|
||||
ClientType string `field:"clientType"` // 客户端类型
|
||||
QrcodeTitle string `field:"qrcodeTitle"` // 二维码标题
|
||||
Order uint32 `field:"order"` // 排序
|
||||
State uint8 `field:"state"` // 状态
|
||||
}
|
||||
|
||||
type OrderMethodOperator struct {
|
||||
Id any // ID
|
||||
Name any // 名称
|
||||
IsOn any // 是否启用
|
||||
Description any // 描述
|
||||
ParentCode any // 内置的父级代号
|
||||
Code any // 代号
|
||||
Url any // URL
|
||||
Secret any // 密钥
|
||||
Params any // 参数
|
||||
ClientType any // 客户端类型
|
||||
QrcodeTitle any // 二维码标题
|
||||
Order any // 排序
|
||||
State any // 状态
|
||||
}
|
||||
|
||||
func NewOrderMethodOperator() *OrderMethodOperator {
|
||||
return &OrderMethodOperator{}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package accounts
|
||||
@@ -0,0 +1,82 @@
|
||||
//go:build plus
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type UserAccountDailyStatDAO dbs.DAO
|
||||
|
||||
func NewUserAccountDailyStatDAO() *UserAccountDailyStatDAO {
|
||||
return dbs.NewDAO(&UserAccountDailyStatDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeUserAccountDailyStats",
|
||||
Model: new(UserAccountDailyStat),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*UserAccountDailyStatDAO)
|
||||
}
|
||||
|
||||
var SharedUserAccountDailyStatDAO *UserAccountDailyStatDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedUserAccountDailyStatDAO = NewUserAccountDailyStatDAO()
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateDailyStat 更新当天统计数据
|
||||
func (this *UserAccountDailyStatDAO) UpdateDailyStat(tx *dbs.Tx) error {
|
||||
var day = timeutil.Format("Ymd")
|
||||
var month = timeutil.Format("Ym")
|
||||
income, err := SharedUserAccountLogDAO.SumDailyEventTypes(tx, day, userconfigs.AccountIncomeEventTypes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
expense, err := SharedUserAccountLogDAO.SumDailyEventTypes(tx, day, userconfigs.AccountExpenseEventTypes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if expense < 0 {
|
||||
expense = -expense
|
||||
}
|
||||
|
||||
return this.Query(tx).
|
||||
InsertOrUpdateQuickly(maps.Map{
|
||||
"day": day,
|
||||
"month": month,
|
||||
"income": income,
|
||||
"expense": expense,
|
||||
}, maps.Map{
|
||||
"income": income,
|
||||
"expense": expense,
|
||||
})
|
||||
}
|
||||
|
||||
// FindDailyStats 查看按天统计
|
||||
func (this *UserAccountDailyStatDAO) FindDailyStats(tx *dbs.Tx, dayFrom string, dayTo string) (result []*UserAccountDailyStat, err error) {
|
||||
_, err = this.Query(tx).
|
||||
Between("day", dayFrom, dayTo).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// FindMonthlyStats 查看某月统计
|
||||
func (this *UserAccountDailyStatDAO) FindMonthlyStats(tx *dbs.Tx, dayFrom string, dayTo string) (result []*UserAccountDailyStat, err error) {
|
||||
_, err = this.Query(tx).
|
||||
Result("SUM(income) AS income", "SUM(expense) AS expense", "month").
|
||||
Between("day", dayFrom, dayTo).
|
||||
Group("month").
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
)
|
||||
@@ -0,0 +1,22 @@
|
||||
package accounts
|
||||
|
||||
// UserAccountDailyStat 账户每日统计
|
||||
type UserAccountDailyStat struct {
|
||||
Id uint32 `field:"id"` // ID
|
||||
Day string `field:"day"` // YYYYMMDD
|
||||
Month string `field:"month"` // YYYYMM
|
||||
Income float64 `field:"income"` // 收入
|
||||
Expense float64 `field:"expense"` // 支出
|
||||
}
|
||||
|
||||
type UserAccountDailyStatOperator struct {
|
||||
Id interface{} // ID
|
||||
Day interface{} // YYYYMMDD
|
||||
Month interface{} // YYYYMM
|
||||
Income interface{} // 收入
|
||||
Expense interface{} // 支出
|
||||
}
|
||||
|
||||
func NewUserAccountDailyStatOperator() *UserAccountDailyStatOperator {
|
||||
return &UserAccountDailyStatOperator{}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package accounts
|
||||
264
EdgeAPI/internal/db/models/accounts/user_account_dao_plus.go
Normal file
264
EdgeAPI/internal/db/models/accounts/user_account_dao_plus.go
Normal file
@@ -0,0 +1,264 @@
|
||||
//go:build plus
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/goman"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
"time"
|
||||
)
|
||||
|
||||
func init() {
|
||||
dbs.OnReadyDone(func() {
|
||||
goman.New(func() {
|
||||
// 自动支付账单任务
|
||||
var ticker = time.NewTicker(6 * time.Hour)
|
||||
for range ticker.C {
|
||||
if SharedUserAccountDAO.Instance != nil {
|
||||
err := SharedUserAccountDAO.Instance.RunTx(func(tx *dbs.Tx) error {
|
||||
return SharedUserAccountDAO.PayBillsAutomatically(tx)
|
||||
})
|
||||
if err != nil {
|
||||
remotelogs.Error("USER_ACCOUNT_DAO", "pay bills task failed: "+err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
type UserAccountDAO dbs.DAO
|
||||
|
||||
func NewUserAccountDAO() *UserAccountDAO {
|
||||
return dbs.NewDAO(&UserAccountDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeUserAccounts",
|
||||
Model: new(UserAccount),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*UserAccountDAO)
|
||||
}
|
||||
|
||||
var SharedUserAccountDAO *UserAccountDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedUserAccountDAO = NewUserAccountDAO()
|
||||
})
|
||||
}
|
||||
|
||||
// FindUserAccountWithUserId 根据用户ID查找用户账户
|
||||
func (this *UserAccountDAO) FindUserAccountWithUserId(tx *dbs.Tx, userId int64) (*UserAccount, error) {
|
||||
if userId <= 0 {
|
||||
return nil, errors.New("invalid userId '" + types.String(userId) + "'")
|
||||
}
|
||||
|
||||
// 用户是否存在
|
||||
user, err := models.SharedUserDAO.FindEnabledUser(tx, userId, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if user == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
account, err := this.Query(tx).
|
||||
Attr("userId", userId).
|
||||
Find()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if account != nil {
|
||||
return account.(*UserAccount), nil
|
||||
}
|
||||
|
||||
var op = NewUserAccountOperator()
|
||||
op.UserId = userId
|
||||
_, err = this.SaveInt64(tx, op)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return this.FindUserAccountWithUserId(tx, userId)
|
||||
}
|
||||
|
||||
// FindUserAccountWithAccountId 根据ID查找用户账户
|
||||
func (this *UserAccountDAO) FindUserAccountWithAccountId(tx *dbs.Tx, accountId int64) (*UserAccount, error) {
|
||||
one, err := this.Query(tx).
|
||||
Pk(accountId).
|
||||
Find()
|
||||
if one != nil {
|
||||
return one.(*UserAccount), nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// UpdateUserAccount 操作用户账户
|
||||
func (this *UserAccountDAO) UpdateUserAccount(tx *dbs.Tx, accountId int64, delta float64, eventType userconfigs.AccountEventType, description string, params maps.Map) error {
|
||||
// 截取两位两位小数
|
||||
var realDelta = delta
|
||||
if realDelta < 0 {
|
||||
realDelta = numberutils.FloorFloat64(realDelta, 2)
|
||||
}
|
||||
|
||||
account, err := this.FindUserAccountWithAccountId(tx, accountId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if account == nil {
|
||||
return errors.New("invalid account id '" + types.String(accountId) + "'")
|
||||
}
|
||||
var userId = int64(account.UserId)
|
||||
if delta < 0 && account.Total < -delta {
|
||||
return errors.New("not enough account quota to decrease")
|
||||
}
|
||||
|
||||
// 操作账户
|
||||
err = this.Query(tx).
|
||||
Pk(account.Id).
|
||||
Set("total", dbs.SQL("total+:delta")).
|
||||
Param("delta", realDelta).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 生成日志
|
||||
err = SharedUserAccountLogDAO.CreateAccountLog(tx, userId, accountId, realDelta, 0, eventType, description, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateUserAccountFrozen 操作用户账户冻结余额
|
||||
func (this *UserAccountDAO) UpdateUserAccountFrozen(tx *dbs.Tx, userId int64, delta float64, eventType userconfigs.AccountEventType, description string, params maps.Map) error {
|
||||
account, err := this.FindUserAccountWithUserId(tx, userId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if account == nil {
|
||||
return errors.New("invalid user account")
|
||||
}
|
||||
var deltaFloat64 = delta
|
||||
if deltaFloat64 < 0 && account.TotalFrozen < -deltaFloat64 {
|
||||
return errors.New("not enough account frozen quota to decrease")
|
||||
}
|
||||
|
||||
// 操作账户
|
||||
err = this.Query(tx).
|
||||
Pk(account.Id).
|
||||
Set("totalFrozen", dbs.SQL("total+:delta")).
|
||||
Param("delta", delta).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 生成日志
|
||||
err = SharedUserAccountLogDAO.CreateAccountLog(tx, userId, int64(account.Id), 0, delta, eventType, description, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CountAllAccounts 计算所有账户数量
|
||||
func (this *UserAccountDAO) CountAllAccounts(tx *dbs.Tx, keyword string) (int64, error) {
|
||||
var query = this.Query(tx)
|
||||
if len(keyword) > 0 {
|
||||
query.Where("userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword))")
|
||||
query.Param("keyword", keyword)
|
||||
} else {
|
||||
query.Where("userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1)")
|
||||
}
|
||||
return query.Count()
|
||||
}
|
||||
|
||||
// ListAccounts 列出单页账户
|
||||
func (this *UserAccountDAO) ListAccounts(tx *dbs.Tx, keyword string, offset int64, size int64) (result []*UserAccount, err error) {
|
||||
var query = this.Query(tx)
|
||||
if len(keyword) > 0 {
|
||||
query.Where("userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword))")
|
||||
query.Param("keyword", keyword)
|
||||
} else {
|
||||
query.Where("userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1)")
|
||||
}
|
||||
_, err = query.
|
||||
DescPk().
|
||||
Offset(offset).
|
||||
Limit(size).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// PayBills 尝试自动支付账单
|
||||
func (this *UserAccountDAO) PayBillsAutomatically(tx *dbs.Tx) error {
|
||||
bills, err := models.SharedUserBillDAO.FindUnpaidBills(tx, 10000)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 先支付久远的
|
||||
lists.Reverse(bills)
|
||||
|
||||
for _, bill := range bills {
|
||||
if bill.Amount <= 0 {
|
||||
err = models.SharedUserBillDAO.UpdateUserBillIsPaid(tx, int64(bill.Id), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
account, err := SharedUserAccountDAO.FindUserAccountWithUserId(tx, int64(bill.UserId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if account == nil || account.Total < bill.Amount {
|
||||
continue
|
||||
}
|
||||
|
||||
// 扣款
|
||||
err = SharedUserAccountDAO.UpdateUserAccount(tx, int64(account.Id), -bill.Amount, userconfigs.AccountEventTypePayBill, "支付账单"+bill.Code, maps.Map{"billId": bill.Id})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 改为已支付
|
||||
err = models.SharedUserBillDAO.UpdateUserBillIsPaid(tx, int64(bill.Id), true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckUserAccount 检查用户账户
|
||||
func (this *UserAccountDAO) CheckUserAccount(tx *dbs.Tx, userId int64, accountId int64) error {
|
||||
exists, err := this.Query(tx).
|
||||
Pk(accountId).
|
||||
Attr("userId", userId).
|
||||
Exist()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
return models.ErrNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
//go:build plus
|
||||
|
||||
package accounts_test
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/accounts"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUserAccountDAO_PayBills(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
|
||||
err := accounts.NewUserAccountDAO().PayBillsAutomatically(nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
func TestUserAccountDAO_UpdateUserAccount(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
var tx *dbs.Tx
|
||||
var dao = accounts.NewUserAccountDAO()
|
||||
|
||||
err := dao.UpdateUserAccount(tx, 3, -17.88, userconfigs.AccountEventTypePayBill, "test", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
|
||||
// 221745.12
|
||||
func TestUserAccountDAO_UpdateUserAccount2(t *testing.T) {
|
||||
dbs.NotifyReady()
|
||||
var tx *dbs.Tx
|
||||
var dao = accounts.NewUserAccountDAO()
|
||||
|
||||
err := dao.UpdateUserAccount(tx, 3, -221745.12, userconfigs.AccountEventTypePayBill, "test", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log("ok")
|
||||
}
|
||||
131
EdgeAPI/internal/db/models/accounts/user_account_log_dao_plus.go
Normal file
131
EdgeAPI/internal/db/models/accounts/user_account_log_dao_plus.go
Normal file
@@ -0,0 +1,131 @@
|
||||
//go:build plus
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/errors"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
)
|
||||
|
||||
type UserAccountLogDAO dbs.DAO
|
||||
|
||||
func NewUserAccountLogDAO() *UserAccountLogDAO {
|
||||
return dbs.NewDAO(&UserAccountLogDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeUserAccountLogs",
|
||||
Model: new(UserAccountLog),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*UserAccountLogDAO)
|
||||
}
|
||||
|
||||
var SharedUserAccountLogDAO *UserAccountLogDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedUserAccountLogDAO = NewUserAccountLogDAO()
|
||||
})
|
||||
}
|
||||
|
||||
// CreateAccountLog 生成用户账户日志
|
||||
func (this *UserAccountLogDAO) CreateAccountLog(tx *dbs.Tx, userId int64, accountId int64, delta float64, deltaFrozen float64, eventType userconfigs.AccountEventType, description string, params maps.Map) error {
|
||||
var op = NewUserAccountLogOperator()
|
||||
op.UserId = userId
|
||||
op.AccountId = accountId
|
||||
op.Delta = delta
|
||||
op.DeltaFrozen = deltaFrozen
|
||||
|
||||
account, err := SharedUserAccountDAO.FindUserAccountWithAccountId(tx, accountId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if account == nil {
|
||||
return errors.New("invalid account id '" + types.String(accountId) + "'")
|
||||
}
|
||||
op.Total = account.Total
|
||||
op.TotalFrozen = account.TotalFrozen
|
||||
|
||||
op.EventType = eventType
|
||||
op.Description = description
|
||||
|
||||
if params == nil {
|
||||
params = maps.Map{}
|
||||
}
|
||||
op.Params = params.AsJSON()
|
||||
|
||||
op.Day = timeutil.Format("Ymd")
|
||||
err = this.Save(tx, op)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return SharedUserAccountDailyStatDAO.UpdateDailyStat(tx)
|
||||
}
|
||||
|
||||
// CountAccountLogs 计算日志数量
|
||||
func (this *UserAccountLogDAO) CountAccountLogs(tx *dbs.Tx, userId int64, accountId int64, keyword string, eventType string) (int64, error) {
|
||||
var query = this.Query(tx)
|
||||
if userId > 0 {
|
||||
query.Attr("userId", userId)
|
||||
}
|
||||
if accountId > 0 {
|
||||
query.Attr("accountId", accountId)
|
||||
}
|
||||
if len(keyword) > 0 {
|
||||
query.Where("(userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword)) OR description LIKE :keyword)")
|
||||
query.Param("keyword", dbutils.QuoteLike(keyword))
|
||||
}
|
||||
if len(eventType) > 0 {
|
||||
query.Attr("eventType", eventType)
|
||||
}
|
||||
return query.Count()
|
||||
}
|
||||
|
||||
// ListAccountLogs 列出单页日志
|
||||
func (this *UserAccountLogDAO) ListAccountLogs(tx *dbs.Tx, userId int64, accountId int64, keyword string, eventType string, offset int64, size int64) (result []*UserAccountLog, err error) {
|
||||
var query = this.Query(tx)
|
||||
if userId > 0 {
|
||||
query.Attr("userId", userId)
|
||||
}
|
||||
if accountId > 0 {
|
||||
query.Attr("accountId", accountId)
|
||||
}
|
||||
if len(keyword) > 0 {
|
||||
query.Where("(userId IN (SELECT id FROM " + models.SharedUserDAO.Table + " WHERE state=1 AND (username LIKE :keyword OR fullname LIKE :keyword)) OR description LIKE :keyword)")
|
||||
query.Param("keyword", dbutils.QuoteLike(keyword))
|
||||
}
|
||||
if len(eventType) > 0 {
|
||||
query.Attr("eventType", eventType)
|
||||
}
|
||||
_, err = query.
|
||||
DescPk().
|
||||
Offset(offset).
|
||||
Limit(size).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// SumDailyEventTypes 统计某天数据总和
|
||||
func (this *UserAccountLogDAO) SumDailyEventTypes(tx *dbs.Tx, day string, eventTypes []userconfigs.AccountEventType) (float32, error) {
|
||||
if len(eventTypes) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
result, err := this.Query(tx).
|
||||
Attr("day", day).
|
||||
Attr("eventType", eventTypes).
|
||||
Sum("delta", 0)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return types.Float32(result), nil
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
)
|
||||
@@ -0,0 +1,38 @@
|
||||
package accounts
|
||||
|
||||
import "github.com/iwind/TeaGo/dbs"
|
||||
|
||||
// UserAccountLog 用户账户日志
|
||||
type UserAccountLog struct {
|
||||
Id uint64 `field:"id"` // ID
|
||||
UserId uint64 `field:"userId"` // 用户ID
|
||||
AccountId uint64 `field:"accountId"` // 账户ID
|
||||
Delta float64 `field:"delta"` // 操作余额的数量(可为负)
|
||||
DeltaFrozen float64 `field:"deltaFrozen"` // 操作冻结的数量(可为负)
|
||||
Total float64 `field:"total"` // 操作后余额
|
||||
TotalFrozen float64 `field:"totalFrozen"` // 操作后冻结余额
|
||||
EventType string `field:"eventType"` // 类型
|
||||
Description string `field:"description"` // 描述文字
|
||||
Day string `field:"day"` // YYYYMMDD
|
||||
CreatedAt uint64 `field:"createdAt"` // 时间
|
||||
Params dbs.JSON `field:"params"` // 参数
|
||||
}
|
||||
|
||||
type UserAccountLogOperator struct {
|
||||
Id interface{} // ID
|
||||
UserId interface{} // 用户ID
|
||||
AccountId interface{} // 账户ID
|
||||
Delta interface{} // 操作余额的数量(可为负)
|
||||
DeltaFrozen interface{} // 操作冻结的数量(可为负)
|
||||
Total interface{} // 操作后余额
|
||||
TotalFrozen interface{} // 操作后冻结余额
|
||||
EventType interface{} // 类型
|
||||
Description interface{} // 描述文字
|
||||
Day interface{} // YYYYMMDD
|
||||
CreatedAt interface{} // 时间
|
||||
Params interface{} // 参数
|
||||
}
|
||||
|
||||
func NewUserAccountLogOperator() *UserAccountLogOperator {
|
||||
return &UserAccountLogOperator{}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package accounts
|
||||
20
EdgeAPI/internal/db/models/accounts/user_account_model.go
Normal file
20
EdgeAPI/internal/db/models/accounts/user_account_model.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package accounts
|
||||
|
||||
// UserAccount 用户账号
|
||||
type UserAccount struct {
|
||||
Id uint64 `field:"id"` // ID
|
||||
UserId uint64 `field:"userId"` // 用户ID
|
||||
Total float64 `field:"total"` // 可用总余额
|
||||
TotalFrozen float64 `field:"totalFrozen"` // 冻结余额
|
||||
}
|
||||
|
||||
type UserAccountOperator struct {
|
||||
Id interface{} // ID
|
||||
UserId interface{} // 用户ID
|
||||
Total interface{} // 可用总余额
|
||||
TotalFrozen interface{} // 冻结余额
|
||||
}
|
||||
|
||||
func NewUserAccountOperator() *UserAccountOperator {
|
||||
return &UserAccountOperator{}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package accounts
|
||||
33
EdgeAPI/internal/db/models/accounts/user_order_dao.go
Normal file
33
EdgeAPI/internal/db/models/accounts/user_order_dao.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
)
|
||||
|
||||
const (
|
||||
UserOrderStateEnabled = 1 // 已启用
|
||||
UserOrderStateDisabled = 0 // 已禁用
|
||||
)
|
||||
|
||||
type UserOrderDAO dbs.DAO
|
||||
|
||||
func NewUserOrderDAO() *UserOrderDAO {
|
||||
return dbs.NewDAO(&UserOrderDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeUserOrders",
|
||||
Model: new(UserOrder),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*UserOrderDAO)
|
||||
}
|
||||
|
||||
var SharedUserOrderDAO *UserOrderDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedUserOrderDAO = NewUserOrderDAO()
|
||||
})
|
||||
}
|
||||
292
EdgeAPI/internal/db/models/accounts/user_order_dao_plus.go
Normal file
292
EdgeAPI/internal/db/models/accounts/user_order_dao_plus.go
Normal file
@@ -0,0 +1,292 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models"
|
||||
"github.com/TeaOSLab/EdgeAPI/internal/db/models/nameservers"
|
||||
dbutils "github.com/TeaOSLab/EdgeAPI/internal/db/utils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/TeaGo/types"
|
||||
timeutil "github.com/iwind/TeaGo/utils/time"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CreateOrder 创建订单
|
||||
func (this *UserOrderDAO) CreateOrder(tx *dbs.Tx, adminId int64, userId int64, orderType userconfigs.OrderType, methodId int64, amount float64, paramsJSON []byte) (orderId int64, code string, err error) {
|
||||
// 查询过期时间
|
||||
configJSON, err := models.SharedSysSettingDAO.ReadSetting(tx, systemconfigs.SettingCodeUserOrderConfig)
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
var config = userconfigs.DefaultUserOrderConfig()
|
||||
if len(configJSON) == 0 {
|
||||
err = json.Unmarshal(configJSON, config)
|
||||
if err != nil {
|
||||
return 0, "", fmt.Errorf("decode order config failed: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 保存订单
|
||||
var op = NewUserOrderOperator()
|
||||
op.UserId = userId
|
||||
op.Type = orderType
|
||||
op.MethodId = methodId
|
||||
op.Amount = amount
|
||||
if len(paramsJSON) > 0 {
|
||||
op.Params = paramsJSON
|
||||
}
|
||||
op.Status = userconfigs.OrderStatusNone
|
||||
|
||||
if config.OrderLife != nil && config.OrderLife.Count > 0 {
|
||||
op.ExpiredAt = time.Now().Unix() + int64(config.OrderLife.Duration().Seconds())
|
||||
} else {
|
||||
op.ExpiredAt = time.Now().Unix() + 3600 /** 默认一个小时 **/
|
||||
}
|
||||
|
||||
op.State = UserOrderStateEnabled
|
||||
orderId, err = this.SaveInt64(tx, op)
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
|
||||
var orderCode = timeutil.Format("Ymd") + fmt.Sprintf("%08d", orderId) // 16 bytes
|
||||
err = this.Query(tx).
|
||||
Pk(orderId).
|
||||
Set("code", orderCode).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
|
||||
// 生成订单日志
|
||||
err = SharedUserOrderLogDAO.CreateOrderLog(tx, adminId, userId, orderId, userconfigs.OrderStatusNone)
|
||||
if err != nil {
|
||||
return 0, "", err
|
||||
}
|
||||
|
||||
return orderId, orderCode, nil
|
||||
}
|
||||
|
||||
// FindEnabledOrder 查找某个订单
|
||||
func (this *UserOrderDAO) FindEnabledOrder(tx *dbs.Tx, orderId int64) (*UserOrder, error) {
|
||||
one, err := this.Query(tx).
|
||||
Pk(orderId).
|
||||
Find()
|
||||
if err != nil || one == nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return one.(*UserOrder), nil
|
||||
}
|
||||
|
||||
// CancelOrder 取消订单
|
||||
func (this *UserOrderDAO) CancelOrder(tx *dbs.Tx, adminId int64, userId int64, orderId int64) error {
|
||||
status, err := this.Query(tx).
|
||||
Pk(orderId).
|
||||
Result("status").
|
||||
FindStringCol("")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if status != userconfigs.OrderStatusNone {
|
||||
return errors.New("can not cancel the order with status '" + status + "'")
|
||||
}
|
||||
|
||||
err = this.Query(tx).
|
||||
Pk(orderId).
|
||||
Set("status", userconfigs.OrderStatusCancelled).
|
||||
Set("cancelledAt", time.Now().Unix()).
|
||||
UpdateQuickly()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return SharedUserOrderLogDAO.CreateOrderLog(tx, adminId, userId, orderId, userconfigs.OrderStatusCancelled)
|
||||
}
|
||||
|
||||
// FinishOrder 完成订单
|
||||
// 不需要检查过期时间,因为用户可能在支付页面停留非常久后才完成支付
|
||||
func (this *UserOrderDAO) FinishOrder(tx *dbs.Tx, adminId int64, userId int64, orderId int64) error {
|
||||
// 检查订单状态
|
||||
order, err := SharedUserOrderDAO.FindEnabledOrder(tx, orderId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if order == nil {
|
||||
return errors.New("can not find order")
|
||||
}
|
||||
|
||||
if order.Status != userconfigs.OrderStatusNone {
|
||||
return errors.New("you can not finish the order, cause order status is '" + order.Status + "'")
|
||||
}
|
||||
|
||||
// 用户账户
|
||||
account, err := SharedUserAccountDAO.FindUserAccountWithUserId(tx, int64(order.UserId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if account == nil {
|
||||
return errors.New("user account not found")
|
||||
}
|
||||
|
||||
switch order.Type {
|
||||
case userconfigs.OrderTypeCharge: // 充值
|
||||
err = SharedUserAccountDAO.UpdateUserAccount(tx, int64(account.Id), order.Amount, userconfigs.AccountEventTypeCharge, "充值,订单号:"+order.Code, maps.Map{
|
||||
"orderCode": order.Code,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case userconfigs.OrderTypeBuyNSPlan: // 购买DNS套餐
|
||||
var params = &userconfigs.OrderTypeBuyNSPlanParams{}
|
||||
err = json.Unmarshal(order.Params, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = nameservers.SharedNSUserPlanDAO.RenewUserPlan(tx, int64(order.UserId), params.PlanId, params.DayFrom, params.DayTo, params.Period)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case userconfigs.OrderTypeBuyTrafficPackage: // 购买流量包
|
||||
var params = &userconfigs.OrderTypeBuyTrafficPackageParams{}
|
||||
err = json.Unmarshal(order.Params, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if params.Count > 0 {
|
||||
for i := 0; i < int(params.Count); i++ {
|
||||
_, err = models.SharedUserTrafficPackageDAO.CreateUserPackage(tx, int64(order.UserId), 0, params.PackageId, params.RegionId, params.PeriodId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
case userconfigs.OrderTypeBuyAntiDDoSInstance: // 购买高防实例
|
||||
var params = &userconfigs.OrderTypeBuyAntiDDoSInstanceParams{}
|
||||
err = json.Unmarshal(order.Params, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = models.SharedUserADInstanceDAO.CreateUserADInstances(tx, int64(order.UserId), params.PackageId, params.PeriodId, params.Count)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case userconfigs.OrderTypeRenewAntiDDoSInstance: // 续费高防实例
|
||||
var params = &userconfigs.OrderTypeRenewAntiDDoSInstanceParams{}
|
||||
err = json.Unmarshal(order.Params, params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
userInstance, err := models.SharedUserADInstanceDAO.FindEnabledUserADInstance(tx, params.UserInstanceId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if userInstance == nil {
|
||||
return errors.New("could not find user instance '" + types.String(params.UserInstanceId) + "'")
|
||||
}
|
||||
|
||||
period, err := models.SharedADPackagePeriodDAO.FindEnabledADPackagePeriod(tx, params.PeriodId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if period == nil {
|
||||
return errors.New("could not find period '" + types.String(params.PeriodId) + "'")
|
||||
}
|
||||
|
||||
_, err = models.SharedUserADInstanceDAO.RenewUserInstance(tx, userInstance, period)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = this.Query(tx).
|
||||
Pk(orderId).
|
||||
Set("status", userconfigs.OrderStatusFinished).
|
||||
Set("finishedAt", time.Now().Unix()).
|
||||
UpdateQuickly()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return SharedUserOrderLogDAO.CreateOrderLog(tx, adminId, userId, orderId, userconfigs.OrderStatusFinished)
|
||||
}
|
||||
|
||||
// CountEnabledUserOrders 计算订单数量
|
||||
func (this *UserOrderDAO) CountEnabledUserOrders(tx *dbs.Tx, userId int64, status userconfigs.OrderStatus, keyword string) (int64, error) {
|
||||
var query = this.Query(tx).
|
||||
State(UserOrderStateEnabled)
|
||||
if userId > 0 {
|
||||
query.Attr("userId", userId)
|
||||
}
|
||||
if len(status) > 0 {
|
||||
query.Attr("status", status)
|
||||
}
|
||||
if len(keyword) > 0 {
|
||||
query.Where("(code LIKE :keyword)")
|
||||
query.Param("keyword", dbutils.QuoteLike(keyword))
|
||||
}
|
||||
return query.Count()
|
||||
}
|
||||
|
||||
// ListEnabledUserOrders 列出单页订单
|
||||
func (this *UserOrderDAO) ListEnabledUserOrders(tx *dbs.Tx, userId int64, status userconfigs.OrderStatus, keyword string, offset int64, size int64) (result []*UserOrder, err error) {
|
||||
var query = this.Query(tx).
|
||||
State(UserOrderStateEnabled)
|
||||
if userId > 0 {
|
||||
query.Attr("userId", userId)
|
||||
}
|
||||
if len(status) > 0 {
|
||||
query.Attr("status", status)
|
||||
}
|
||||
if len(keyword) > 0 {
|
||||
query.Where("(code LIKE :keyword)")
|
||||
query.Param("keyword", dbutils.QuoteLike(keyword))
|
||||
}
|
||||
_, err = query.
|
||||
DescPk().
|
||||
Offset(offset).
|
||||
Limit(size).
|
||||
Slice(&result).
|
||||
FindAll()
|
||||
return
|
||||
}
|
||||
|
||||
// FindUserOrderIdWithCode 根据订单号查找订单ID
|
||||
func (this *UserOrderDAO) FindUserOrderIdWithCode(tx *dbs.Tx, code string) (int64, error) {
|
||||
if len(code) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
return this.Query(tx).
|
||||
ResultPk().
|
||||
State(UserOrderStateEnabled).
|
||||
Attr("code", code).
|
||||
FindInt64Col(0)
|
||||
}
|
||||
|
||||
// FindUserOrderWithCode 根据订单号查找订单
|
||||
func (this *UserOrderDAO) FindUserOrderWithCode(tx *dbs.Tx, code string) (*UserOrder, error) {
|
||||
if len(code) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
one, err := this.Query(tx).
|
||||
State(UserOrderStateEnabled).
|
||||
Attr("code", code).
|
||||
Find()
|
||||
if err != nil || one == nil {
|
||||
return nil, err
|
||||
}
|
||||
return one.(*UserOrder), nil
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package accounts_test
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
)
|
||||
28
EdgeAPI/internal/db/models/accounts/user_order_log_dao.go
Normal file
28
EdgeAPI/internal/db/models/accounts/user_order_log_dao.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
)
|
||||
|
||||
type UserOrderLogDAO dbs.DAO
|
||||
|
||||
func NewUserOrderLogDAO() *UserOrderLogDAO {
|
||||
return dbs.NewDAO(&UserOrderLogDAO{
|
||||
DAOObject: dbs.DAOObject{
|
||||
DB: Tea.Env,
|
||||
Table: "edgeUserOrderLogs",
|
||||
Model: new(UserOrderLog),
|
||||
PkName: "id",
|
||||
},
|
||||
}).(*UserOrderLogDAO)
|
||||
}
|
||||
|
||||
var SharedUserOrderLogDAO *UserOrderLogDAO
|
||||
|
||||
func init() {
|
||||
dbs.OnReady(func() {
|
||||
SharedUserOrderLogDAO = NewUserOrderLogDAO()
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
//go:build plus
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CreateOrderLog 创建订单日志
|
||||
func (this *UserOrderLogDAO) CreateOrderLog(tx *dbs.Tx, adminId int64, userId int64, orderId int64, status userconfigs.OrderStatus) error {
|
||||
var op = NewUserOrderLogOperator()
|
||||
op.AdminId = adminId
|
||||
op.UserId = userId
|
||||
op.OrderId = orderId
|
||||
op.Status = status
|
||||
op.CreatedAt = time.Now().Unix()
|
||||
return this.Save(tx, op)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package accounts_test
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/iwind/TeaGo/bootstrap"
|
||||
)
|
||||
28
EdgeAPI/internal/db/models/accounts/user_order_log_model.go
Normal file
28
EdgeAPI/internal/db/models/accounts/user_order_log_model.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package accounts
|
||||
|
||||
import "github.com/iwind/TeaGo/dbs"
|
||||
|
||||
// UserOrderLog 订单日志
|
||||
type UserOrderLog struct {
|
||||
Id uint64 `field:"id"` // ID
|
||||
AdminId uint64 `field:"adminId"` // 管理员ID
|
||||
UserId uint64 `field:"userId"` // 用户ID
|
||||
OrderId uint64 `field:"orderId"` // 订单ID
|
||||
Status string `field:"status"` // 状态
|
||||
Snapshot dbs.JSON `field:"snapshot"` // 状态快照
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
}
|
||||
|
||||
type UserOrderLogOperator struct {
|
||||
Id interface{} // ID
|
||||
AdminId interface{} // 管理员ID
|
||||
UserId interface{} // 用户ID
|
||||
OrderId interface{} // 订单ID
|
||||
Status interface{} // 状态
|
||||
Snapshot interface{} // 状态快照
|
||||
CreatedAt interface{} // 创建时间
|
||||
}
|
||||
|
||||
func NewUserOrderLogOperator() *UserOrderLogOperator {
|
||||
return &UserOrderLogOperator{}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package accounts
|
||||
40
EdgeAPI/internal/db/models/accounts/user_order_model.go
Normal file
40
EdgeAPI/internal/db/models/accounts/user_order_model.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package accounts
|
||||
|
||||
import "github.com/iwind/TeaGo/dbs"
|
||||
|
||||
// UserOrder 用户订单
|
||||
type UserOrder struct {
|
||||
Id uint64 `field:"id"` // 用户订单
|
||||
UserId uint64 `field:"userId"` // 用户ID
|
||||
Code string `field:"code"` // 订单号
|
||||
Type string `field:"type"` // 订单类型
|
||||
MethodId uint32 `field:"methodId"` // 支付方式
|
||||
Status string `field:"status"` // 订单状态
|
||||
Amount float64 `field:"amount"` // 金额
|
||||
Params dbs.JSON `field:"params"` // 附加参数
|
||||
ExpiredAt uint64 `field:"expiredAt"` // 过期时间
|
||||
CreatedAt uint64 `field:"createdAt"` // 创建时间
|
||||
CancelledAt uint64 `field:"cancelledAt"` // 取消时间
|
||||
FinishedAt uint64 `field:"finishedAt"` // 结束时间
|
||||
State uint8 `field:"state"` // 状态
|
||||
}
|
||||
|
||||
type UserOrderOperator struct {
|
||||
Id interface{} // 用户订单
|
||||
UserId interface{} // 用户ID
|
||||
Code interface{} // 订单号
|
||||
Type interface{} // 订单类型
|
||||
MethodId interface{} // 支付方式
|
||||
Status interface{} // 订单状态
|
||||
Amount interface{} // 金额
|
||||
Params interface{} // 附加参数
|
||||
ExpiredAt interface{} // 过期时间
|
||||
CreatedAt interface{} // 创建时间
|
||||
CancelledAt interface{} // 取消时间
|
||||
FinishedAt interface{} // 结束时间
|
||||
State interface{} // 状态
|
||||
}
|
||||
|
||||
func NewUserOrderOperator() *UserOrderOperator {
|
||||
return &UserOrderOperator{}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package accounts
|
||||
@@ -0,0 +1,14 @@
|
||||
//go:build plus
|
||||
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
|
||||
"time"
|
||||
)
|
||||
|
||||
// IsExpired 检查当前订单是否已经过期
|
||||
func (this *UserOrder) IsExpired() bool {
|
||||
return this.Status == userconfigs.OrderStatusNone &&
|
||||
time.Now().Unix() > int64(this.ExpiredAt)
|
||||
}
|
||||
Reference in New Issue
Block a user