mirror of
				https://github.com/TeaOSLab/EdgeAPI.git
				synced 2025-11-04 16:00:24 +08:00 
			
		
		
		
	实现带宽计费套餐
This commit is contained in:
		@@ -1,6 +1,6 @@
 | 
				
			|||||||
package models
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 区域计费设置
 | 
					// NodePriceItem 区域计费设置
 | 
				
			||||||
type NodePriceItem struct {
 | 
					type NodePriceItem struct {
 | 
				
			||||||
	Id        uint32 `field:"id"`        // ID
 | 
						Id        uint32 `field:"id"`        // ID
 | 
				
			||||||
	IsOn      uint8  `field:"isOn"`      // 是否启用
 | 
						IsOn      uint8  `field:"isOn"`      // 是否启用
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
package models
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 节点区域
 | 
					// NodeRegion 节点区域
 | 
				
			||||||
type NodeRegion struct {
 | 
					type NodeRegion struct {
 | 
				
			||||||
	Id          uint32 `field:"id"`          // ID
 | 
						Id          uint32 `field:"id"`          // ID
 | 
				
			||||||
	AdminId     uint32 `field:"adminId"`     // 管理员ID
 | 
						AdminId     uint32 `field:"adminId"`     // 管理员ID
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +1,18 @@
 | 
				
			|||||||
package models
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import "encoding/json"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (this *NodeRegion) DecodePriceMap() map[int64]float64 {
 | 
				
			||||||
 | 
						var m = map[int64]float64{}
 | 
				
			||||||
 | 
						if len(this.Prices) == 0 {
 | 
				
			||||||
 | 
							return m
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := json.Unmarshal([]byte(this.Prices), &m)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							// 忽略错误
 | 
				
			||||||
 | 
							return m
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return m
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,7 +11,7 @@ func TestNodeTaskDAO_CreateNodeTask(t *testing.T) {
 | 
				
			|||||||
	dbs.NotifyReady()
 | 
						dbs.NotifyReady()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var tx *dbs.Tx
 | 
						var tx *dbs.Tx
 | 
				
			||||||
	err := SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, 1, 2, NodeTaskTypeConfigChanged, 0)
 | 
						err := SharedNodeTaskDAO.CreateNodeTask(tx, nodeconfigs.NodeRoleNode, 1, 2, 0, NodeTaskTypeConfigChanged, 0)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -22,7 +22,7 @@ func TestNodeTaskDAO_CreateClusterTask(t *testing.T) {
 | 
				
			|||||||
	dbs.NotifyReady()
 | 
						dbs.NotifyReady()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var tx *dbs.Tx
 | 
						var tx *dbs.Tx
 | 
				
			||||||
	err := SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, 1, NodeTaskTypeConfigChanged)
 | 
						err := SharedNodeTaskDAO.CreateClusterTask(tx, nodeconfigs.NodeRoleNode, 1, 0, NodeTaskTypeConfigChanged)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -33,7 +33,7 @@ func TestNodeTaskDAO_ExtractClusterTask(t *testing.T) {
 | 
				
			|||||||
	dbs.NotifyReady()
 | 
						dbs.NotifyReady()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var tx *dbs.Tx
 | 
						var tx *dbs.Tx
 | 
				
			||||||
	err := SharedNodeTaskDAO.ExtractNodeClusterTask(tx, 1, NodeTaskTypeConfigChanged)
 | 
						err := SharedNodeTaskDAO.ExtractNodeClusterTask(tx, 1, 0, NodeTaskTypeConfigChanged)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,7 +80,17 @@ func (this *PlanDAO) FindPlanName(tx *dbs.Tx, id int64) (string, error) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CreatePlan 创建套餐
 | 
					// CreatePlan 创建套餐
 | 
				
			||||||
func (this *PlanDAO) CreatePlan(tx *dbs.Tx, name string, clusterId int64, trafficLimitJSON []byte, featuresJSON []byte, priceType serverconfigs.PlanPriceType, trafficPriceJSON []byte, monthlyPrice float32, seasonallyPrice float32, yearlyPrice float32) (int64, error) {
 | 
					func (this *PlanDAO) CreatePlan(tx *dbs.Tx,
 | 
				
			||||||
 | 
						name string,
 | 
				
			||||||
 | 
						clusterId int64,
 | 
				
			||||||
 | 
						trafficLimitJSON []byte,
 | 
				
			||||||
 | 
						featuresJSON []byte,
 | 
				
			||||||
 | 
						priceType serverconfigs.PlanPriceType,
 | 
				
			||||||
 | 
						trafficPriceJSON []byte,
 | 
				
			||||||
 | 
						bandwidthPriceJSON []byte,
 | 
				
			||||||
 | 
						monthlyPrice float32,
 | 
				
			||||||
 | 
						seasonallyPrice float32,
 | 
				
			||||||
 | 
						yearlyPrice float32) (int64, error) {
 | 
				
			||||||
	var op = NewPlanOperator()
 | 
						var op = NewPlanOperator()
 | 
				
			||||||
	op.Name = name
 | 
						op.Name = name
 | 
				
			||||||
	op.ClusterId = clusterId
 | 
						op.ClusterId = clusterId
 | 
				
			||||||
@@ -94,6 +104,9 @@ func (this *PlanDAO) CreatePlan(tx *dbs.Tx, name string, clusterId int64, traffi
 | 
				
			|||||||
	if len(trafficPriceJSON) > 0 {
 | 
						if len(trafficPriceJSON) > 0 {
 | 
				
			||||||
		op.TrafficPrice = trafficPriceJSON
 | 
							op.TrafficPrice = trafficPriceJSON
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if len(bandwidthPriceJSON) > 0 {
 | 
				
			||||||
 | 
							op.BandwidthPrice = bandwidthPriceJSON
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if monthlyPrice >= 0 {
 | 
						if monthlyPrice >= 0 {
 | 
				
			||||||
		op.MonthlyPrice = monthlyPrice
 | 
							op.MonthlyPrice = monthlyPrice
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -109,7 +122,19 @@ func (this *PlanDAO) CreatePlan(tx *dbs.Tx, name string, clusterId int64, traffi
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UpdatePlan 修改套餐
 | 
					// UpdatePlan 修改套餐
 | 
				
			||||||
func (this *PlanDAO) UpdatePlan(tx *dbs.Tx, planId int64, name string, isOn bool, clusterId int64, trafficLimitJSON []byte, featuresJSON []byte, priceType serverconfigs.PlanPriceType, trafficPriceJSON []byte, monthlyPrice float32, seasonallyPrice float32, yearlyPrice float32) error {
 | 
					func (this *PlanDAO) UpdatePlan(tx *dbs.Tx,
 | 
				
			||||||
 | 
						planId int64,
 | 
				
			||||||
 | 
						name string,
 | 
				
			||||||
 | 
						isOn bool,
 | 
				
			||||||
 | 
						clusterId int64,
 | 
				
			||||||
 | 
						trafficLimitJSON []byte,
 | 
				
			||||||
 | 
						featuresJSON []byte,
 | 
				
			||||||
 | 
						priceType serverconfigs.PlanPriceType,
 | 
				
			||||||
 | 
						trafficPriceJSON []byte,
 | 
				
			||||||
 | 
						bandwidthPriceJSON []byte,
 | 
				
			||||||
 | 
						monthlyPrice float32,
 | 
				
			||||||
 | 
						seasonallyPrice float32,
 | 
				
			||||||
 | 
						yearlyPrice float32) error {
 | 
				
			||||||
	if planId <= 0 {
 | 
						if planId <= 0 {
 | 
				
			||||||
		return errors.New("invalid planId")
 | 
							return errors.New("invalid planId")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -138,6 +163,9 @@ func (this *PlanDAO) UpdatePlan(tx *dbs.Tx, planId int64, name string, isOn bool
 | 
				
			|||||||
	if len(trafficPriceJSON) > 0 {
 | 
						if len(trafficPriceJSON) > 0 {
 | 
				
			||||||
		op.TrafficPrice = trafficPriceJSON
 | 
							op.TrafficPrice = trafficPriceJSON
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if len(bandwidthPriceJSON) > 0 {
 | 
				
			||||||
 | 
							op.BandwidthPrice = bandwidthPriceJSON
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if monthlyPrice >= 0 {
 | 
						if monthlyPrice >= 0 {
 | 
				
			||||||
		op.MonthlyPrice = monthlyPrice
 | 
							op.MonthlyPrice = monthlyPrice
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ type Plan struct {
 | 
				
			|||||||
	TrafficLimit    string  `field:"trafficLimit"`    // 流量限制
 | 
						TrafficLimit    string  `field:"trafficLimit"`    // 流量限制
 | 
				
			||||||
	Features        string  `field:"features"`        // 允许的功能
 | 
						Features        string  `field:"features"`        // 允许的功能
 | 
				
			||||||
	TrafficPrice    string  `field:"trafficPrice"`    // 流量价格设定
 | 
						TrafficPrice    string  `field:"trafficPrice"`    // 流量价格设定
 | 
				
			||||||
 | 
						BandwidthPrice  string  `field:"bandwidthPrice"`  // 带宽价格
 | 
				
			||||||
	MonthlyPrice    float64 `field:"monthlyPrice"`    // 月付
 | 
						MonthlyPrice    float64 `field:"monthlyPrice"`    // 月付
 | 
				
			||||||
	SeasonallyPrice float64 `field:"seasonallyPrice"` // 季付
 | 
						SeasonallyPrice float64 `field:"seasonallyPrice"` // 季付
 | 
				
			||||||
	YearlyPrice     float64 `field:"yearlyPrice"`     // 年付
 | 
						YearlyPrice     float64 `field:"yearlyPrice"`     // 年付
 | 
				
			||||||
@@ -25,6 +26,7 @@ type PlanOperator struct {
 | 
				
			|||||||
	TrafficLimit    interface{} // 流量限制
 | 
						TrafficLimit    interface{} // 流量限制
 | 
				
			||||||
	Features        interface{} // 允许的功能
 | 
						Features        interface{} // 允许的功能
 | 
				
			||||||
	TrafficPrice    interface{} // 流量价格设定
 | 
						TrafficPrice    interface{} // 流量价格设定
 | 
				
			||||||
 | 
						BandwidthPrice  interface{} // 带宽价格
 | 
				
			||||||
	MonthlyPrice    interface{} // 月付
 | 
						MonthlyPrice    interface{} // 月付
 | 
				
			||||||
	SeasonallyPrice interface{} // 季付
 | 
						SeasonallyPrice interface{} // 季付
 | 
				
			||||||
	YearlyPrice     interface{} // 年付
 | 
						YearlyPrice     interface{} // 年付
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1 +1,38 @@
 | 
				
			|||||||
package models
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"encoding/json"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DecodeTrafficPrice 流量价格配置
 | 
				
			||||||
 | 
					func (this *Plan) DecodeTrafficPrice() *serverconfigs.PlanTrafficPriceConfig {
 | 
				
			||||||
 | 
						var config = &serverconfigs.PlanTrafficPriceConfig{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(this.TrafficPrice) == 0 {
 | 
				
			||||||
 | 
							return config
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := json.Unmarshal([]byte(this.TrafficPrice), config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							// 忽略错误
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return config
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DecodeBandwidthPrice 带宽价格配置
 | 
				
			||||||
 | 
					func (this *Plan) DecodeBandwidthPrice() *serverconfigs.PlanBandwidthPriceConfig {
 | 
				
			||||||
 | 
						var config = &serverconfigs.PlanBandwidthPriceConfig{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if len(this.BandwidthPrice) == 0 {
 | 
				
			||||||
 | 
							return config
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err := json.Unmarshal([]byte(this.BandwidthPrice), config)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							// 忽略错误
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return config
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										96
									
								
								internal/db/models/server_bill_dao.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								internal/db/models/server_bill_dao.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/Tea"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ServerBillDAO dbs.DAO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewServerBillDAO() *ServerBillDAO {
 | 
				
			||||||
 | 
						return dbs.NewDAO(&ServerBillDAO{
 | 
				
			||||||
 | 
							DAOObject: dbs.DAOObject{
 | 
				
			||||||
 | 
								DB:     Tea.Env,
 | 
				
			||||||
 | 
								Table:  "edgeServerBills",
 | 
				
			||||||
 | 
								Model:  new(ServerBill),
 | 
				
			||||||
 | 
								PkName: "id",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}).(*ServerBillDAO)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var SharedServerBillDAO *ServerBillDAO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						dbs.OnReady(func() {
 | 
				
			||||||
 | 
							SharedServerBillDAO = NewServerBillDAO()
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CreateOrUpdateServerBill 创建账单
 | 
				
			||||||
 | 
					func (this *ServerBillDAO) CreateOrUpdateServerBill(tx *dbs.Tx, userId int64, serverId int64, month string, userPlanId int64, planId int64, totalTrafficBytes int64, bandwidthPercentileBytes int64, bandwidthPercentile int, fee float64) error {
 | 
				
			||||||
 | 
						fee = math.Floor(fee*100) / 100
 | 
				
			||||||
 | 
						return this.Query(tx).
 | 
				
			||||||
 | 
							InsertOrUpdateQuickly(maps.Map{
 | 
				
			||||||
 | 
								"userId":                   userId,
 | 
				
			||||||
 | 
								"serverId":                 serverId,
 | 
				
			||||||
 | 
								"month":                    month,
 | 
				
			||||||
 | 
								"amount":                   fee,
 | 
				
			||||||
 | 
								"userPlanId":               userPlanId,
 | 
				
			||||||
 | 
								"planId":                   planId,
 | 
				
			||||||
 | 
								"totalTrafficBytes":        totalTrafficBytes,
 | 
				
			||||||
 | 
								"bandwidthPercentileBytes": bandwidthPercentileBytes,
 | 
				
			||||||
 | 
								"bandwidthPercentile":      bandwidthPercentile,
 | 
				
			||||||
 | 
								"createdAt":                time.Now().Unix(),
 | 
				
			||||||
 | 
							}, maps.Map{
 | 
				
			||||||
 | 
								"userId":                   userId,
 | 
				
			||||||
 | 
								"amount":                   fee,
 | 
				
			||||||
 | 
								"userPlanId":               userPlanId,
 | 
				
			||||||
 | 
								"planId":                   planId,
 | 
				
			||||||
 | 
								"totalTrafficBytes":        totalTrafficBytes,
 | 
				
			||||||
 | 
								"bandwidthPercentileBytes": bandwidthPercentileBytes,
 | 
				
			||||||
 | 
								"bandwidthPercentile":      bandwidthPercentile,
 | 
				
			||||||
 | 
								"createdAt":                time.Now().Unix(),
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SumUserMonthlyAmount 计算总费用
 | 
				
			||||||
 | 
					func (this *ServerBillDAO) SumUserMonthlyAmount(tx *dbs.Tx, userId int64, month string) (float64, error) {
 | 
				
			||||||
 | 
						return this.Query(tx).
 | 
				
			||||||
 | 
							Attr("userId", userId).
 | 
				
			||||||
 | 
							Attr("month", month).
 | 
				
			||||||
 | 
							Sum("amount", 0)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CountServerBills 计算总账单数量
 | 
				
			||||||
 | 
					func (this *ServerBillDAO) CountServerBills(tx *dbs.Tx, userId int64, month string) (int64, error) {
 | 
				
			||||||
 | 
						var query = this.Query(tx)
 | 
				
			||||||
 | 
						if userId > 0 {
 | 
				
			||||||
 | 
							query.Attr("userId", userId)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(month) > 0 {
 | 
				
			||||||
 | 
							query.Attr("month", month)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return query.Count()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ListServerBills 列出单页账单
 | 
				
			||||||
 | 
					func (this *ServerBillDAO) ListServerBills(tx *dbs.Tx, userId int64, month string, offset int64, size int64) (result []*ServerBill, err error) {
 | 
				
			||||||
 | 
						var query = this.Query(tx)
 | 
				
			||||||
 | 
						if userId > 0 {
 | 
				
			||||||
 | 
							query.Attr("userId", userId)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(month) > 0 {
 | 
				
			||||||
 | 
							query.Attr("month", month)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						_, err = query.
 | 
				
			||||||
 | 
							Desc("serverId").
 | 
				
			||||||
 | 
							Offset(offset).
 | 
				
			||||||
 | 
							Limit(size).
 | 
				
			||||||
 | 
							Slice(&result).
 | 
				
			||||||
 | 
							FindAll()
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										20
									
								
								internal/db/models/server_bill_dao_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								internal/db/models/server_bill_dao_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
 | 
						_ "github.com/iwind/TeaGo/bootstrap"
 | 
				
			||||||
 | 
						"github.com/iwind/TeaGo/dbs"
 | 
				
			||||||
 | 
						timeutil "github.com/iwind/TeaGo/utils/time"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestServerBillDAO_CreateOrUpdateServerBill(t *testing.T) {
 | 
				
			||||||
 | 
						var dao = NewServerBillDAO()
 | 
				
			||||||
 | 
						var tx *dbs.Tx
 | 
				
			||||||
 | 
						var month = timeutil.Format("Y02")
 | 
				
			||||||
 | 
						err := dao.CreateOrUpdateServerBill(tx, 1, 2, month, 4, 5, 6, 7, 95, 100)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						t.Log("ok")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										34
									
								
								internal/db/models/server_bill_model.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								internal/db/models/server_bill_model.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
				
			|||||||
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ServerBill 服务账单
 | 
				
			||||||
 | 
					type ServerBill struct {
 | 
				
			||||||
 | 
						Id                       uint64  `field:"id"`                       // ID
 | 
				
			||||||
 | 
						UserId                   uint32  `field:"userId"`                   // 用户ID
 | 
				
			||||||
 | 
						ServerId                 uint32  `field:"serverId"`                 // 服务ID
 | 
				
			||||||
 | 
						Amount                   float64 `field:"amount"`                   // 金额
 | 
				
			||||||
 | 
						Month                    string  `field:"month"`                    // 月份
 | 
				
			||||||
 | 
						CreatedAt                uint64  `field:"createdAt"`                // 创建时间
 | 
				
			||||||
 | 
						UserPlanId               uint32  `field:"userPlanId"`               // 用户套餐ID
 | 
				
			||||||
 | 
						PlanId                   uint32  `field:"planId"`                   // 套餐ID
 | 
				
			||||||
 | 
						TotalTrafficBytes        uint64  `field:"totalTrafficBytes"`        // 总流量
 | 
				
			||||||
 | 
						BandwidthPercentileBytes uint64  `field:"bandwidthPercentileBytes"` // 带宽百分位字节
 | 
				
			||||||
 | 
						BandwidthPercentile      uint8   `field:"bandwidthPercentile"`      // 带宽百分位
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type ServerBillOperator struct {
 | 
				
			||||||
 | 
						Id                       interface{} // ID
 | 
				
			||||||
 | 
						UserId                   interface{} // 用户ID
 | 
				
			||||||
 | 
						ServerId                 interface{} // 服务ID
 | 
				
			||||||
 | 
						Amount                   interface{} // 金额
 | 
				
			||||||
 | 
						Month                    interface{} // 月份
 | 
				
			||||||
 | 
						CreatedAt                interface{} // 创建时间
 | 
				
			||||||
 | 
						UserPlanId               interface{} // 用户套餐ID
 | 
				
			||||||
 | 
						PlanId                   interface{} // 套餐ID
 | 
				
			||||||
 | 
						TotalTrafficBytes        interface{} // 总流量
 | 
				
			||||||
 | 
						BandwidthPercentileBytes interface{} // 带宽百分位字节
 | 
				
			||||||
 | 
						BandwidthPercentile      interface{} // 带宽百分位
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func NewServerBillOperator() *ServerBillOperator {
 | 
				
			||||||
 | 
						return &ServerBillOperator{}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								internal/db/models/server_bill_model_ext.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								internal/db/models/server_bill_model_ext.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					package models
 | 
				
			||||||
@@ -12,7 +12,9 @@ import (
 | 
				
			|||||||
	"github.com/iwind/TeaGo/maps"
 | 
						"github.com/iwind/TeaGo/maps"
 | 
				
			||||||
	"github.com/iwind/TeaGo/rands"
 | 
						"github.com/iwind/TeaGo/rands"
 | 
				
			||||||
	timeutil "github.com/iwind/TeaGo/utils/time"
 | 
						timeutil "github.com/iwind/TeaGo/utils/time"
 | 
				
			||||||
 | 
						"math"
 | 
				
			||||||
	"regexp"
 | 
						"regexp"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,7 +26,7 @@ func init() {
 | 
				
			|||||||
		var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
 | 
							var ticker = time.NewTicker(time.Duration(rands.Int(24, 48)) * time.Hour)
 | 
				
			||||||
		goman.New(func() {
 | 
							goman.New(func() {
 | 
				
			||||||
			for range ticker.C {
 | 
								for range ticker.C {
 | 
				
			||||||
				err := SharedServerDailyStatDAO.Clean(nil, 30) // 只保留N天
 | 
									err := SharedServerDailyStatDAO.Clean(nil, 60) // 只保留 N 天,时间需要长一些,因为需要用来生成账单
 | 
				
			||||||
				if err != nil {
 | 
									if err != nil {
 | 
				
			||||||
					logs.Println("ServerDailyStatDAO", "clean expired data failed: "+err.Error())
 | 
										logs.Println("ServerDailyStatDAO", "clean expired data failed: "+err.Error())
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
@@ -130,15 +132,15 @@ func (this *ServerDailyStatDAO) SaveStats(tx *dbs.Tx, stats []*pb.ServerDailySta
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SumUserMonthly 根据用户计算某月合计
 | 
					// SumServerMonthlyWithRegion 根据服务计算某月合计
 | 
				
			||||||
// month 格式为YYYYMM
 | 
					// month 格式为YYYYMM
 | 
				
			||||||
func (this *ServerDailyStatDAO) SumUserMonthly(tx *dbs.Tx, userId int64, regionId int64, month string) (int64, error) {
 | 
					func (this *ServerDailyStatDAO) SumServerMonthlyWithRegion(tx *dbs.Tx, serverId int64, regionId int64, month string) (int64, error) {
 | 
				
			||||||
	query := this.Query(tx)
 | 
						query := this.Query(tx)
 | 
				
			||||||
	if regionId > 0 {
 | 
						if regionId > 0 {
 | 
				
			||||||
		query.Attr("regionId", regionId)
 | 
							query.Attr("regionId", regionId)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return query.Between("day", month+"01", month+"32").
 | 
						return query.Between("day", month+"01", month+"32").
 | 
				
			||||||
		Attr("userId", userId).
 | 
							Attr("serverId", serverId).
 | 
				
			||||||
		SumInt64("bytes", 0)
 | 
							SumInt64("bytes", 0)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -156,16 +158,6 @@ func (this *ServerDailyStatDAO) SumUserMonthlyWithoutPlan(tx *dbs.Tx, userId int
 | 
				
			|||||||
		SumInt64("bytes", 0)
 | 
							SumInt64("bytes", 0)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SumUserMonthlyFee 计算用户某个月费用
 | 
					 | 
				
			||||||
// month 格式为YYYYMM
 | 
					 | 
				
			||||||
func (this *ServerDailyStatDAO) SumUserMonthlyFee(tx *dbs.Tx, userId int64, month string) (float64, error) {
 | 
					 | 
				
			||||||
	return this.Query(tx).
 | 
					 | 
				
			||||||
		Attr("userId", userId).
 | 
					 | 
				
			||||||
		Between("day", month+"01", month+"32").
 | 
					 | 
				
			||||||
		Gt("fee", 0).
 | 
					 | 
				
			||||||
		Sum("fee", 0)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// SumUserMonthlyPeek 获取某月带宽峰值
 | 
					// SumUserMonthlyPeek 获取某月带宽峰值
 | 
				
			||||||
// month 格式为YYYYMM
 | 
					// month 格式为YYYYMM
 | 
				
			||||||
func (this *ServerDailyStatDAO) SumUserMonthlyPeek(tx *dbs.Tx, userId int64, regionId int64, month string) (int64, error) {
 | 
					func (this *ServerDailyStatDAO) SumUserMonthlyPeek(tx *dbs.Tx, userId int64, regionId int64, month string) (int64, error) {
 | 
				
			||||||
@@ -195,6 +187,15 @@ func (this *ServerDailyStatDAO) SumUserDaily(tx *dbs.Tx, userId int64, regionId
 | 
				
			|||||||
		SumInt64("bytes", 0)
 | 
							SumInt64("bytes", 0)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SumUserMonthly 获取某月流量总和
 | 
				
			||||||
 | 
					// month 格式为YYYYMM
 | 
				
			||||||
 | 
					func (this *ServerDailyStatDAO) SumUserMonthly(tx *dbs.Tx, userId int64, month string) (int64, error) {
 | 
				
			||||||
 | 
						return this.Query(tx).
 | 
				
			||||||
 | 
							Between("day", month+"01", month+"31").
 | 
				
			||||||
 | 
							Attr("userId", userId).
 | 
				
			||||||
 | 
							SumInt64("bytes", 0)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SumUserDailyPeek 获取某天带宽峰值
 | 
					// SumUserDailyPeek 获取某天带宽峰值
 | 
				
			||||||
// day 格式为YYYYMMDD
 | 
					// day 格式为YYYYMMDD
 | 
				
			||||||
func (this *ServerDailyStatDAO) SumUserDailyPeek(tx *dbs.Tx, userId int64, regionId int64, day string) (int64, error) {
 | 
					func (this *ServerDailyStatDAO) SumUserDailyPeek(tx *dbs.Tx, userId int64, regionId int64, day string) (int64, error) {
 | 
				
			||||||
@@ -339,6 +340,59 @@ func (this *ServerDailyStatDAO) SumMonthlyStat(tx *dbs.Tx, serverId int64, month
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SumMonthlyBytes 获取某月内的流量
 | 
				
			||||||
 | 
					// month 格式为YYYYMM
 | 
				
			||||||
 | 
					func (this *ServerDailyStatDAO) SumMonthlyBytes(tx *dbs.Tx, serverId int64, month string) (result int64, err error) {
 | 
				
			||||||
 | 
						if !regexp.MustCompile(`^\d{6}$`).MatchString(month) {
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return this.Query(tx).
 | 
				
			||||||
 | 
							Result("SUM(bytes) AS bytes").
 | 
				
			||||||
 | 
							Attr("serverId", serverId).
 | 
				
			||||||
 | 
							Between("day", month+"01", month+"31").
 | 
				
			||||||
 | 
							FindInt64Col(0)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindMonthlyPercentile 获取某月内百分位
 | 
				
			||||||
 | 
					func (this *ServerDailyStatDAO) FindMonthlyPercentile(tx *dbs.Tx, serverId int64, month string, percentile int) (result int64, err error) {
 | 
				
			||||||
 | 
						if percentile <= 0 {
 | 
				
			||||||
 | 
							percentile = 95
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if percentile > 100 {
 | 
				
			||||||
 | 
							percentile = 100
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						total, err := this.Query(tx).
 | 
				
			||||||
 | 
							Attr("serverId", serverId).
 | 
				
			||||||
 | 
							Between("day", month+"01", month+"31").
 | 
				
			||||||
 | 
							Count()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return 0, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if total == 0 {
 | 
				
			||||||
 | 
							return 0, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var offset int64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if total > 1 {
 | 
				
			||||||
 | 
							offset = int64(math.Ceil(float64(total) * float64(100-percentile) / 100))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						result, err = this.Query(tx).
 | 
				
			||||||
 | 
							Result("bytes").
 | 
				
			||||||
 | 
							Attr("serverId", serverId).
 | 
				
			||||||
 | 
							Between("day", month+"01", month+"31").
 | 
				
			||||||
 | 
							Desc("bytes").
 | 
				
			||||||
 | 
							Offset(offset).
 | 
				
			||||||
 | 
							Limit(1).
 | 
				
			||||||
 | 
							FindInt64Col(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 因为是5分钟统计,所以需要除以300
 | 
				
			||||||
 | 
						result = result / 300
 | 
				
			||||||
 | 
						return
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindDailyStats 按天统计
 | 
					// FindDailyStats 按天统计
 | 
				
			||||||
func (this *ServerDailyStatDAO) FindDailyStats(tx *dbs.Tx, serverId int64, dayFrom string, dayTo string) (result []*ServerDailyStat, err error) {
 | 
					func (this *ServerDailyStatDAO) FindDailyStats(tx *dbs.Tx, serverId int64, dayFrom string, dayTo string) (result []*ServerDailyStat, err error) {
 | 
				
			||||||
	ones, err := this.Query(tx).
 | 
						ones, err := this.Query(tx).
 | 
				
			||||||
@@ -428,6 +482,25 @@ func (this *ServerDailyStatDAO) FindTopUserStats(tx *dbs.Tx, hourFrom string, ho
 | 
				
			|||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindDistinctServerIds 查找所有有流量的服务ID列表
 | 
				
			||||||
 | 
					// dayFrom YYYYMMDD
 | 
				
			||||||
 | 
					// dayTo YYYYMMDD
 | 
				
			||||||
 | 
					func (this *ServerDailyStatDAO) FindDistinctServerIds(tx *dbs.Tx, dayFrom string, dayTo string) (serverIds []int64, err error) {
 | 
				
			||||||
 | 
						dayFrom = strings.ReplaceAll(dayFrom, "-", "")
 | 
				
			||||||
 | 
						dayTo = strings.ReplaceAll(dayTo, "-", "")
 | 
				
			||||||
 | 
						ones, _, err := this.Query(tx).
 | 
				
			||||||
 | 
							Result("DISTINCT(serverId) AS serverId").
 | 
				
			||||||
 | 
							Between("day", dayFrom, dayTo).
 | 
				
			||||||
 | 
							FindOnes()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, one := range ones {
 | 
				
			||||||
 | 
							serverIds = append(serverIds, one.GetInt64("serverId"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return serverIds, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UpdateStatFee 设置费用
 | 
					// UpdateStatFee 设置费用
 | 
				
			||||||
func (this *ServerDailyStatDAO) UpdateStatFee(tx *dbs.Tx, statId int64, fee float32) error {
 | 
					func (this *ServerDailyStatDAO) UpdateStatFee(tx *dbs.Tx, statId int64, fee float32) error {
 | 
				
			||||||
	return this.Query(tx).
 | 
						return this.Query(tx).
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,7 +46,7 @@ func TestServerDailyStatDAO_SaveStats2(t *testing.T) {
 | 
				
			|||||||
func TestServerDailyStatDAO_SumUserMonthly(t *testing.T) {
 | 
					func TestServerDailyStatDAO_SumUserMonthly(t *testing.T) {
 | 
				
			||||||
	dbs.NotifyReady()
 | 
						dbs.NotifyReady()
 | 
				
			||||||
	var tx *dbs.Tx
 | 
						var tx *dbs.Tx
 | 
				
			||||||
	bytes, err := NewServerDailyStatDAO().SumUserMonthly(tx, 1, 1, timeutil.Format("Ym"))
 | 
						bytes, err := NewServerDailyStatDAO().SumUserMonthly(tx, 1, timeutil.Format("Ym"))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -68,9 +68,28 @@ func TestServerDailyStatDAO_SumMinutelyRequests(t *testing.T) {
 | 
				
			|||||||
	dbs.NotifyReady()
 | 
						dbs.NotifyReady()
 | 
				
			||||||
	var tx *dbs.Tx
 | 
						var tx *dbs.Tx
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stat, err := NewServerDailyStatDAO().SumMinutelyStat(tx, 23, timeutil.Format("Ymd") + "1435")
 | 
						stat, err := NewServerDailyStatDAO().SumMinutelyStat(tx, 23, timeutil.Format("Ymd")+"1435")
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatal(err)
 | 
							t.Fatal(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	logs.PrintAsJSON(stat, t)
 | 
						logs.PrintAsJSON(stat, t)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestServerDailyStatDAO_FindDistinctPlanServerIdsBetweenDay(t *testing.T) {
 | 
				
			||||||
 | 
						var tx *dbs.Tx
 | 
				
			||||||
 | 
						serverIds, err := NewServerDailyStatDAO().FindDistinctServerIds(tx, timeutil.Format("Ym01"), timeutil.Format("Ymd"))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						t.Log(serverIds)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestServerDailyStatDAO_FindMonthlyPercentile(t *testing.T) {
 | 
				
			||||||
 | 
						var tx *dbs.Tx
 | 
				
			||||||
 | 
						var dao = NewServerDailyStatDAO()
 | 
				
			||||||
 | 
						result, err := dao.FindMonthlyPercentile(tx, 23, timeutil.Format("Ym"), 95)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						t.Log("result:", result)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -221,6 +221,7 @@ func (this *ServerDAO) CreateServer(tx *dbs.Tx,
 | 
				
			|||||||
	op.DnsName = dnsName
 | 
						op.DnsName = dnsName
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	op.UserPlanId = userPlanId
 | 
						op.UserPlanId = userPlanId
 | 
				
			||||||
 | 
						op.LastUserPlanId = userPlanId
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	op.Version = 1
 | 
						op.Version = 1
 | 
				
			||||||
	op.IsOn = 1
 | 
						op.IsOn = 1
 | 
				
			||||||
@@ -2242,6 +2243,7 @@ func (this *ServerDAO) UpdateServerUserPlanId(tx *dbs.Tx, serverId int64, userPl
 | 
				
			|||||||
	err = this.Query(tx).
 | 
						err = this.Query(tx).
 | 
				
			||||||
		Pk(serverId).
 | 
							Pk(serverId).
 | 
				
			||||||
		Set("userPlanId", userPlanId).
 | 
							Set("userPlanId", userPlanId).
 | 
				
			||||||
 | 
							Set("lastUserPlanId", userPlanId).
 | 
				
			||||||
		Set("clusterId", plan.ClusterId).
 | 
							Set("clusterId", plan.ClusterId).
 | 
				
			||||||
		UpdateQuickly()
 | 
							UpdateQuickly()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -2250,6 +2252,19 @@ func (this *ServerDAO) UpdateServerUserPlanId(tx *dbs.Tx, serverId int64, userPl
 | 
				
			|||||||
	return this.NotifyUpdate(tx, serverId)
 | 
						return this.NotifyUpdate(tx, serverId)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindServerLastUserPlanIdAndUserId 查找最后使用的套餐
 | 
				
			||||||
 | 
					func (this *ServerDAO) FindServerLastUserPlanIdAndUserId(tx *dbs.Tx, serverId int64) (userPlanId int64, userId int64, err error) {
 | 
				
			||||||
 | 
						one, err := this.Query(tx).
 | 
				
			||||||
 | 
							Pk(serverId).
 | 
				
			||||||
 | 
							Result("lastUserPlanId", "userId").
 | 
				
			||||||
 | 
							Find()
 | 
				
			||||||
 | 
						if err != nil || one == nil {
 | 
				
			||||||
 | 
							return 0, 0, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return int64(one.(*Server).LastUserPlanId), int64(one.(*Server).UserId), nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NotifyUpdate 同步集群
 | 
					// NotifyUpdate 同步集群
 | 
				
			||||||
func (this *ServerDAO) NotifyUpdate(tx *dbs.Tx, serverId int64) error {
 | 
					func (this *ServerDAO) NotifyUpdate(tx *dbs.Tx, serverId int64) error {
 | 
				
			||||||
	// 创建任务
 | 
						// 创建任务
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -43,6 +43,7 @@ type Server struct {
 | 
				
			|||||||
	TrafficLimitStatus  string  `field:"trafficLimitStatus"`  // 流量限制状态
 | 
						TrafficLimitStatus  string  `field:"trafficLimitStatus"`  // 流量限制状态
 | 
				
			||||||
	TotalTraffic        float64 `field:"totalTraffic"`        // 总流量
 | 
						TotalTraffic        float64 `field:"totalTraffic"`        // 总流量
 | 
				
			||||||
	UserPlanId          uint32  `field:"userPlanId"`          // 所属套餐ID
 | 
						UserPlanId          uint32  `field:"userPlanId"`          // 所属套餐ID
 | 
				
			||||||
 | 
						LastUserPlanId      uint32  `field:"lastUserPlanId"`      // 上一次使用的套餐
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type ServerOperator struct {
 | 
					type ServerOperator struct {
 | 
				
			||||||
@@ -87,6 +88,7 @@ type ServerOperator struct {
 | 
				
			|||||||
	TrafficLimitStatus  interface{} // 流量限制状态
 | 
						TrafficLimitStatus  interface{} // 流量限制状态
 | 
				
			||||||
	TotalTraffic        interface{} // 总流量
 | 
						TotalTraffic        interface{} // 总流量
 | 
				
			||||||
	UserPlanId          interface{} // 所属套餐ID
 | 
						UserPlanId          interface{} // 所属套餐ID
 | 
				
			||||||
 | 
						LastUserPlanId      interface{} // 上一次使用的套餐
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewServerOperator() *ServerOperator {
 | 
					func NewServerOperator() *ServerOperator {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,9 @@
 | 
				
			|||||||
package models
 | 
					package models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
					 | 
				
			||||||
	"github.com/TeaOSLab/EdgeAPI/internal/goman"
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/goman"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/remotelogs"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeAPI/internal/utils/numberutils"
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils"
 | 
				
			||||||
	"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
 | 
				
			||||||
	_ "github.com/go-sql-driver/mysql"
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
	"github.com/iwind/TeaGo/Tea"
 | 
						"github.com/iwind/TeaGo/Tea"
 | 
				
			||||||
@@ -23,7 +22,7 @@ func init() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		goman.New(func() {
 | 
							goman.New(func() {
 | 
				
			||||||
			// 自动生成账单任务
 | 
								// 自动生成账单任务
 | 
				
			||||||
			var ticker = time.NewTicker(1 * time.Minute)
 | 
								var ticker = time.NewTicker(1 * time.Hour)
 | 
				
			||||||
			for range ticker.C {
 | 
								for range ticker.C {
 | 
				
			||||||
				// 是否已经生成了,如果已经生成了就跳过
 | 
									// 是否已经生成了,如果已经生成了就跳过
 | 
				
			||||||
				var lastMonth = timeutil.Format("Ym", time.Now().AddDate(0, -1, 0))
 | 
									var lastMonth = timeutil.Format("Ym", time.Now().AddDate(0, -1, 0))
 | 
				
			||||||
@@ -136,7 +135,7 @@ func (this *UserBillDAO) FindUnpaidBills(tx *dbs.Tx, size int64) (result []*User
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CreateBill 创建账单
 | 
					// CreateBill 创建账单
 | 
				
			||||||
func (this *UserBillDAO) CreateBill(tx *dbs.Tx, userId int64, billType BillType, description string, amount float32, month string) error {
 | 
					func (this *UserBillDAO) CreateBill(tx *dbs.Tx, userId int64, billType BillType, description string, amount float64, month string, canPay bool) error {
 | 
				
			||||||
	code, err := this.GenerateBillCode(tx)
 | 
						code, err := this.GenerateBillCode(tx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -149,9 +148,11 @@ func (this *UserBillDAO) CreateBill(tx *dbs.Tx, userId int64, billType BillType,
 | 
				
			|||||||
			"amount":      amount,
 | 
								"amount":      amount,
 | 
				
			||||||
			"month":       month,
 | 
								"month":       month,
 | 
				
			||||||
			"code":        code,
 | 
								"code":        code,
 | 
				
			||||||
			"isPaid":      false,
 | 
								"isPaid":      amount == 0,
 | 
				
			||||||
 | 
								"canPay":      canPay,
 | 
				
			||||||
		}, maps.Map{
 | 
							}, maps.Map{
 | 
				
			||||||
			"amount": amount,
 | 
								"amount": amount,
 | 
				
			||||||
 | 
								"canPay": canPay,
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -172,19 +173,16 @@ func (this *UserBillDAO) GenerateBills(tx *dbs.Tx, month string) error {
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if len(regions) == 0 {
 | 
					
 | 
				
			||||||
		return nil
 | 
						var priceItems []*NodePriceItem
 | 
				
			||||||
 | 
						if len(regions) > 0 {
 | 
				
			||||||
 | 
							priceItems, err = SharedNodePriceItemDAO.FindAllEnabledRegionPrices(tx, NodePriceTypeTraffic)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	priceItems, err := SharedNodePriceItemDAO.FindAllEnabledRegionPrices(tx, NodePriceTypeTraffic)
 | 
						// 计算服务套餐费用
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if len(priceItems) == 0 {
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// 计算套餐费用
 | 
					 | 
				
			||||||
	plans, err := SharedPlanDAO.FindAllEnabledPlans(tx)
 | 
						plans, err := SharedPlanDAO.FindAllEnabledPlans(tx)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -194,54 +192,169 @@ func (this *UserBillDAO) GenerateBills(tx *dbs.Tx, month string) error {
 | 
				
			|||||||
		planMap[int64(plan.Id)] = plan
 | 
							planMap[int64(plan.Id)] = plan
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stats, err := SharedServerDailyStatDAO.FindMonthlyStatsWithPlan(tx, month)
 | 
						var dayFrom = month + "01"
 | 
				
			||||||
 | 
						var dayTo = month + "32"
 | 
				
			||||||
 | 
						serverIds, err := SharedServerDailyStatDAO.FindDistinctServerIds(tx, dayFrom, dayTo)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for _, stat := range stats {
 | 
						var cacheMap = utils.NewCacheMap()
 | 
				
			||||||
		plan, ok := planMap[int64(stat.PlanId)]
 | 
						var userIds = []int64{}
 | 
				
			||||||
		if !ok {
 | 
						for _, serverId := range serverIds {
 | 
				
			||||||
			continue
 | 
							// 套餐类型
 | 
				
			||||||
		}
 | 
							userPlanId, userId, err := SharedServerDAO.FindServerLastUserPlanIdAndUserId(tx, serverId)
 | 
				
			||||||
		if plan.PriceType != serverconfigs.PlanPriceTypeTraffic {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if len(plan.TrafficPrice) == 0 {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		var priceConfig = &serverconfigs.PlanTrafficPrice{}
 | 
					 | 
				
			||||||
		err = json.Unmarshal([]byte(plan.TrafficPrice), priceConfig)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if priceConfig.Base > 0 {
 | 
							if userId == 0 {
 | 
				
			||||||
			var fee = priceConfig.Base * (float32(stat.Bytes) / 1024 / 1024 / 1024)
 | 
								continue
 | 
				
			||||||
			err = SharedServerDailyStatDAO.UpdateStatFee(tx, int64(stat.Id), fee)
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							userIds = append(userIds, userId)
 | 
				
			||||||
 | 
							if userPlanId == 0 {
 | 
				
			||||||
 | 
								var fee float64
 | 
				
			||||||
 | 
								for _, region := range regions {
 | 
				
			||||||
 | 
									var regionId = int64(region.Id)
 | 
				
			||||||
 | 
									var pricesMap = region.DecodePriceMap()
 | 
				
			||||||
 | 
									if len(pricesMap) == 0 {
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									trafficBytes, err := SharedServerDailyStatDAO.SumServerMonthlyWithRegion(tx, serverId, regionId, month)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if trafficBytes == 0 {
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									var itemId = SharedNodePriceItemDAO.SearchItemsWithBytes(priceItems, trafficBytes)
 | 
				
			||||||
 | 
									if itemId == 0 {
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									price, ok := pricesMap[itemId]
 | 
				
			||||||
 | 
									if !ok {
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if price <= 0 {
 | 
				
			||||||
 | 
										continue
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									var regionFee = float64(trafficBytes) / 1000 / 1000 / 1000 * 8 * price
 | 
				
			||||||
 | 
									fee += regionFee
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 总流量
 | 
				
			||||||
 | 
								totalTrafficBytes, err := SharedServerDailyStatDAO.SumMonthlyBytes(tx, serverId, month)
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				return err
 | 
									return err
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 百分位
 | 
				
			||||||
 | 
								var percentile = 95
 | 
				
			||||||
 | 
								percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								err = SharedServerBillDAO.CreateOrUpdateServerBill(tx, userId, serverId, month, userPlanId, 0, totalTrafficBytes, percentileBytes, percentile, fee)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								userPlan, err := SharedUserPlanDAO.FindUserPlanWithoutState(tx, userPlanId, cacheMap)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if userPlan == nil {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								plan, ok := planMap[int64(userPlan.PlanId)]
 | 
				
			||||||
 | 
								if !ok {
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// 总流量
 | 
				
			||||||
 | 
								totalTrafficBytes, err := SharedServerDailyStatDAO.SumMonthlyBytes(tx, serverId, month)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								switch plan.PriceType {
 | 
				
			||||||
 | 
								case serverconfigs.PlanPriceTypePeriod:
 | 
				
			||||||
 | 
									// 已经在购买套餐的时候付过费,这里不再重复计费
 | 
				
			||||||
 | 
									var fee float64 = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// 百分位
 | 
				
			||||||
 | 
									var percentile = 95
 | 
				
			||||||
 | 
									percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									err = SharedServerBillDAO.CreateOrUpdateServerBill(tx, int64(userPlan.UserId), serverId, month, userPlanId, int64(userPlan.PlanId), totalTrafficBytes, percentileBytes, percentile, fee)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case serverconfigs.PlanPriceTypeTraffic:
 | 
				
			||||||
 | 
									var config = plan.DecodeTrafficPrice()
 | 
				
			||||||
 | 
									var fee float64 = 0
 | 
				
			||||||
 | 
									if config != nil && config.Base > 0 {
 | 
				
			||||||
 | 
										fee = float64(totalTrafficBytes) / 1024 / 1024 / 1024 * float64(config.Base)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// 百分位
 | 
				
			||||||
 | 
									var percentile = 95
 | 
				
			||||||
 | 
									percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									err = SharedServerBillDAO.CreateOrUpdateServerBill(tx, int64(userPlan.UserId), serverId, month, userPlanId, int64(userPlan.PlanId), totalTrafficBytes, percentileBytes, percentile, fee)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								case serverconfigs.PlanPriceTypeBandwidth:
 | 
				
			||||||
 | 
									// 百分位
 | 
				
			||||||
 | 
									var percentile = 95
 | 
				
			||||||
 | 
									var config = plan.DecodeBandwidthPrice()
 | 
				
			||||||
 | 
									if config != nil {
 | 
				
			||||||
 | 
										percentile = config.Percentile
 | 
				
			||||||
 | 
										if percentile <= 0 {
 | 
				
			||||||
 | 
											percentile = 95
 | 
				
			||||||
 | 
										} else if percentile > 100 {
 | 
				
			||||||
 | 
											percentile = 100
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									percentileBytes, err := SharedServerDailyStatDAO.FindMonthlyPercentile(tx, serverId, month, percentile)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									var mb = float32(percentileBytes) / 1024 / 1024
 | 
				
			||||||
 | 
									var price float32
 | 
				
			||||||
 | 
									if config != nil {
 | 
				
			||||||
 | 
										price = config.LookupPrice(mb)
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									var fee = float64(price)
 | 
				
			||||||
 | 
									err = SharedServerBillDAO.CreateOrUpdateServerBill(tx, int64(userPlan.UserId), serverId, month, userPlanId, int64(userPlan.PlanId), totalTrafficBytes, percentileBytes, percentile, fee)
 | 
				
			||||||
 | 
									if err != nil {
 | 
				
			||||||
 | 
										return err
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 用户
 | 
						// 计算用户费用
 | 
				
			||||||
	offset := int64(0)
 | 
						for _, userId := range userIds {
 | 
				
			||||||
	size := int64(100) // 每次只查询N次,防止由于执行时间过长而锁表
 | 
							if userId == 0 {
 | 
				
			||||||
	for {
 | 
								continue
 | 
				
			||||||
		userIds, err := SharedUserDAO.ListEnabledUserIds(tx, offset, size)
 | 
							}
 | 
				
			||||||
 | 
							amount, err := SharedServerBillDAO.SumUserMonthlyAmount(tx, userId, month)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		offset += size
 | 
							err = SharedUserBillDAO.CreateBill(tx, userId, BillTypeTraffic, "流量带宽费用", amount, month, month < timeutil.Format("Ym"))
 | 
				
			||||||
		if len(userIds) == 0 {
 | 
							if err != nil {
 | 
				
			||||||
			break
 | 
								return err
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for _, userId := range userIds {
 | 
					 | 
				
			||||||
			// CDN流量账单
 | 
					 | 
				
			||||||
			err := this.generateTrafficBill(tx, userId, month, regions, priceItems)
 | 
					 | 
				
			||||||
			if err != nil {
 | 
					 | 
				
			||||||
				return err
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -256,74 +369,11 @@ func (this *UserBillDAO) UpdateUserBillIsPaid(tx *dbs.Tx, billId int64, isPaid b
 | 
				
			|||||||
		UpdateQuickly()
 | 
							UpdateQuickly()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 生成CDN流量账单
 | 
					 | 
				
			||||||
// month 格式YYYYMM
 | 
					 | 
				
			||||||
func (this *UserBillDAO) generateTrafficBill(tx *dbs.Tx, userId int64, month string, regions []*NodeRegion, priceItems []*NodePriceItem) error {
 | 
					 | 
				
			||||||
	// 检查是否已经有账单了
 | 
					 | 
				
			||||||
	if month < timeutil.Format("Ym") {
 | 
					 | 
				
			||||||
		b, err := this.ExistBill(tx, userId, BillTypeTraffic, month)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if b {
 | 
					 | 
				
			||||||
			return nil
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	var cost = float32(0)
 | 
					 | 
				
			||||||
	for _, region := range regions {
 | 
					 | 
				
			||||||
		if len(region.Prices) == 0 || region.Prices == "null" {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		priceMap := map[string]float32{}
 | 
					 | 
				
			||||||
		err := json.Unmarshal([]byte(region.Prices), &priceMap)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		trafficBytes, err := SharedServerDailyStatDAO.SumUserMonthlyWithoutPlan(tx, userId, int64(region.Id), month)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if trafficBytes == 0 {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		itemId := SharedNodePriceItemDAO.SearchItemsWithBytes(priceItems, trafficBytes)
 | 
					 | 
				
			||||||
		if itemId == 0 {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		price, ok := priceMap[numberutils.FormatInt64(itemId)]
 | 
					 | 
				
			||||||
		if !ok {
 | 
					 | 
				
			||||||
			continue
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// 计算钱
 | 
					 | 
				
			||||||
		// 这里采用1000进制
 | 
					 | 
				
			||||||
		cost += (float32(trafficBytes*8) / 1_000_000_000) * price
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// 套餐费用
 | 
					 | 
				
			||||||
	planFee, err := SharedServerDailyStatDAO.SumUserMonthlyFee(tx, userId, month)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	cost += float32(planFee)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if cost == 0 {
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// 创建账单
 | 
					 | 
				
			||||||
	return this.CreateBill(tx, userId, BillTypeTraffic, "按流量计费", cost, month)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// BillTypeName 获取账单类型名称
 | 
					// BillTypeName 获取账单类型名称
 | 
				
			||||||
func (this *UserBillDAO) BillTypeName(billType BillType) string {
 | 
					func (this *UserBillDAO) BillTypeName(billType BillType) string {
 | 
				
			||||||
	switch billType {
 | 
						switch billType {
 | 
				
			||||||
	case BillTypeTraffic:
 | 
						case BillTypeTraffic:
 | 
				
			||||||
		return "流量"
 | 
							return "流量带宽"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return ""
 | 
						return ""
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,10 @@ type UserBill struct {
 | 
				
			|||||||
	Type        string  `field:"type"`        // 消费类型
 | 
						Type        string  `field:"type"`        // 消费类型
 | 
				
			||||||
	Description string  `field:"description"` // 描述
 | 
						Description string  `field:"description"` // 描述
 | 
				
			||||||
	Amount      float64 `field:"amount"`      // 消费数额
 | 
						Amount      float64 `field:"amount"`      // 消费数额
 | 
				
			||||||
 | 
						DayFrom     string  `field:"dayFrom"`     // YYYYMMDD
 | 
				
			||||||
 | 
						DayTo       string  `field:"dayTo"`       // YYYYMMDD
 | 
				
			||||||
	Month       string  `field:"month"`       // 帐期YYYYMM
 | 
						Month       string  `field:"month"`       // 帐期YYYYMM
 | 
				
			||||||
 | 
						CanPay      uint8   `field:"canPay"`      // 是否可以支付
 | 
				
			||||||
	IsPaid      uint8   `field:"isPaid"`      // 是否已支付
 | 
						IsPaid      uint8   `field:"isPaid"`      // 是否已支付
 | 
				
			||||||
	PaidAt      uint64  `field:"paidAt"`      // 支付时间
 | 
						PaidAt      uint64  `field:"paidAt"`      // 支付时间
 | 
				
			||||||
	Code        string  `field:"code"`        // 账单编号
 | 
						Code        string  `field:"code"`        // 账单编号
 | 
				
			||||||
@@ -20,7 +23,10 @@ type UserBillOperator struct {
 | 
				
			|||||||
	Type        interface{} // 消费类型
 | 
						Type        interface{} // 消费类型
 | 
				
			||||||
	Description interface{} // 描述
 | 
						Description interface{} // 描述
 | 
				
			||||||
	Amount      interface{} // 消费数额
 | 
						Amount      interface{} // 消费数额
 | 
				
			||||||
 | 
						DayFrom     interface{} // YYYYMMDD
 | 
				
			||||||
 | 
						DayTo       interface{} // YYYYMMDD
 | 
				
			||||||
	Month       interface{} // 帐期YYYYMM
 | 
						Month       interface{} // 帐期YYYYMM
 | 
				
			||||||
 | 
						CanPay      interface{} // 是否可以支付
 | 
				
			||||||
	IsPaid      interface{} // 是否已支付
 | 
						IsPaid      interface{} // 是否已支付
 | 
				
			||||||
	PaidAt      interface{} // 支付时间
 | 
						PaidAt      interface{} // 支付时间
 | 
				
			||||||
	Code        interface{} // 账单编号
 | 
						Code        interface{} // 账单编号
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -95,6 +95,18 @@ func (this *UserDAO) FindEnabledBasicUser(tx *dbs.Tx, id int64) (*User, error) {
 | 
				
			|||||||
	return result.(*User), err
 | 
						return result.(*User), err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindBasicUserWithoutState 查找用户基本信息,并忽略状态
 | 
				
			||||||
 | 
					func (this *UserDAO) FindBasicUserWithoutState(tx *dbs.Tx, id int64) (*User, error) {
 | 
				
			||||||
 | 
						result, err := this.Query(tx).
 | 
				
			||||||
 | 
							Pk(id).
 | 
				
			||||||
 | 
							Result("id", "fullname", "username").
 | 
				
			||||||
 | 
							Find()
 | 
				
			||||||
 | 
						if result == nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return result.(*User), err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// FindUserFullname 获取管理员名称
 | 
					// FindUserFullname 获取管理员名称
 | 
				
			||||||
func (this *UserDAO) FindUserFullname(tx *dbs.Tx, userId int64) (string, error) {
 | 
					func (this *UserDAO) FindUserFullname(tx *dbs.Tx, userId int64) (string, error) {
 | 
				
			||||||
	return this.Query(tx).
 | 
						return this.Query(tx).
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,6 +85,31 @@ func (this *UserPlanDAO) FindEnabledUserPlan(tx *dbs.Tx, userPlanId int64, cache
 | 
				
			|||||||
	return result.(*UserPlan), err
 | 
						return result.(*UserPlan), err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// FindUserPlanWithoutState 查找套餐,并不检查状态
 | 
				
			||||||
 | 
					// 防止因为删除套餐而导致计费失败
 | 
				
			||||||
 | 
					func (this *UserPlanDAO) FindUserPlanWithoutState(tx *dbs.Tx, userPlanId int64, cacheMap *utils.CacheMap) (*UserPlan, error) {
 | 
				
			||||||
 | 
						var cacheKey = this.Table + ":FindUserPlanWithoutState:" + types.String(userPlanId)
 | 
				
			||||||
 | 
						if cacheMap != nil {
 | 
				
			||||||
 | 
							cache, ok := cacheMap.Get(cacheKey)
 | 
				
			||||||
 | 
							if ok {
 | 
				
			||||||
 | 
								return cache.(*UserPlan), nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result, err := this.Query(tx).
 | 
				
			||||||
 | 
							Pk(userPlanId).
 | 
				
			||||||
 | 
							Find()
 | 
				
			||||||
 | 
						if result == nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if cacheMap != nil {
 | 
				
			||||||
 | 
							cacheMap.Put(cacheKey, result)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result.(*UserPlan), err
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CountAllEnabledUserPlans 计算套餐数量
 | 
					// CountAllEnabledUserPlans 计算套餐数量
 | 
				
			||||||
func (this *UserPlanDAO) CountAllEnabledUserPlans(tx *dbs.Tx, userId int64, isAvailable bool, isExpired bool, expiringDays int32) (int64, error) {
 | 
					func (this *UserPlanDAO) CountAllEnabledUserPlans(tx *dbs.Tx, userId int64, isAvailable bool, isExpired bool, expiringDays int32) (int64, error) {
 | 
				
			||||||
	var query = this.Query(tx).
 | 
						var query = this.Query(tx).
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -348,6 +348,11 @@ func (this *APINode) registerServices(server *grpc.Server) {
 | 
				
			|||||||
		pb.RegisterUserBillServiceServer(server, instance)
 | 
							pb.RegisterUserBillServiceServer(server, instance)
 | 
				
			||||||
		this.rest(instance)
 | 
							this.rest(instance)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							instance := this.serviceInstance(&services.ServerBillService{}).(*services.ServerBillService)
 | 
				
			||||||
 | 
							pb.RegisterServerBillServiceServer(server, instance)
 | 
				
			||||||
 | 
							this.rest(instance)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		instance := this.serviceInstance(&services.UserNodeService{}).(*services.UserNodeService)
 | 
							instance := this.serviceInstance(&services.UserNodeService{}).(*services.UserNodeService)
 | 
				
			||||||
		pb.RegisterUserNodeServiceServer(server, instance)
 | 
							pb.RegisterUserNodeServiceServer(server, instance)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										131
									
								
								internal/rpc/services/service_server_bill.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								internal/rpc/services/service_server_bill.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,131 @@
 | 
				
			|||||||
 | 
					// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package services
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"context"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/db/models"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeAPI/internal/utils"
 | 
				
			||||||
 | 
						"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ServerBillService 服务账单相关服务
 | 
				
			||||||
 | 
					type ServerBillService struct {
 | 
				
			||||||
 | 
						BaseService
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CountAllServerBills 查询服务账单数量
 | 
				
			||||||
 | 
					func (this *ServerBillService) CountAllServerBills(ctx context.Context, req *pb.CountAllServerBillsRequest) (*pb.RPCCountResponse, error) {
 | 
				
			||||||
 | 
						_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if userId > 0 {
 | 
				
			||||||
 | 
							req.UserId = userId
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
						count, err := models.SharedServerBillDAO.CountServerBills(tx, req.UserId, req.Month)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return this.SuccessCount(count)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ListServerBills 查询服务账单列表
 | 
				
			||||||
 | 
					func (this *ServerBillService) ListServerBills(ctx context.Context, req *pb.ListServerBillsRequest) (*pb.ListServerBillsResponse, error) {
 | 
				
			||||||
 | 
						_, userId, err := this.ValidateAdminAndUser(ctx, 0, 0)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if userId > 0 {
 | 
				
			||||||
 | 
							req.UserId = userId
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var tx = this.NullTx()
 | 
				
			||||||
 | 
						serverBills, err := models.SharedServerBillDAO.ListServerBills(tx, req.UserId, req.Month, req.Offset, req.Size)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var pbServerBills = []*pb.ServerBill{}
 | 
				
			||||||
 | 
						var cacheMap = utils.NewCacheMap()
 | 
				
			||||||
 | 
						for _, bill := range serverBills {
 | 
				
			||||||
 | 
							// user
 | 
				
			||||||
 | 
							user, err := models.SharedUserDAO.FindBasicUserWithoutState(tx, int64(bill.UserId))
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							var pbUser = &pb.User{Id: int64(bill.UserId)}
 | 
				
			||||||
 | 
							if user != nil {
 | 
				
			||||||
 | 
								pbUser = &pb.User{
 | 
				
			||||||
 | 
									Id:       int64(bill.UserId),
 | 
				
			||||||
 | 
									Username: user.Username,
 | 
				
			||||||
 | 
									Fullname: user.Fullname,
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// plan
 | 
				
			||||||
 | 
							var pbPlan *pb.Plan
 | 
				
			||||||
 | 
							if bill.PlanId > 0 {
 | 
				
			||||||
 | 
								plan, err := models.SharedPlanDAO.FindEnabledPlan(tx, int64(bill.PlanId))
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if plan != nil {
 | 
				
			||||||
 | 
									pbPlan = &pb.Plan{
 | 
				
			||||||
 | 
										Id:        int64(plan.Id),
 | 
				
			||||||
 | 
										Name:      plan.Name,
 | 
				
			||||||
 | 
										PriceType: plan.PriceType,
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// user plan
 | 
				
			||||||
 | 
							var pbUserPlan *pb.UserPlan
 | 
				
			||||||
 | 
							if bill.UserPlanId > 0 {
 | 
				
			||||||
 | 
								userPlan, err := models.SharedUserPlanDAO.FindEnabledUserPlan(tx, int64(bill.UserPlanId), cacheMap)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if userPlan != nil {
 | 
				
			||||||
 | 
									pbUserPlan = &pb.UserPlan{
 | 
				
			||||||
 | 
										Id: int64(userPlan.Id),
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// server
 | 
				
			||||||
 | 
							var pbServer *pb.Server
 | 
				
			||||||
 | 
							if bill.ServerId > 0 {
 | 
				
			||||||
 | 
								server, err := models.SharedServerDAO.FindEnabledServerBasic(tx, int64(bill.ServerId))
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									return nil, err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if server != nil {
 | 
				
			||||||
 | 
									pbServer = &pb.Server{Id: int64(bill.ServerId), Name: server.Name}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pbServerBills = append(pbServerBills, &pb.ServerBill{
 | 
				
			||||||
 | 
								Id:                       int64(bill.Id),
 | 
				
			||||||
 | 
								UserId:                   int64(bill.UserId),
 | 
				
			||||||
 | 
								ServerId:                 int64(bill.ServerId),
 | 
				
			||||||
 | 
								Amount:                   float32(bill.Amount),
 | 
				
			||||||
 | 
								CreatedAt:                int64(bill.CreatedAt),
 | 
				
			||||||
 | 
								UserPlanId:               int64(bill.UserPlanId),
 | 
				
			||||||
 | 
								PlanId:                   int64(bill.PlanId),
 | 
				
			||||||
 | 
								TotalTrafficBytes:        int64(bill.TotalTrafficBytes),
 | 
				
			||||||
 | 
								BandwidthPercentileBytes: int64(bill.BandwidthPercentileBytes),
 | 
				
			||||||
 | 
								BandwidthPercentile:      int32(bill.BandwidthPercentile),
 | 
				
			||||||
 | 
								User:                     pbUser,
 | 
				
			||||||
 | 
								Plan:                     pbPlan,
 | 
				
			||||||
 | 
								UserPlan:                 pbUserPlan,
 | 
				
			||||||
 | 
								Server:                   pbServer,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return &pb.ListServerBillsResponse{ServerBills: pbServerBills}, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -406,7 +406,7 @@ func (this *UserService) ComposeUserDashboard(ctx context.Context, req *pb.Compo
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// 本月总流量
 | 
						// 本月总流量
 | 
				
			||||||
	month := timeutil.Format("Ym")
 | 
						month := timeutil.Format("Ym")
 | 
				
			||||||
	monthlyTrafficBytes, err := models.SharedServerDailyStatDAO.SumUserMonthly(tx, req.UserId, 0, month)
 | 
						monthlyTrafficBytes, err := models.SharedServerDailyStatDAO.SumUserMonthly(tx, req.UserId, month)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -74,7 +74,7 @@ func (this *UserBillService) ListUserBills(ctx context.Context, req *pb.ListUser
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	result := []*pb.UserBill{}
 | 
						result := []*pb.UserBill{}
 | 
				
			||||||
	for _, bill := range bills {
 | 
						for _, bill := range bills {
 | 
				
			||||||
		user, err := models.SharedUserDAO.FindEnabledBasicUser(tx, int64(bill.UserId))
 | 
							user, err := models.SharedUserDAO.FindBasicUserWithoutState(tx, int64(bill.UserId))
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -85,15 +85,17 @@ func (this *UserBillService) ListUserBills(ctx context.Context, req *pb.ListUser
 | 
				
			|||||||
		result = append(result, &pb.UserBill{
 | 
							result = append(result, &pb.UserBill{
 | 
				
			||||||
			Id: int64(bill.Id),
 | 
								Id: int64(bill.Id),
 | 
				
			||||||
			User: &pb.User{
 | 
								User: &pb.User{
 | 
				
			||||||
				Id:       int64(bill.UserId),
 | 
									Id:        int64(bill.UserId),
 | 
				
			||||||
				Fullname: user.Fullname,
 | 
									Fullname:  user.Fullname,
 | 
				
			||||||
				Username: user.Username,
 | 
									Username:  user.Username,
 | 
				
			||||||
 | 
									IsDeleted: user.State == models.UserStateDisabled,
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			Type:        bill.Type,
 | 
								Type:        bill.Type,
 | 
				
			||||||
			TypeName:    models.SharedUserBillDAO.BillTypeName(bill.Type),
 | 
								TypeName:    models.SharedUserBillDAO.BillTypeName(bill.Type),
 | 
				
			||||||
			Description: bill.Description,
 | 
								Description: bill.Description,
 | 
				
			||||||
			Amount:      float32(bill.Amount),
 | 
								Amount:      float32(bill.Amount),
 | 
				
			||||||
			Month:       bill.Month,
 | 
								Month:       bill.Month,
 | 
				
			||||||
 | 
								CanPay:      bill.CanPay == 1,
 | 
				
			||||||
			IsPaid:      bill.IsPaid == 1,
 | 
								IsPaid:      bill.IsPaid == 1,
 | 
				
			||||||
			PaidAt:      int64(bill.PaidAt),
 | 
								PaidAt:      int64(bill.PaidAt),
 | 
				
			||||||
			Code:        bill.Code,
 | 
								Code:        bill.Code,
 | 
				
			||||||
@@ -151,6 +153,7 @@ func (this *UserBillService) FindUserBill(ctx context.Context, req *pb.FindUserB
 | 
				
			|||||||
			Description: bill.Description,
 | 
								Description: bill.Description,
 | 
				
			||||||
			Amount:      float32(bill.Amount),
 | 
								Amount:      float32(bill.Amount),
 | 
				
			||||||
			Month:       bill.Month,
 | 
								Month:       bill.Month,
 | 
				
			||||||
 | 
								CanPay:      bill.CanPay == 1,
 | 
				
			||||||
			IsPaid:      bill.IsPaid == 1,
 | 
								IsPaid:      bill.IsPaid == 1,
 | 
				
			||||||
			PaidAt:      int64(bill.PaidAt),
 | 
								PaidAt:      int64(bill.PaidAt),
 | 
				
			||||||
			Code:        bill.Code,
 | 
								Code:        bill.Code,
 | 
				
			||||||
@@ -194,6 +197,10 @@ func (this *UserBillService) PayUserBill(ctx context.Context, req *pb.PayUserBil
 | 
				
			|||||||
			return models.SharedUserBillDAO.UpdateUserBillIsPaid(tx, req.UserBillId, true)
 | 
								return models.SharedUserBillDAO.UpdateUserBillIsPaid(tx, req.UserBillId, true)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if bill.CanPay == 0 {
 | 
				
			||||||
 | 
								return errors.New("can not pay now")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// 余额是否足够
 | 
							// 余额是否足够
 | 
				
			||||||
		account, err := accounts.SharedUserAccountDAO.FindUserAccountWithUserId(tx, userId)
 | 
							account, err := accounts.SharedUserAccountDAO.FindUserAccountWithUserId(tx, userId)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -65,6 +65,9 @@ var upgradeFuncs = []*upgradeVersion{
 | 
				
			|||||||
	{
 | 
						{
 | 
				
			||||||
		"0.4.0", upgradeV0_4_0,
 | 
							"0.4.0", upgradeV0_4_0,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							"0.4.1", upgradeV0_4_1,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// UpgradeSQLData 升级SQL数据
 | 
					// UpgradeSQLData 升级SQL数据
 | 
				
			||||||
@@ -569,3 +572,14 @@ func upgradeV0_4_0(db *dbs.DB) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// v0.4.1
 | 
				
			||||||
 | 
					func upgradeV0_4_1(db *dbs.DB) error {
 | 
				
			||||||
 | 
						// 升级 servers.lastUserPlanId
 | 
				
			||||||
 | 
						_, err := db.Exec("UPDATE edgeServers SET lastUserPlanId=userPlanId WHERE userPlanId>0")
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,7 +85,6 @@ func TestUpgradeSQLData_v0_3_7(t *testing.T) {
 | 
				
			|||||||
	t.Log("ok")
 | 
						t.Log("ok")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestUpgradeSQLData_v0_4_0(t *testing.T) {
 | 
					func TestUpgradeSQLData_v0_4_0(t *testing.T) {
 | 
				
			||||||
	db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
 | 
						db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
 | 
				
			||||||
		Driver: "mysql",
 | 
							Driver: "mysql",
 | 
				
			||||||
@@ -101,3 +100,19 @@ func TestUpgradeSQLData_v0_4_0(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	t.Log("ok")
 | 
						t.Log("ok")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestUpgradeSQLData_v0_4_1(t *testing.T) {
 | 
				
			||||||
 | 
						db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
 | 
				
			||||||
 | 
							Driver: "mysql",
 | 
				
			||||||
 | 
							Dsn:    "root:123456@tcp(127.0.0.1:3306)/db_edge?charset=utf8mb4&timeout=30s",
 | 
				
			||||||
 | 
							Prefix: "edge",
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						err = upgradeV0_4_1(db)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Fatal(err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						t.Log("ok")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user