bugfix: 实现和余额表同步以及把修改待发数据的接口与申诉合并
This commit is contained in:
parent
142bf642dd
commit
7748878608
@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
bundleConfig "micro-bundle/config"
|
||||
"micro-bundle/internal/controller"
|
||||
"micro-bundle/internal/dao"
|
||||
_ "micro-bundle/internal/handler"
|
||||
"micro-bundle/pkg/app"
|
||||
"micro-bundle/pkg/db"
|
||||
@ -32,6 +33,12 @@ func main() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 一次性执行任务余额同步(幂等):若已执行或存在数据则跳过
|
||||
if syncErr := dao.RunInitialTaskBalanceSync(); syncErr != nil {
|
||||
app.ModuleClients.Lg.Warn("initial task-balance sync failed", zap.Error(syncErr))
|
||||
}
|
||||
|
||||
//l, err := net.Listen("tcp", ":8883")
|
||||
//if err != nil {
|
||||
// fmt.Printf("failed to listen: %v", err)
|
||||
|
@ -93,6 +93,8 @@ func (b *BundleProvider) UpdatePendingCount(_ context.Context, req *bundle.Updat
|
||||
PendingDataCount: int(req.PendingDataCount),
|
||||
Operator: req.Operator,
|
||||
OperatorNum: req.OperatorNum,
|
||||
TaskAssignee: req.TaskAssignee,
|
||||
TaskAssigneeNum: req.TaskAssigneeNum,
|
||||
}
|
||||
|
||||
// 调用logic层
|
||||
|
459
internal/dao/taskBalanceSync.go
Normal file
459
internal/dao/taskBalanceSync.go
Normal file
@ -0,0 +1,459 @@
|
||||
package dao
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
|
||||
"micro-bundle/internal/model"
|
||||
"micro-bundle/pkg/app"
|
||||
)
|
||||
|
||||
// RunInitialTaskBalanceSync 一次性将 BundleBalance 同步到 TaskBalance
|
||||
// 仅在未执行过且任务余额表为空时运行;执行成功后写入标记,避免再次执行
|
||||
func RunInitialTaskBalanceSync() error {
|
||||
// 确保标记表存在
|
||||
_ = app.ModuleClients.TaskBenchDB.AutoMigrate(&model.TaskSyncStatus{})
|
||||
|
||||
// 已执行标记检查
|
||||
var markerCount int64
|
||||
if err := app.ModuleClients.TaskBenchDB.Model(&model.TaskSyncStatus{}).
|
||||
Where("sync_key = ?", model.InitialSyncKey).Count(&markerCount).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if markerCount > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 安全检查:如果任务余额表已存在数据,则不再执行,同样写入标记
|
||||
var existing int64
|
||||
if err := app.ModuleClients.TaskBenchDB.Model(&model.TaskBalance{}).Count(&existing).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if existing > 0 {
|
||||
_ = app.ModuleClients.TaskBenchDB.Create(&model.TaskSyncStatus{
|
||||
SyncKey: model.InitialSyncKey,
|
||||
ExecutedAt: time.Now(),
|
||||
Remark: "skipped: task_balance already has data",
|
||||
}).Error
|
||||
return nil
|
||||
}
|
||||
|
||||
// 获取当前有效(未过期且已支付)的艺人及其最新订单
|
||||
validArtists, err := GetValidArtistList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(validArtists) == 0 {
|
||||
_ = app.ModuleClients.TaskBenchDB.Create(&model.TaskSyncStatus{
|
||||
SyncKey: model.InitialSyncKey,
|
||||
ExecutedAt: time.Now(),
|
||||
Remark: "skipped: no valid artists",
|
||||
}).Error
|
||||
return nil
|
||||
}
|
||||
|
||||
// 构造待插入的 TaskBalance 列表
|
||||
tasks := make([]model.TaskBalance, 0, len(validArtists))
|
||||
for _, a := range validArtists {
|
||||
// 根据 user_id + order_uuid 获取 BundleBalance 明细
|
||||
var bb model.BundleBalance
|
||||
if err := app.ModuleClients.BundleDB.Where("user_id = ? AND order_uuid = ?", a.UserID, a.OrderUUID).First(&bb).Error; err != nil {
|
||||
// 若未查到则跳过该条
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
subNum, telNum, err := fetchIdentityForBundle(&bb)
|
||||
if err != nil {
|
||||
// 无法获取身份信息则跳过该条
|
||||
continue
|
||||
}
|
||||
|
||||
tb := model.TaskBalance{
|
||||
SubNum: subNum,
|
||||
TelNum: telNum,
|
||||
Month: bb.Month,
|
||||
StartAt: bb.StartAt,
|
||||
ExpiredAt: bb.ExpiredAt,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
copyBundleToTaskBalance(&tb, &bb)
|
||||
tasks = append(tasks, tb)
|
||||
}
|
||||
|
||||
// 原子写入:插入 TaskBalance + 插入标记
|
||||
tx := app.ModuleClients.TaskBenchDB.Begin()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
|
||||
if len(tasks) > 0 {
|
||||
if err := tx.Create(&tasks).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := tx.Create(&model.TaskSyncStatus{
|
||||
SyncKey: model.InitialSyncKey,
|
||||
ExecutedAt: time.Now(),
|
||||
Remark: "initial sync executed",
|
||||
}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 用户新买套餐时使用
|
||||
// SyncTaskBalanceFromBundleBalance 增量/每月:根据单条 BundleBalance 同步或更新 TaskBalance(按 sub_num + tel_num + month 唯一)
|
||||
func SyncTaskBalanceFromBundleBalance(bb model.BundleBalance) error {
|
||||
// 获取身份信息(sub_num, tel_num)
|
||||
subNum, telNum, err := fetchIdentityForBundle(&bb)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 组装 TaskBalance
|
||||
tb := model.TaskBalance{
|
||||
SubNum: subNum,
|
||||
TelNum: telNum,
|
||||
Month: bb.Month,
|
||||
ExpiredAt: bb.ExpiredAt,
|
||||
StartAt: bb.StartAt,
|
||||
UpdatedAt: time.Now(),
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
copyBundleToTaskBalance(&tb, &bb)
|
||||
|
||||
// 查询是否已存在(唯一:sub_num + tel_num + month)
|
||||
var existing model.TaskBalance
|
||||
err = app.ModuleClients.TaskBenchDB.
|
||||
Where("sub_num = ? AND tel_num = ? AND month = ?", subNum, telNum, bb.Month).
|
||||
First(&existing).Error
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
// 不存在则创建
|
||||
return app.ModuleClients.TaskBenchDB.Create(&tb).Error
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 已存在则更新所有映射字段与时间
|
||||
tb.ID = existing.ID
|
||||
return app.ModuleClients.TaskBenchDB.Save(&tb).Error
|
||||
}
|
||||
|
||||
// fetchIdentityForBundle 根据 BundleBalance 拿到 sub_num 与 tel_num
|
||||
func fetchIdentityForBundle(bb *model.BundleBalance) (string, string, error) {
|
||||
// tel_num 来自 micro-account.user
|
||||
type userRow struct {
|
||||
Tel string `gorm:"column:tel_num"`
|
||||
}
|
||||
var ur userRow
|
||||
if err := app.ModuleClients.BundleDB.Table("`micro-account`.`user`").Unscoped().
|
||||
Select("tel_num").Where("id = ?", bb.UserId).First(&ur).Error; err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
// customer_num 来自 bundle_order_records(按 order_uuid)
|
||||
type orderRow struct {
|
||||
Customer string `gorm:"column:customer_num"`
|
||||
}
|
||||
var or orderRow
|
||||
if bb.OrderUUID == "" {
|
||||
return "", "", errors.New("bundle order_uuid missing")
|
||||
}
|
||||
if err := app.ModuleClients.BundleDB.Table("bundle_order_records").
|
||||
Select("customer_num").Where("uuid = ?", bb.OrderUUID).First(&or).Error; err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
return or.Customer, ur.Tel, nil
|
||||
}
|
||||
|
||||
// UpdateTaskBalance 每月批量更新任务余额
|
||||
// 类似于 UpdateBundleBalance 的逻辑,但针对任务余额表
|
||||
func UpdateTaskBalanceEveryMon() error {
|
||||
// 查询需要更新的任务余额记录(最新月份且未过期的记录)
|
||||
tl := []model.TaskBalance{}
|
||||
if err := app.ModuleClients.TaskBenchDB.Raw(`select
|
||||
*
|
||||
from
|
||||
task_balance tb
|
||||
inner join (
|
||||
select
|
||||
max(tb.month) as month ,
|
||||
sub_num,
|
||||
tel_num
|
||||
from
|
||||
task_balance tb
|
||||
group by
|
||||
tb.sub_num, tb.tel_num
|
||||
) newest on
|
||||
newest.month = tb.month
|
||||
and (tb.sub_num = newest.sub_num OR tb.tel_num = newest.tel_num)
|
||||
and tb.expired_at > now()`).Find(&tl).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
month := time.Now().Format("2006-01")
|
||||
|
||||
for _, v := range tl {
|
||||
if v.Month == month {
|
||||
continue
|
||||
}
|
||||
|
||||
// 计算本月发放的限制类型数量(与套餐余额一致)
|
||||
cal := func(total, limit int) int {
|
||||
var released int // 已释放的次数
|
||||
if v.StartAt.Month() == now.Month() && v.StartAt.Year() == now.Year() {
|
||||
// 本月为第一个月,不计算之前的释放
|
||||
} else if v.StartAt.Day() >= 16 { // 第一个月释放的(向上取整一半)
|
||||
released += (limit + 1) / 2
|
||||
} else {
|
||||
released += limit
|
||||
}
|
||||
interval := now.Year()*12 + int(now.Month()) - (v.StartAt.Year()*12 + int(v.StartAt.Month())) // 后续月份释放的
|
||||
released += interval * limit
|
||||
remaining := max(total-released, 0) // 还剩余多少次没有发放
|
||||
|
||||
if v.StartAt.Month() == now.Month() && v.StartAt.Year() == now.Year() && v.StartAt.Day() >= 16 { // 本月为第一个月并且16号后购买只给一半(向上取整)
|
||||
return min((limit+1)/2, remaining)
|
||||
}
|
||||
if v.ExpiredAt.Month() == now.Month() && v.ExpiredAt.Year() == now.Year() && v.ExpiredAt.Day() < 16 { // 本月为最后一个月并且16号前到期只给一半(向下取整)
|
||||
return min(limit/2, remaining)
|
||||
}
|
||||
return min(limit, remaining)
|
||||
}
|
||||
|
||||
// ===== 处理视频类过期数据 =====
|
||||
v.TaskMonthlyInvalidBundleVideoNumber = v.TaskMonthlyLimitVideoExpireNumber - v.TaskMonthlyLimitVideoExpireConsumptionNumber
|
||||
v.TaskInvalidBundleVideoNumber += v.TaskMonthlyInvalidBundleVideoNumber
|
||||
|
||||
// ===== 处理图片类过期数据 =====
|
||||
v.TaskMonthlyInvalidBundleImageNumber = v.TaskMonthlyLimitImageExpireNumber - v.TaskMonthlyLimitImageExpireConsumptionNumber
|
||||
v.TaskInvalidBundleImageNumber += v.TaskMonthlyInvalidBundleImageNumber
|
||||
|
||||
// ===== 处理数据分析类过期数据 =====
|
||||
v.TaskMonthlyInvalidBundleDataAnalysisNumber = v.TaskMonthlyLimitDataAnalysisExpireNumber - v.TaskMonthlyLimitDataAnalysisExpireConsumptionNumber
|
||||
v.TaskInvalidBundleDataAnalysisNumber += v.TaskMonthlyInvalidBundleDataAnalysisNumber
|
||||
|
||||
// ===== 计算新月份的可用数量 =====
|
||||
// 视频类
|
||||
v.TaskMonthlyLimitVideoExpireNumber = cal(v.TaskBundleLimitVideoExpiredNumber, v.TaskMonthlyLimitVideoQuotaNumber) + cal(v.TaskIncreaseLimitVideoExpiredNumber, v.TaskMonthlyLimitVideoQuotaNumber)
|
||||
v.TaskMonthlyLimitVideoNumber = v.TaskMonthlyLimitVideoNumber - v.TaskMonthlyLimitVideoConsumptionNumber + cal(v.TaskBundleLimitVideoNumber, v.TaskMonthlyLimitVideoQuotaNumber) + cal(v.TaskIncreaseLimitVideoNumber, v.TaskMonthlyLimitVideoQuotaNumber)
|
||||
|
||||
// 图片类
|
||||
v.TaskMonthlyLimitImageExpireNumber = cal(v.TaskBundleLimitImageExpiredNumber, v.TaskMonthlyLimitImageQuotaNumber) + cal(v.TaskIncreaseLimitImageExpiredNumber, v.TaskMonthlyLimitImageQuotaNumber)
|
||||
v.TaskMonthlyLimitImageNumber = v.TaskMonthlyLimitImageNumber - v.TaskMonthlyLimitImageConsumptionNumber + cal(v.TaskBundleLimitImageNumber, v.TaskMonthlyLimitImageQuotaNumber) + cal(v.TaskIncreaseLimitImageNumber, v.TaskMonthlyLimitImageQuotaNumber)
|
||||
|
||||
// 数据分析类
|
||||
v.TaskMonthlyLimitDataAnalysisExpireNumber = cal(v.TaskBundleLimitDataAnalysisExpiredNumber, v.TaskMonthlyLimitDataAnalysisQuotaNumber) + cal(v.TaskIncreaseLimitDataAnalysisExpiredNumber, v.TaskMonthlyLimitDataAnalysisQuotaNumber)
|
||||
v.TaskMonthlyLimitDataAnalysisNumber = v.TaskMonthlyLimitDataAnalysisNumber - v.TaskMonthlyLimitDataAnalysisConsumptionNumber + cal(v.TaskBundleLimitDataAnalysisNumber, v.TaskMonthlyLimitDataAnalysisQuotaNumber) + cal(v.TaskIncreaseLimitDataAnalysisNumber, v.TaskMonthlyLimitDataAnalysisQuotaNumber)
|
||||
|
||||
// ===== 重置月度消耗数量 =====
|
||||
// 视频类月度消耗重置
|
||||
v.TaskMonthlyLimitVideoConsumptionNumber = 0
|
||||
v.TaskMonthlyLimitVideoExpireConsumptionNumber = 0
|
||||
v.TaskMonthlyManualVideoConsumptionNumber = 0
|
||||
v.TaskMonthlyBundleVideoConsumptionNumber = 0
|
||||
v.TaskMonthlyIncreaseVideoConsumptionNumber = 0
|
||||
|
||||
// 图片类月度消耗重置
|
||||
v.TaskMonthlyLimitImageConsumptionNumber = 0
|
||||
v.TaskMonthlyLimitImageExpireConsumptionNumber = 0
|
||||
v.TaskMonthlyManualImageConsumptionNumber = 0
|
||||
v.TaskMonthlyBundleImageConsumptionNumber = 0
|
||||
v.TaskMonthlyIncreaseImageConsumptionNumber = 0
|
||||
|
||||
// 数据分析类月度消耗重置
|
||||
v.TaskMonthlyLimitDataAnalysisConsumptionNumber = 0
|
||||
v.TaskMonthlyLimitDataAnalysisExpireConsumptionNumber = 0
|
||||
v.TaskMonthlyManualDataAnalysisConsumptionNumber = 0
|
||||
v.TaskMonthlyBundleDataAnalysisConsumptionNumber = 0
|
||||
v.TaskMonthlyIncreaseDataAnalysisConsumptionNumber = 0
|
||||
|
||||
// 设置新月份和重置ID
|
||||
v.Month = month
|
||||
v.ID = 0
|
||||
|
||||
// 创建新的任务余额记录
|
||||
if err := app.ModuleClients.TaskBenchDB.Create(&v).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// updateTaskBalanceExpiredAt 更新任务余额表的ExpiredAt字段
|
||||
func updateTaskBalanceExpiredAt(subNum, telNum string, durationNumber int) error {
|
||||
return app.ModuleClients.TaskBenchDB.Transaction(func(tx *gorm.DB) error {
|
||||
var taskBalance model.TaskBalance
|
||||
query := tx.Model(&model.TaskBalance{})
|
||||
|
||||
// 构建查询条件,优先使用 subNum
|
||||
if subNum != "" {
|
||||
query = query.Where("sub_num = ?", subNum)
|
||||
} else {
|
||||
query = query.Where("tel_num = ?", telNum)
|
||||
}
|
||||
|
||||
// 查询当前有效的任务余额记录,按最新的开始时间排序
|
||||
now := time.Now()
|
||||
err := query.Where("start_at <= ? AND expired_at >= ?", now, now).Order("start_at DESC").First(&taskBalance).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 增加过期时间
|
||||
taskBalance.ExpiredAt = taskBalance.ExpiredAt.Add(time.Hour * 24 * time.Duration(durationNumber))
|
||||
|
||||
return tx.Save(&taskBalance).Error
|
||||
})
|
||||
}
|
||||
|
||||
// copyBundleToTaskBalance 将 BundleBalance 的图片、视频、数据分析相关字段映射到 TaskBalance
|
||||
func copyBundleToTaskBalance(tb *model.TaskBalance, bb *model.BundleBalance) {
|
||||
// ===== 视频类 =====
|
||||
tb.TaskBundleVideoNumber = bb.BundleVideoNumber
|
||||
tb.TaskIncreaseVideoNumber = bb.IncreaseVideoNumber
|
||||
tb.TaskBundleLimitVideoNumber = bb.BundleLimitVideoNumber
|
||||
tb.TaskIncreaseLimitVideoNumber = bb.IncreaseLimitVideoNumber
|
||||
tb.TaskBundleLimitVideoExpiredNumber = bb.BundleLimitVideoExpiredNumber
|
||||
tb.TaskIncreaseLimitVideoExpiredNumber = bb.IncreaseLimitVideoExpiredNumber
|
||||
tb.TaskMonthlyInvalidBundleVideoNumber = bb.MonthlyInvalidBundleVideoNumber
|
||||
tb.TaskInvalidBundleVideoNumber = bb.InvalidBundleVideoNumber
|
||||
tb.TaskMonthlyInvalidIncreaseVideoNumber = bb.MonthlyInvalidIncreaseVideoNumber
|
||||
tb.TaskInvalidIncreaseVideoNumber = bb.InvalidIncreaseVideoNumber
|
||||
tb.TaskBundleVideoConsumptionNumber = bb.BundleVideoConsumptionNumber
|
||||
tb.TaskIncreaseVideoConsumptionNumber = bb.IncreaseVideoConsumptionNumber
|
||||
tb.TaskBundleLimitVideoConsumptionNumber = bb.BundleLimitVideoConsumptionNumber
|
||||
tb.TaskIncreaseLimitVideoConsumptionNumber = bb.IncreaseLimitVideoConsumptionNumber
|
||||
tb.TaskBundleLimitVideoExpiredConsumptionNumber = bb.BundleLimitVideoExpiredConsumptionNumber
|
||||
tb.TaskIncreaseLimitVideoExpiredConsumptionNumber = bb.IncreaseLimitVideoExpiredConsumptionNumber
|
||||
tb.TaskMonthlyLimitVideoNumber = bb.MonthlyLimitVideoNumber
|
||||
tb.TaskMonthlyLimitVideoConsumptionNumber = bb.MonthlyLimitVideoConsumptionNumber
|
||||
tb.TaskMonthlyLimitVideoExpireNumber = bb.MonthlyLimitVideoExpireNumber
|
||||
tb.TaskMonthlyLimitVideoExpireConsumptionNumber = bb.MonthlyLimitVideoExpireConsumptionNumber
|
||||
tb.TaskMonthlyBundleVideoConsumptionNumber = bb.MonthlyBundleVideoConsumptionNumber
|
||||
tb.TaskMonthlyIncreaseVideoConsumptionNumber = bb.MonthlyIncreaseVideoConsumptionNumber
|
||||
tb.TaskMonthlyLimitVideoQuotaNumber = bb.MonthlyLimitVideoQuotaNumber
|
||||
|
||||
// ===== 图片类 =====
|
||||
tb.TaskBundleImageNumber = bb.BundleImageNumber
|
||||
tb.TaskIncreaseImageNumber = bb.IncreaseImageNumber
|
||||
tb.TaskBundleLimitImageNumber = bb.BundleLimitImageNumber
|
||||
tb.TaskIncreaseLimitImageNumber = bb.IncreaseLimitImageNumber
|
||||
tb.TaskBundleLimitImageExpiredNumber = bb.BundleLimitImageExpiredNumber
|
||||
tb.TaskIncreaseLimitImageExpiredNumber = bb.IncreaseLimitImageExpiredNumber
|
||||
tb.TaskMonthlyInvalidBundleImageNumber = bb.MonthlyInvalidBundleImageNumber
|
||||
tb.TaskInvalidBundleImageNumber = bb.InvalidBundleImageNumber
|
||||
tb.TaskMonthlyInvalidIncreaseImageNumber = bb.MonthlyInvalidIncreaseImageNumber
|
||||
tb.TaskInvalidIncreaseImageNumber = bb.InvalidIncreaseImageNumber
|
||||
tb.TaskBundleImageConsumptionNumber = bb.BundleImageConsumptionNumber
|
||||
tb.TaskIncreaseImageConsumptionNumber = bb.IncreaseImageConsumptionNumber
|
||||
tb.TaskBundleLimitImageConsumptionNumber = bb.BundleLimitImageConsumptionNumber
|
||||
tb.TaskIncreaseLimitImageConsumptionNumber = bb.IncreaseLimitImageConsumptionNumber
|
||||
tb.TaskBundleLimitImageExpiredConsumptionNumber = bb.BundleLimitImageExpiredConsumptionNumber
|
||||
tb.TaskIncreaseLimitImageExpiredConsumptionNumber = bb.IncreaseLimitImageExpiredConsumptionNumber
|
||||
tb.TaskMonthlyLimitImageNumber = bb.MonthlyLimitImageNumber
|
||||
tb.TaskMonthlyLimitImageConsumptionNumber = bb.MonthlyLimitImageConsumptionNumber
|
||||
tb.TaskMonthlyLimitImageExpireNumber = bb.MonthlyLimitImageExpireNumber
|
||||
tb.TaskMonthlyLimitImageExpireConsumptionNumber = bb.MonthlyLimitImageExpireConsumptionNumber
|
||||
tb.TaskMonthlyBundleImageConsumptionNumber = bb.MonthlyBundleImageConsumptionNumber
|
||||
tb.TaskMonthlyIncreaseImageConsumptionNumber = bb.MonthlyIncreaseImageConsumptionNumber
|
||||
tb.TaskMonthlyLimitImageQuotaNumber = bb.MonthlyLimitImageQuotaNumber
|
||||
|
||||
// ===== 数据分析类 =====
|
||||
tb.TaskBundleDataAnalysisNumber = bb.BundleDataAnalysisNumber
|
||||
tb.TaskIncreaseDataAnalysisNumber = bb.IncreaseDataAnalysisNumber
|
||||
tb.TaskBundleLimitDataAnalysisNumber = bb.BundleLimitDataAnalysisNumber
|
||||
tb.TaskIncreaseLimitDataAnalysisNumber = bb.IncreaseLimitDataAnalysisNumber
|
||||
tb.TaskBundleLimitDataAnalysisExpiredNumber = bb.BundleLimitDataAnalysisExpiredNumber
|
||||
tb.TaskIncreaseLimitDataAnalysisExpiredNumber = bb.IncreaseLimitDataAnalysisExpiredNumber
|
||||
tb.TaskMonthlyInvalidBundleDataAnalysisNumber = bb.MonthlyInvalidBundleDataAnalysisNumber
|
||||
tb.TaskInvalidBundleDataAnalysisNumber = bb.InvalidBundleDataAnalysisNumber
|
||||
tb.TaskMonthlyInvalidIncreaseDataAnalysisNumber = bb.MonthlyInvalidIncreaseDataAnalysisNumber
|
||||
tb.TaskInvalidIncreaseDataAnalysisNumber = bb.InvalidIncreaseDataAnalysisNumber
|
||||
tb.TaskBundleDataAnalysisConsumptionNumber = bb.BundleDataAnalysisConsumptionNumber
|
||||
tb.TaskIncreaseDataAnalysisConsumptionNumber = bb.IncreaseDataAnalysisConsumptionNumber
|
||||
tb.TaskBundleLimitDataAnalysisConsumptionNumber = bb.BundleLimitDataAnalysisConsumptionNumber
|
||||
tb.TaskIncreaseLimitDataAnalysisConsumptionNumber = bb.IncreaseLimitDataAnalysisConsumptionNumber
|
||||
tb.TaskBundleLimitDataAnalysisExpiredConsumptionNumber = bb.BundleLimitDataAnalysisExpiredConsumptionNumber
|
||||
tb.TaskIncreaseLimitDataAnalysisExpiredConsumptionNumber = bb.IncreaseLimitDataAnalysisExpiredConsumptionNumber
|
||||
tb.TaskMonthlyLimitDataAnalysisNumber = bb.MonthlyLimitDataAnalysisNumber
|
||||
tb.TaskMonthlyLimitDataAnalysisConsumptionNumber = bb.MonthlyLimitDataAnalysisConsumptionNumber
|
||||
tb.TaskMonthlyLimitDataAnalysisExpireNumber = bb.MonthlyLimitDataAnalysisExpireNumber
|
||||
tb.TaskMonthlyLimitDataAnalysisExpireConsumptionNumber = bb.MonthlyLimitDataAnalysisExpireConsumptionNumber
|
||||
tb.TaskMonthlyBundleDataAnalysisConsumptionNumber = bb.MonthlyBundleDataAnalysisConsumptionNumber
|
||||
tb.TaskMonthlyIncreaseDataAnalysisConsumptionNumber = bb.MonthlyIncreaseDataAnalysisConsumptionNumber
|
||||
tb.TaskMonthlyLimitDataAnalysisQuotaNumber = bb.MonthlyLimitDataAnalysisQuotaNumber
|
||||
}
|
||||
|
||||
func ExtendTaskBalanceByUserId(userId int, imageNumber int, dataAnalysisNumber int, videoNumber int, durationNumber int) error {
|
||||
// 根据用户ID获取其最新套餐记录,进而获取 sub_num、tel_num
|
||||
oldBundle := model.BundleBalance{}
|
||||
if err := app.ModuleClients.BundleDB.Model(&model.BundleBalance{}).
|
||||
Where("user_id = ?", userId).
|
||||
Order("created_at desc").
|
||||
First(&oldBundle).Error; err != nil {
|
||||
return errors.New("用户还没有套餐信息")
|
||||
}
|
||||
|
||||
subNum, telNum, err := fetchIdentityForBundle(&oldBundle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 事务更新当前有效的任务余额记录(按 start_at 最近的一条)
|
||||
err = app.ModuleClients.TaskBenchDB.Transaction(func(tx *gorm.DB) error {
|
||||
var tb model.TaskBalance
|
||||
now := time.Now()
|
||||
query := tx.Model(&model.TaskBalance{}).
|
||||
Where("sub_num = ? AND tel_num = ? AND start_at <= ? AND expired_at >= ?", subNum, telNum, now, now).
|
||||
Order("start_at DESC")
|
||||
|
||||
if err := query.First(&tb).Error; err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return errors.New("用户还没有任务余额信息")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 手动扩展额度与当月新增记录
|
||||
tb.TaskManualImageNumber += imageNumber
|
||||
tb.TaskMonthlyNewManualImageNumber += imageNumber
|
||||
|
||||
tb.TaskManualDataAnalysisNumber += dataAnalysisNumber
|
||||
tb.TaskMonthlyNewManualDataAnalysisNumber += dataAnalysisNumber
|
||||
|
||||
tb.TaskManualVideoNumber += videoNumber
|
||||
tb.TaskMonthlyNewManualVideoNumber += videoNumber
|
||||
|
||||
tb.TaskMonthlyNewDurationNumber += durationNumber
|
||||
|
||||
return tx.Model(&model.TaskBalance{}).Where("id = ?", tb.ID).Save(&tb).Error
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 增加过期时间(按天)
|
||||
if durationNumber > 0 {
|
||||
if err := updateTaskBalanceExpiredAt(subNum, telNum, durationNumber); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -43,6 +43,8 @@ type UpdatePendingCountRequest struct {
|
||||
PendingDataCount int `json:"pendingDataCount"` // 待发数据数量
|
||||
Operator string `json:"operator"` // 操作人
|
||||
OperatorNum string `json:"operatorNum"` // 操作人账号
|
||||
TaskAssignee string `json:"taskAssignee"` // 任务指派人
|
||||
TaskAssigneeNum string `json:"taskAssigneeNum"` // 任务指派人账号
|
||||
}
|
||||
|
||||
// EmployeeTaskQueryRequest 员工任务查询请求参数
|
||||
@ -614,6 +616,380 @@ func GetRemainingPendingBySubNum(subNum string) (*ArtistRemainingPendingResponse
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdatePendingCount 扣减任务余额(一次可同时扣减视频/图文/数据),遵循套餐扣减优先级
|
||||
func UpdatePendingCount(req *UpdatePendingCountRequest) error {
|
||||
// 参数校验
|
||||
if req.SubNum == "" {
|
||||
return commonErr.ReturnError(nil, "参数错误", "艺人编号不能为空")
|
||||
}
|
||||
if req.PendingVideoCount < 0 || req.PendingPostCount < 0 || req.PendingDataCount < 0 {
|
||||
return commonErr.ReturnError(nil, "参数错误", "扣减数量必须为非负")
|
||||
}
|
||||
|
||||
// 开启事务
|
||||
tx := app.ModuleClients.TaskBenchDB.Begin()
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
tx.Rollback()
|
||||
}
|
||||
}()
|
||||
|
||||
// 查询当前有效期内或最新一条任务余额
|
||||
now := time.Now()
|
||||
var tb model.TaskBalance
|
||||
{
|
||||
err := tx.Where("sub_num = ? AND start_at <= ? AND expired_at >= ?", req.SubNum, now, now).Order("start_at DESC").First(&tb).Error
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
err = tx.Where("sub_num = ?", req.SubNum).Order("start_at DESC").First(&tb).Error
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
tx.Rollback()
|
||||
return commonErr.ReturnError(nil, "余额不存在", "未找到任务余额记录")
|
||||
}
|
||||
tx.Rollback()
|
||||
return commonErr.ReturnError(err, "查询任务余额失败", "查询任务余额失败: ")
|
||||
}
|
||||
} else {
|
||||
tx.Rollback()
|
||||
return commonErr.ReturnError(err, "查询任务余额失败", "查询任务余额失败: ")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 先检查各类型是否有足够的总体余额(包含套餐、增值、手动)
|
||||
bundleVideo, bundleImage, bundleData := calculateBundleBalances(&tb)
|
||||
increaseVideo, increaseImage, increaseData := calculateIncreaseBalances(&tb)
|
||||
manualVideo := tb.TaskManualVideoNumber - tb.TaskManualVideoConsumptionNumber
|
||||
manualImage := tb.TaskManualImageNumber - tb.TaskManualImageConsumptionNumber
|
||||
manualData := tb.TaskManualDataAnalysisNumber - tb.TaskManualDataAnalysisConsumptionNumber
|
||||
|
||||
if req.PendingVideoCount > bundleVideo+increaseVideo+manualVideo {
|
||||
tx.Rollback()
|
||||
return commonErr.ReturnError(nil, "可用视频数不足", "扣减视频数量超过当前余额")
|
||||
}
|
||||
if req.PendingPostCount > bundleImage+increaseImage+manualImage {
|
||||
tx.Rollback()
|
||||
return commonErr.ReturnError(nil, "可用图文数不足", "扣减图文数量超过当前余额")
|
||||
}
|
||||
if req.PendingDataCount > bundleData+increaseData+manualData {
|
||||
tx.Rollback()
|
||||
return commonErr.ReturnError(nil, "可用数据分析数不足", "扣减数据分析数量超过当前余额")
|
||||
}
|
||||
|
||||
// 扣减视频:优先 会过期限制(套餐→增值) → 不过期限制(套餐→增值) → 非限制套餐 → 非限制增值 → 手动
|
||||
need := req.PendingVideoCount
|
||||
if need > 0 {
|
||||
// 限制会过期 - 套餐
|
||||
if need > 0 {
|
||||
limitRemain := tb.TaskMonthlyLimitVideoExpireNumber - tb.TaskMonthlyLimitVideoExpireConsumptionNumber
|
||||
totalRemain := tb.TaskBundleLimitVideoExpiredNumber - tb.TaskBundleLimitVideoExpiredConsumptionNumber
|
||||
alloc := minInt(need, minInt(limitRemain, totalRemain))
|
||||
if alloc > 0 {
|
||||
tb.TaskBundleLimitVideoExpiredConsumptionNumber += alloc
|
||||
tb.TaskMonthlyLimitVideoExpireConsumptionNumber += alloc
|
||||
tb.TaskMonthlyBundleVideoConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 限制会过期 - 增值
|
||||
if need > 0 {
|
||||
limitRemain := tb.TaskMonthlyLimitVideoExpireNumber - tb.TaskMonthlyLimitVideoExpireConsumptionNumber
|
||||
totalRemain := tb.TaskIncreaseLimitVideoExpiredNumber - tb.TaskIncreaseLimitVideoExpiredConsumptionNumber
|
||||
alloc := minInt(need, minInt(limitRemain, totalRemain))
|
||||
if alloc > 0 {
|
||||
tb.TaskIncreaseLimitVideoExpiredConsumptionNumber += alloc
|
||||
tb.TaskMonthlyLimitVideoExpireConsumptionNumber += alloc
|
||||
tb.TaskMonthlyIncreaseVideoConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 限制不过期 - 套餐
|
||||
if need > 0 {
|
||||
limitRemain := tb.TaskMonthlyLimitVideoNumber - tb.TaskMonthlyLimitVideoConsumptionNumber
|
||||
totalRemain := tb.TaskBundleLimitVideoNumber - tb.TaskBundleLimitVideoConsumptionNumber
|
||||
alloc := minInt(need, minInt(limitRemain, totalRemain))
|
||||
if alloc > 0 {
|
||||
tb.TaskBundleLimitVideoConsumptionNumber += alloc
|
||||
tb.TaskMonthlyLimitVideoConsumptionNumber += alloc
|
||||
tb.TaskMonthlyBundleVideoConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 限制不过期 - 增值
|
||||
if need > 0 {
|
||||
limitRemain := tb.TaskMonthlyLimitVideoNumber - tb.TaskMonthlyLimitVideoConsumptionNumber
|
||||
totalRemain := tb.TaskIncreaseLimitVideoNumber - tb.TaskIncreaseLimitVideoConsumptionNumber
|
||||
alloc := minInt(need, minInt(limitRemain, totalRemain))
|
||||
if alloc > 0 {
|
||||
tb.TaskIncreaseLimitVideoConsumptionNumber += alloc
|
||||
tb.TaskMonthlyLimitVideoConsumptionNumber += alloc
|
||||
tb.TaskMonthlyIncreaseVideoConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 非限制 - 套餐
|
||||
if need > 0 {
|
||||
totalRemain := tb.TaskBundleVideoNumber - tb.TaskBundleVideoConsumptionNumber
|
||||
alloc := minInt(need, totalRemain)
|
||||
if alloc > 0 {
|
||||
tb.TaskBundleVideoConsumptionNumber += alloc
|
||||
tb.TaskMonthlyBundleVideoConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 非限制 - 增值
|
||||
if need > 0 {
|
||||
totalRemain := tb.TaskIncreaseVideoNumber - tb.TaskIncreaseVideoConsumptionNumber
|
||||
alloc := minInt(need, totalRemain)
|
||||
if alloc > 0 {
|
||||
tb.TaskIncreaseVideoConsumptionNumber += alloc
|
||||
tb.TaskMonthlyIncreaseVideoConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 手动扩展
|
||||
if need > 0 {
|
||||
totalRemain := tb.TaskManualVideoNumber - tb.TaskManualVideoConsumptionNumber
|
||||
alloc := minInt(need, totalRemain)
|
||||
if alloc > 0 {
|
||||
tb.TaskManualVideoConsumptionNumber += alloc
|
||||
tb.TaskMonthlyManualVideoConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
if need > 0 {
|
||||
tx.Rollback()
|
||||
return commonErr.ReturnError(nil, "可用视频数不足", "扣减视频数量超过当前余额或当月限额")
|
||||
}
|
||||
}
|
||||
|
||||
// 扣减图文
|
||||
need = req.PendingPostCount
|
||||
if need > 0 {
|
||||
// 限制会过期 - 套餐
|
||||
if need > 0 {
|
||||
limitRemain := tb.TaskMonthlyLimitImageExpireNumber - tb.TaskMonthlyLimitImageExpireConsumptionNumber
|
||||
totalRemain := tb.TaskBundleLimitImageExpiredNumber - tb.TaskBundleLimitImageExpiredConsumptionNumber
|
||||
alloc := minInt(need, minInt(limitRemain, totalRemain))
|
||||
if alloc > 0 {
|
||||
tb.TaskBundleLimitImageExpiredConsumptionNumber += alloc
|
||||
tb.TaskMonthlyLimitImageExpireConsumptionNumber += alloc
|
||||
tb.TaskMonthlyBundleImageConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 限制会过期 - 增值
|
||||
if need > 0 {
|
||||
limitRemain := tb.TaskMonthlyLimitImageExpireNumber - tb.TaskMonthlyLimitImageExpireConsumptionNumber
|
||||
totalRemain := tb.TaskIncreaseLimitImageExpiredNumber - tb.TaskIncreaseLimitImageExpiredConsumptionNumber
|
||||
alloc := minInt(need, minInt(limitRemain, totalRemain))
|
||||
if alloc > 0 {
|
||||
tb.TaskIncreaseLimitImageExpiredConsumptionNumber += alloc
|
||||
tb.TaskMonthlyLimitImageExpireConsumptionNumber += alloc
|
||||
tb.TaskMonthlyIncreaseImageConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 限制不过期 - 套餐
|
||||
if need > 0 {
|
||||
limitRemain := tb.TaskMonthlyLimitImageNumber - tb.TaskMonthlyLimitImageConsumptionNumber
|
||||
totalRemain := tb.TaskBundleLimitImageNumber - tb.TaskBundleLimitImageConsumptionNumber
|
||||
alloc := minInt(need, minInt(limitRemain, totalRemain))
|
||||
if alloc > 0 {
|
||||
tb.TaskBundleLimitImageConsumptionNumber += alloc
|
||||
tb.TaskMonthlyLimitImageConsumptionNumber += alloc
|
||||
tb.TaskMonthlyBundleImageConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 限制不过期 - 增值
|
||||
if need > 0 {
|
||||
limitRemain := tb.TaskMonthlyLimitImageNumber - tb.TaskMonthlyLimitImageConsumptionNumber
|
||||
totalRemain := tb.TaskIncreaseLimitImageNumber - tb.TaskIncreaseLimitImageConsumptionNumber
|
||||
alloc := minInt(need, minInt(limitRemain, totalRemain))
|
||||
if alloc > 0 {
|
||||
tb.TaskIncreaseLimitImageConsumptionNumber += alloc
|
||||
tb.TaskMonthlyLimitImageConsumptionNumber += alloc
|
||||
tb.TaskMonthlyIncreaseImageConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 非限制 - 套餐
|
||||
if need > 0 {
|
||||
totalRemain := tb.TaskBundleImageNumber - tb.TaskBundleImageConsumptionNumber
|
||||
alloc := minInt(need, totalRemain)
|
||||
if alloc > 0 {
|
||||
tb.TaskBundleImageConsumptionNumber += alloc
|
||||
tb.TaskMonthlyBundleImageConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 非限制 - 增值
|
||||
if need > 0 {
|
||||
totalRemain := tb.TaskIncreaseImageNumber - tb.TaskIncreaseImageConsumptionNumber
|
||||
alloc := minInt(need, totalRemain)
|
||||
if alloc > 0 {
|
||||
tb.TaskIncreaseImageConsumptionNumber += alloc
|
||||
tb.TaskMonthlyIncreaseImageConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 手动扩展
|
||||
if need > 0 {
|
||||
totalRemain := tb.TaskManualImageNumber - tb.TaskManualImageConsumptionNumber
|
||||
alloc := minInt(need, totalRemain)
|
||||
if alloc > 0 {
|
||||
tb.TaskManualImageConsumptionNumber += alloc
|
||||
tb.TaskMonthlyManualImageConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
if need > 0 {
|
||||
tx.Rollback()
|
||||
return commonErr.ReturnError(nil, "可用图文数不足", "扣减图文数量超过当前余额或当月限额")
|
||||
}
|
||||
}
|
||||
|
||||
// 扣减数据分析
|
||||
need = req.PendingDataCount
|
||||
if need > 0 {
|
||||
// 限制会过期 - 套餐
|
||||
if need > 0 {
|
||||
limitRemain := tb.TaskMonthlyLimitDataAnalysisExpireNumber - tb.TaskMonthlyLimitDataAnalysisExpireConsumptionNumber
|
||||
totalRemain := tb.TaskBundleLimitDataAnalysisExpiredNumber - tb.TaskBundleLimitDataAnalysisExpiredConsumptionNumber
|
||||
alloc := minInt(need, minInt(limitRemain, totalRemain))
|
||||
if alloc > 0 {
|
||||
tb.TaskBundleLimitDataAnalysisExpiredConsumptionNumber += alloc
|
||||
tb.TaskMonthlyLimitDataAnalysisExpireConsumptionNumber += alloc
|
||||
tb.TaskMonthlyBundleDataAnalysisConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 限制会过期 - 增值
|
||||
if need > 0 {
|
||||
limitRemain := tb.TaskMonthlyLimitDataAnalysisExpireNumber - tb.TaskMonthlyLimitDataAnalysisExpireConsumptionNumber
|
||||
totalRemain := tb.TaskIncreaseLimitDataAnalysisExpiredNumber - tb.TaskIncreaseLimitDataAnalysisExpiredConsumptionNumber
|
||||
alloc := minInt(need, minInt(limitRemain, totalRemain))
|
||||
if alloc > 0 {
|
||||
tb.TaskIncreaseLimitDataAnalysisExpiredConsumptionNumber += alloc
|
||||
tb.TaskMonthlyLimitDataAnalysisExpireConsumptionNumber += alloc
|
||||
tb.TaskMonthlyIncreaseDataAnalysisConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 限制不过期 - 套餐
|
||||
if need > 0 {
|
||||
limitRemain := tb.TaskMonthlyLimitDataAnalysisNumber - tb.TaskMonthlyLimitDataAnalysisConsumptionNumber
|
||||
totalRemain := tb.TaskBundleLimitDataAnalysisNumber - tb.TaskBundleLimitDataAnalysisConsumptionNumber
|
||||
alloc := minInt(need, minInt(limitRemain, totalRemain))
|
||||
if alloc > 0 {
|
||||
tb.TaskBundleLimitDataAnalysisConsumptionNumber += alloc
|
||||
tb.TaskMonthlyLimitDataAnalysisConsumptionNumber += alloc
|
||||
tb.TaskMonthlyBundleDataAnalysisConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 限制不过期 - 增值
|
||||
if need > 0 {
|
||||
limitRemain := tb.TaskMonthlyLimitDataAnalysisNumber - tb.TaskMonthlyLimitDataAnalysisConsumptionNumber
|
||||
totalRemain := tb.TaskIncreaseLimitDataAnalysisNumber - tb.TaskIncreaseLimitDataAnalysisConsumptionNumber
|
||||
alloc := minInt(need, minInt(limitRemain, totalRemain))
|
||||
if alloc > 0 {
|
||||
tb.TaskIncreaseLimitDataAnalysisConsumptionNumber += alloc
|
||||
tb.TaskMonthlyLimitDataAnalysisConsumptionNumber += alloc
|
||||
tb.TaskMonthlyIncreaseDataAnalysisConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 非限制 - 套餐
|
||||
if need > 0 {
|
||||
totalRemain := tb.TaskBundleDataAnalysisNumber - tb.TaskBundleDataAnalysisConsumptionNumber
|
||||
alloc := minInt(need, totalRemain)
|
||||
if alloc > 0 {
|
||||
tb.TaskBundleDataAnalysisConsumptionNumber += alloc
|
||||
tb.TaskMonthlyBundleDataAnalysisConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 非限制 - 增值
|
||||
if need > 0 {
|
||||
totalRemain := tb.TaskIncreaseDataAnalysisNumber - tb.TaskIncreaseDataAnalysisConsumptionNumber
|
||||
alloc := minInt(need, totalRemain)
|
||||
if alloc > 0 {
|
||||
tb.TaskIncreaseDataAnalysisConsumptionNumber += alloc
|
||||
tb.TaskMonthlyIncreaseDataAnalysisConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
// 手动扩展
|
||||
if need > 0 {
|
||||
totalRemain := tb.TaskManualDataAnalysisNumber - tb.TaskManualDataAnalysisConsumptionNumber
|
||||
alloc := minInt(need, totalRemain)
|
||||
if alloc > 0 {
|
||||
tb.TaskManualDataAnalysisConsumptionNumber += alloc
|
||||
tb.TaskMonthlyManualDataAnalysisConsumptionNumber += alloc
|
||||
need -= alloc
|
||||
}
|
||||
}
|
||||
if need > 0 {
|
||||
tx.Rollback()
|
||||
return commonErr.ReturnError(nil, "可用数据分析数不足", "扣减数据分析数量超过当前余额或当月限额")
|
||||
}
|
||||
}
|
||||
|
||||
// 保存余额
|
||||
if err := tx.Model(&model.TaskBalance{}).Where("id = ?", tb.ID).Save(&tb).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return commonErr.ReturnError(err, "更新任务余额失败", "更新任务余额失败: ")
|
||||
}
|
||||
|
||||
// 写入操作日志(修改待发数量)
|
||||
assignRecord := &model.TaskAssignRecords{
|
||||
AssignRecordsUUID: uuid.New().String(),
|
||||
SubNum: req.SubNum,
|
||||
TelNum: req.TelNum,
|
||||
ArtistName: req.ArtistName,
|
||||
Status: 1,
|
||||
ActualStatus: 1,
|
||||
OperatorType: 2, // 2 是指派,现在把修改待发数量接口改成指派
|
||||
Operator: req.Operator,
|
||||
OperatorNum: req.OperatorNum,
|
||||
OperatorTime: time.Now(),
|
||||
TaskAssignee: req.TaskAssignee,
|
||||
TaskAssigneeNum: req.TaskAssigneeNum,
|
||||
PendingVideoCount: req.PendingVideoCount,
|
||||
PendingPostCount: req.PendingPostCount,
|
||||
PendingDataCount: req.PendingDataCount,
|
||||
AssignVideoCount: 0,
|
||||
AssignPostCount: 0,
|
||||
AssignDataCount: 0,
|
||||
CompleteVideoCount: 0,
|
||||
CompletePostCount: 0,
|
||||
CompleteDataCount: 0,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
if err := tx.Create(assignRecord).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return commonErr.ReturnError(err, "记录任务操作日志失败", "创建修改待发数量记录失败: ")
|
||||
}
|
||||
|
||||
// 提交事务
|
||||
if err := tx.Commit().Error; err != nil {
|
||||
return commonErr.ReturnError(err, "提交事务失败", "提交事务失败: ")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// minInt 返回两个整数的最小值
|
||||
func minInt(a, b int) int {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// GetAssignRecordByUUID 根据UUID查询指派记录
|
||||
func GetAssignRecordByUUID(uuid string) (*model.TaskAssignRecords, error) {
|
||||
var record model.TaskAssignRecords
|
||||
|
@ -1,7 +1,6 @@
|
||||
package logic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"micro-bundle/internal/dao"
|
||||
commonErr "micro-bundle/pkg/err"
|
||||
"sort"
|
||||
@ -221,17 +220,14 @@ func UpdatePendingCount(req *dao.UpdatePendingCountRequest) error {
|
||||
return commonErr.ReturnError(nil, "艺人套餐已过期", "该艺人没有有效的套餐,无法修改待发数量")
|
||||
}
|
||||
|
||||
// 查询艺人当前任务余额,校验余额的总和是否足够
|
||||
resp, err := dao.GetRemainingPendingBySubNum(req.SubNum)
|
||||
// 查询艺人当前任务余额,校验是否存在记录(不做数量比较,避免排除手动余额)
|
||||
_, err = dao.GetRemainingPendingBySubNum(req.SubNum)
|
||||
if err != nil {
|
||||
return commonErr.ReturnError(err, "查询艺人任务余额失败", "查询艺人任务余额失败: ")
|
||||
}
|
||||
|
||||
fmt.Println(resp)
|
||||
|
||||
// 2. 调用DAO层更新待发数量
|
||||
// return dao.UpdatePendingCount(req)
|
||||
return nil
|
||||
// 2. 调用DAO层更新待发数量(DAO 内部已做充足的额度与当月限额校验)
|
||||
return dao.UpdatePendingCount(req)
|
||||
}
|
||||
|
||||
// GetRecentAssignRecords 查询最近被指派记录
|
||||
@ -384,3 +380,7 @@ func calculatePendingFromTaskBalance(subNum string) (videoTotal, imageTotal, dat
|
||||
|
||||
return videoTotal, imageTotal, dataTotal
|
||||
}
|
||||
|
||||
func UpdateTaskBalanceEveryMonLogic() {
|
||||
dao.UpdateTaskBalanceEveryMon()
|
||||
}
|
||||
|
@ -93,6 +93,11 @@ type TaskBalance struct {
|
||||
TaskMonthlyIncreaseVideoConsumptionNumber int `gorm:"column:task_monthly_increase_video_consumption_number;not null;comment:任务当月增值类型总使用数" json:"taskMonthlyIncreaseVideoConsumptionNumber"`
|
||||
TaskMonthlyLimitVideoQuotaNumber int `gorm:"column:task_monthly_limit_video_quota_number;not null;comment:任务当月限制类型视频额度" json:"taskMonthlyLimitVideoQuotaNumber"`
|
||||
|
||||
TaskManualVideoNumber int `gorm:"column:task_manual_video_number;comment:手动扩展视频总数"`
|
||||
TaskManualVideoConsumptionNumber int `gorm:"column:task_manual_video_consumption_number;comment:手动扩展视频使用数"`
|
||||
TaskMonthlyNewManualVideoNumber int `gorm:"column:task_monthly_new_manual_video_number;comment:当月手动扩展视频新增数"`
|
||||
TaskMonthlyManualVideoConsumptionNumber int `gorm:"column:task_monthly_manual_video_consumption_number;comment:当月手动扩展视频使用数"`
|
||||
|
||||
// ===== 任务图片类 =====
|
||||
TaskBundleImageNumber int `gorm:"column:task_bundle_image_number;not null;comment:任务非限制类型套餐权益图片总数" json:"taskBundleImageNumber"`
|
||||
TaskIncreaseImageNumber int `gorm:"column:task_increase_image_number;not null;comment:任务非限制类型增值权益图片总数" json:"taskIncreaseImageNumber"`
|
||||
@ -118,6 +123,11 @@ type TaskBalance struct {
|
||||
TaskMonthlyIncreaseImageConsumptionNumber int `gorm:"column:task_monthly_increase_image_consumption_number;not null;comment:任务当月增值类型总使用数" json:"taskMonthlyIncreaseImageConsumptionNumber"`
|
||||
TaskMonthlyLimitImageQuotaNumber int `gorm:"column:task_monthly_limit_image_quota_number;not null;comment:任务当月限制类型图片额度" json:"taskMonthlyLimitImageQuotaNumber"`
|
||||
|
||||
TaskManualImageNumber int `gorm:"column:task_manual_image_number;comment:手动扩展图片总数"`
|
||||
TaskManualImageConsumptionNumber int `gorm:"column:task_manual_image_consumption_number;comment:手动扩展图片使用数"`
|
||||
TaskMonthlyNewManualImageNumber int `gorm:"column:task_monthly_new_manual_image_number;comment:当月手动扩展图片新增数"`
|
||||
TaskMonthlyManualImageConsumptionNumber int `gorm:"column:task_monthly_manual_image_consumption_number;comment:当月手动扩展图片使用数"`
|
||||
|
||||
// ===== 任务数据分析类 =====
|
||||
TaskBundleDataAnalysisNumber int `gorm:"column:task_bundle_data_analysis_number;not null;comment:任务非限制类型套餐权益数据分析总数" json:"taskBundleDataAnalysisNumber"`
|
||||
TaskIncreaseDataAnalysisNumber int `gorm:"column:task_increase_data_analysis_number;not null;comment:任务非限制类型增值权益数据分析总数" json:"taskIncreaseDataAnalysisNumber"`
|
||||
@ -143,6 +153,14 @@ type TaskBalance struct {
|
||||
TaskMonthlyIncreaseDataAnalysisConsumptionNumber int `gorm:"column:task_monthly_increase_data_analysis_consumption_number;not null;comment:任务当月增值类型总使用数" json:"taskMonthlyIncreaseDataAnalysisConsumptionNumber"`
|
||||
TaskMonthlyLimitDataAnalysisQuotaNumber int `gorm:"column:task_monthly_limit_data_analysis_quota_number;not null;comment:任务当月限制类型数据分析额度" json:"taskMonthlyLimitDataAnalysisQuotaNumber"`
|
||||
|
||||
TaskManualDataAnalysisNumber int `gorm:"column:task_manual_data_analysis_number;comment:手动扩展数据分析总数"`
|
||||
TaskManualDataAnalysisConsumptionNumber int `gorm:"column:task_manual_data_analysis_consumption_number;comment:手动扩展数据分析使用数"`
|
||||
TaskMonthlyNewManualDataAnalysisNumber int `gorm:"column:task_monthly_new_manual_data_analysis_number;comment:当月手动扩展数据分析新增数"`
|
||||
TaskMonthlyManualDataAnalysisConsumptionNumber int `gorm:"column:task_monthly_manual_data_analysis_consumption_number;comment:当月手动扩展数据分析使用数"`
|
||||
|
||||
TaskMonthlyNewDurationNumber int `gorm:"column:task_monthly_new_duration_number;comment:当月新增手动扩展时长(天)"`
|
||||
TaskExpansionPacksNumber int `gorm:"column:task_expansion_packs_number;not null;comment:扩展包数量"`
|
||||
|
||||
CreatedAt time.Time `gorm:"column:created_at;comment:创建时间" json:"createdAt"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at;comment:更新时间" json:"updatedAt"`
|
||||
DeletedAt soft_delete.DeletedAt `gorm:"column:deleted_at;type:int(11);index:idx_task_balance_deleted_at" json:"deletedAt"`
|
||||
@ -152,6 +170,20 @@ func (t *TaskBalance) TableName() string {
|
||||
return "task_balance"
|
||||
}
|
||||
|
||||
// TaskSyncStatus 用于标记一次性任务余额同步是否已经执行
|
||||
// 记录键唯一,避免重复执行
|
||||
type TaskSyncStatus struct {
|
||||
ID int64 `gorm:"primarykey"`
|
||||
SyncKey string `gorm:"column:sync_key;type:varchar(100);uniqueIndex;not null"`
|
||||
ExecutedAt time.Time `gorm:"column:executed_at;type:datetime;not null"`
|
||||
Remark string `gorm:"column:remark;type:varchar(255)"`
|
||||
}
|
||||
|
||||
func (TaskSyncStatus) TableName() string { return "task_sync_status" }
|
||||
|
||||
// InitialSyncKey 一次性同步的唯一标识键
|
||||
const InitialSyncKey = "bundle_to_task_balance_initial_sync"
|
||||
|
||||
// 任务日志表
|
||||
type TaskLog struct {
|
||||
LogUUID string `gorm:"column:log_uuid;type:varchar(50);comment:任务日志UUID;not null" json:"taskLogUUID"`
|
||||
|
@ -948,6 +948,8 @@ message UpdatePendingCountRequest {
|
||||
int32 pendingDataCount = 6 [json_name = "pendingDataCount"]; // 待发数据数量
|
||||
string operator = 7 [json_name = "operator"]; // 操作人
|
||||
string operatorNum = 8 [json_name = "operatorNum"]; // 操作人账号
|
||||
string taskAssignee = 9 [json_name = "taskAssignee"]; // 任务指派人
|
||||
string taskAssigneeNum = 10 [json_name = "taskAssigneeNum"]; // 任务指派人账号
|
||||
}
|
||||
|
||||
// 查询最近被指派记录
|
||||
|
File diff suppressed because it is too large
Load Diff
37
pkg/cron/cron.go
Normal file
37
pkg/cron/cron.go
Normal file
@ -0,0 +1,37 @@
|
||||
package cron
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"micro-bundle/internal/logic"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
)
|
||||
|
||||
func InitCronJob() {
|
||||
c := cron.New(cron.WithSeconds())
|
||||
|
||||
spec := "0 0 0 1 * *"
|
||||
|
||||
_, err := c.AddFunc(spec, func() {
|
||||
log.Printf("执行余量每月数据更新")
|
||||
// logic.UpdateBundleBalance()
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// 避免冲突,任务余额每月更新定时任务 - 每月1号1点执行
|
||||
taskBalanceSpec := "0 0 1 1 * *"
|
||||
_, err = c.AddFunc(taskBalanceSpec, func() {
|
||||
log.Printf("执行任务余额每月数据更新")
|
||||
logic.UpdateTaskBalanceEveryMonLogic()
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("添加任务余额每月数据更新定时任务失败", err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Start()
|
||||
|
||||
}
|
@ -105,6 +105,7 @@ func loadTaskBenchMysqlConn(conn string) *gorm.DB {
|
||||
&model.TaskAssignRecords{},
|
||||
&model.TaskBalance{},
|
||||
&model.TaskLog{},
|
||||
&model.TaskSyncStatus{},
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user