低空智控平台 后端go
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

224 lines
7.1 KiB

package service
import (
"errors"
"time"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"laic-backend/common"
"laic-backend/logger"
"laic-backend/model"
"laic-backend/tool"
"laic-backend/vo"
)
type PlatformBillingService struct{}
var DefaultPlatformBillingService = &PlatformBillingService{}
func (s *PlatformBillingService) GetPool() (*model.PlatformResourcePool, *common.BusiError) {
var pool model.PlatformResourcePool
err := common.DB.Order("id ASC").First(&pool).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, common.ErrNotFound
}
if err != nil {
logger.ERROR("查询平台资源池失败", err)
return nil, common.ErrInternal
}
return &pool, nil
}
func (s *PlatformBillingService) CreatePurchase(adminID int64, req *vo.PlatformPurchaseCreateReq) (*model.PlatformResourcePurchase, *common.BusiError) {
var purchase model.PlatformResourcePurchase
now := time.Now()
err := common.DB.Transaction(func(tx *gorm.DB) error {
if err := tx.Where("batch_no = ?", req.BatchNo).First(&purchase).Error; err == nil {
if purchase.Provider == req.Provider && purchase.TotalBytes == req.TotalBytes && purchase.TotalCost == req.TotalCost {
return gorm.ErrDuplicatedKey
}
return common.NewBusiError(common.ParamError, "采购批次号已存在且内容不一致")
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
id, err := tool.NextID()
if err != nil {
return err
}
purchase = model.PlatformResourcePurchase{
ID: id, BatchNo: req.BatchNo, Provider: req.Provider, TotalBytes: req.TotalBytes,
UnitCost: req.UnitCost, TotalCost: req.TotalCost, ExpiresAt: req.ExpiresAt,
Status: "active", Remark: req.Remark, CreatedBy: adminID, CreatedAt: now, UpdatedAt: now,
}
if err := tx.Create(&purchase).Error; err != nil {
return err
}
var pool model.PlatformResourcePool
err = tx.Clauses(clause.Locking{Strength: "UPDATE"}).Order("id ASC").First(&pool).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
pool = model.PlatformResourcePool{ID: mustPlatformID(), Status: "active", CreatedAt: now, UpdatedAt: now}
if pool.ID == 0 {
return common.ErrInternal
}
if err := tx.Create(&pool).Error; err != nil {
return err
}
err = nil
}
if err != nil {
return err
}
before := pool.AvailableBytes
if err := tx.Model(&pool).Updates(map[string]any{
"total_bytes": gorm.Expr("total_bytes + ?", req.TotalBytes),
"available_bytes": gorm.Expr("available_bytes + ?", req.TotalBytes),
"version": gorm.Expr("version + 1"), "updated_at": now,
}).Error; err != nil {
return err
}
return tx.Create(&model.TrafficLedger{
ID: mustPlatformID(), AccountType: "platform", AccountID: pool.ID, Direction: "credit",
AmountBytes: req.TotalBytes, BalanceBefore: before, BalanceAfter: before + req.TotalBytes,
SourceType: "purchase", SourceID: req.BatchNo, IdempotencyKey: "purchase:" + req.BatchNo,
OperatorID: adminID, CreatedAt: now,
}).Error
})
if err != nil {
if errors.Is(err, gorm.ErrDuplicatedKey) {
return &purchase, nil
}
if busiErr, ok := err.(*common.BusiError); ok {
return nil, busiErr
}
logger.ERROR("录入平台资源采购失败", err)
return nil, common.ErrInternal
}
return &purchase, nil
}
func (s *PlatformBillingService) GetPurchasePage(req *vo.PlatformPurchasePageReq) (*common.PageResponse[model.PlatformResourcePurchase], *common.BusiError) {
db := common.DB.Model(&model.PlatformResourcePurchase{})
if req.Status != "" {
db = db.Where("status = ?", req.Status)
}
if req.Provider != "" {
db = db.Where("provider = ?", req.Provider)
}
if req.Keyword != "" {
db = db.Where("batch_no LIKE ?", "%"+req.Keyword+"%")
}
var total int64
if err := db.Count(&total).Error; err != nil {
return nil, common.ErrInternal
}
var list []model.PlatformResourcePurchase
if err := db.Scopes(req.Paginate).Order("created_at DESC, id DESC").Find(&list).Error; err != nil {
return nil, common.ErrInternal
}
return common.Page(req.Pagination, total, list), nil
}
func (s *PlatformBillingService) CreatePackage(req *vo.TrafficPackageCreateReq) (*model.TrafficPackage, *common.BusiError) {
id, err := tool.NextID()
if err != nil {
return nil, common.ErrInternal
}
now := time.Now()
pkg := &model.TrafficPackage{ID: id, Code: req.Code, Name: req.Name, AmountBytes: req.AmountBytes, Price: req.Price, ValidityDays: req.ValidityDays, Status: "active", Sort: req.Sort, CreatedAt: now, UpdatedAt: now}
if err := common.DB.Create(pkg).Error; err != nil {
if code, _ := common.ParseError(err); code == 1062 {
return nil, common.NewBusiError(common.ParamError, "套餐编码已存在")
}
return nil, common.ErrInternal
}
return pkg, nil
}
func (s *PlatformBillingService) GetPackagePage(req *vo.TrafficPackagePageReq) (*common.PageResponse[model.TrafficPackage], *common.BusiError) {
db := common.DB.Model(&model.TrafficPackage{})
if req.Status != "" {
db = db.Where("status = ?", req.Status)
}
var total int64
if err := db.Count(&total).Error; err != nil {
return nil, common.ErrInternal
}
var list []model.TrafficPackage
if err := db.Scopes(req.Paginate).Order("sort ASC, id DESC").Find(&list).Error; err != nil {
return nil, common.ErrInternal
}
return common.Page(req.Pagination, total, list), nil
}
func (s *PlatformBillingService) UpdatePackage(id int64, req *vo.TrafficPackageUpdateReq) *common.BusiError {
updates := map[string]any{"updated_at": time.Now(), "sort": req.Sort}
if req.Name != "" {
updates["name"] = req.Name
}
if req.AmountBytes > 0 {
updates["amount_bytes"] = req.AmountBytes
}
if req.Price > 0 {
updates["price"] = req.Price
}
if req.ValidityDays > 0 {
updates["validity_days"] = req.ValidityDays
}
if req.Status != "" {
updates["status"] = req.Status
}
res := common.DB.Model(&model.TrafficPackage{}).Where("id = ?", id).Updates(updates)
if res.Error != nil {
return common.ErrInternal
}
if res.RowsAffected == 0 {
return common.ErrNotFound
}
return nil
}
func (s *PlatformBillingService) DisablePackage(id int64) *common.BusiError {
res := common.DB.Model(&model.TrafficPackage{}).Where("id = ?", id).Updates(map[string]any{"status": "inactive", "updated_at": time.Now()})
if res.Error != nil {
return common.ErrInternal
}
if res.RowsAffected == 0 {
return common.ErrNotFound
}
return nil
}
func (s *PlatformBillingService) GetLedgerPage(req *vo.TrafficLedgerPageReq) (*common.PageResponse[model.TrafficLedger], *common.BusiError) {
db := common.DB.Model(&model.TrafficLedger{})
if req.AccountType != "" {
db = db.Where("account_type = ?", req.AccountType)
}
if req.AccountID > 0 {
db = db.Where("account_id = ?", req.AccountID)
}
if req.SourceType != "" {
db = db.Where("source_type = ?", req.SourceType)
}
var total int64
if err := db.Count(&total).Error; err != nil {
return nil, common.ErrInternal
}
var list []model.TrafficLedger
if err := db.Scopes(req.Paginate).Order("created_at DESC, id DESC").Find(&list).Error; err != nil {
return nil, common.ErrInternal
}
return common.Page(req.Pagination, total, list), nil
}
func mustPlatformID() int64 {
id, err := tool.NextID()
if err != nil {
logger.ERROR("生成平台账务 ID 失败", err)
return 0
}
return id
}