diff --git a/model/main.go b/model/main.go index c286d64f..0c460bda 100644 --- a/model/main.go +++ b/model/main.go @@ -288,6 +288,7 @@ func migrateDB() error { &ChannelMonitor{}, &ChannelMonitorHistory{}, &ChannelMonitorDailyRollup{}, + &RebateRecord{}, ) if err != nil { return err @@ -344,6 +345,7 @@ func migrateDBFast() error { {&ChannelMonitor{}, "ChannelMonitor"}, {&ChannelMonitorHistory{}, "ChannelMonitorHistory"}, {&ChannelMonitorDailyRollup{}, "ChannelMonitorDailyRollup"}, + {&RebateRecord{}, "RebateRecord"}, } // 动态计算migration数量,确保errChan缓冲区足够大 errChan := make(chan error, len(migrations)) diff --git a/model/option.go b/model/option.go index e0a3048d..a534c11c 100644 --- a/model/option.go +++ b/model/option.go @@ -19,6 +19,12 @@ type Option struct { Value string `json:"value"` } +const ( + AffRebateRatePercentKey = "AffRebateRatePercent" + AffRebateFrozenDaysKey = "AffRebateFrozenDays" + AffRebateEnabledKey = "AffRebateEnabled" +) + func AllOption() ([]*Option, error) { var options []*Option var err error @@ -135,6 +141,9 @@ func InitOptionMap() { common.OptionMap["QuotaForNewUser"] = strconv.Itoa(common.QuotaForNewUser) common.OptionMap["QuotaForInviter"] = strconv.Itoa(common.QuotaForInviter) common.OptionMap["QuotaForInvitee"] = strconv.Itoa(common.QuotaForInvitee) + common.OptionMap[AffRebateRatePercentKey] = "0" + common.OptionMap[AffRebateFrozenDaysKey] = "0" + common.OptionMap[AffRebateEnabledKey] = strconv.FormatBool(false) common.OptionMap["QuotaRemindThreshold"] = strconv.Itoa(common.QuotaRemindThreshold) common.OptionMap["PreConsumedQuota"] = strconv.Itoa(common.PreConsumedQuota) common.OptionMap["ModelRequestRateLimitCount"] = strconv.Itoa(setting.ModelRequestRateLimitCount) diff --git a/model/rebate_record.go b/model/rebate_record.go new file mode 100644 index 00000000..97902ff9 --- /dev/null +++ b/model/rebate_record.go @@ -0,0 +1,61 @@ +package model + +import "time" + +type RebateRecord struct { + Id int `json:"id" gorm:"primaryKey;autoIncrement"` + InviterId int `json:"inviter_id" gorm:"index;not null"` + InviteeId int `json:"invitee_id" gorm:"index;not null"` + OrderId int `json:"order_id" gorm:"index"` + OrderType string `json:"order_type" gorm:"type:varchar(16);not null"` + OrderAmount int `json:"order_amount" gorm:"not null"` + RebateAmount int `json:"rebate_amount" gorm:"not null"` + RatePercent int `json:"rate_percent" gorm:"not null"` + Status string `json:"status" gorm:"type:varchar(16);not null;default:'frozen';index"` + FrozenUntil *time.Time `json:"frozen_until" gorm:"index"` + ReleasedAt *time.Time `json:"released_at"` + CreatedAt time.Time `json:"created_at"` +} + +func (RebateRecord) TableName() string { + return "rebate_records" +} + +func (r *RebateRecord) Insert() error { + return DB.Create(r).Error +} + +func (r *RebateRecord) Update() error { + return DB.Save(r).Error +} + +func GetFrozenRebatesDue() ([]RebateRecord, error) { + var records []RebateRecord + err := DB.Where("status = ? AND frozen_until IS NOT NULL AND frozen_until <= ?", "frozen", time.Now()). + Order("id ASC"). + Find(&records).Error + return records, err +} + +func GetRebateRecords(page int, pageSize int, status string, userId int) ([]RebateRecord, int64, error) { + var records []RebateRecord + var total int64 + query := DB.Model(&RebateRecord{}) + if status != "" { + query = query.Where("status = ?", status) + } + if userId > 0 { + query = query.Where("inviter_id = ? OR invitee_id = ?", userId, userId) + } + if err := query.Count(&total).Error; err != nil { + return nil, 0, err + } + if page < 1 { + page = 1 + } + if pageSize < 1 { + pageSize = 20 + } + err := query.Order("id DESC").Offset((page - 1) * pageSize).Limit(pageSize).Find(&records).Error + return records, total, err +} diff --git a/model/user.go b/model/user.go index 5079acaf..85c69f8d 100644 --- a/model/user.go +++ b/model/user.go @@ -22,37 +22,39 @@ const UserNameMaxLength = 20 // User if you add sensitive fields, don't forget to clean them in setupLogin function. // Otherwise, the sensitive information will be saved on local storage in plain text! type User struct { - Id int `json:"id"` - Username string `json:"username" gorm:"unique;index" validate:"max=20"` - Password string `json:"password" gorm:"not null;" validate:"min=8,max=20"` - OriginalPassword string `json:"original_password" gorm:"-:all"` // this field is only for Password change verification, don't save it to database! - DisplayName string `json:"display_name" gorm:"index" validate:"max=20"` - Role int `json:"role" gorm:"type:int;default:1"` // admin, common - Status int `json:"status" gorm:"type:int;default:1"` // enabled, disabled - Email string `json:"email" gorm:"index" validate:"max=50"` - GitHubId string `json:"github_id" gorm:"column:github_id;index"` - DiscordId string `json:"discord_id" gorm:"column:discord_id;index"` - OidcId string `json:"oidc_id" gorm:"column:oidc_id;index"` - WeChatId string `json:"wechat_id" gorm:"column:wechat_id;index"` - TelegramId string `json:"telegram_id" gorm:"column:telegram_id;index"` - VerificationCode string `json:"verification_code" gorm:"-:all"` // this field is only for Email verification, don't save it to database! - AccessToken *string `json:"access_token" gorm:"type:char(32);column:access_token;uniqueIndex"` // this token is for system management - Quota int `json:"quota" gorm:"type:int;default:0"` - UsedQuota int `json:"used_quota" gorm:"type:int;default:0;column:used_quota"` // used quota - RequestCount int `json:"request_count" gorm:"type:int;default:0;"` // request number - Group string `json:"group" gorm:"type:varchar(64);default:'default'"` - AffCode string `json:"aff_code" gorm:"type:varchar(32);column:aff_code;uniqueIndex"` - AffCount int `json:"aff_count" gorm:"type:int;default:0;column:aff_count"` - AffQuota int `json:"aff_quota" gorm:"type:int;default:0;column:aff_quota"` // 邀请剩余额度 - AffHistoryQuota int `json:"aff_history_quota" gorm:"type:int;default:0;column:aff_history"` // 邀请历史额度 - InviterId int `json:"inviter_id" gorm:"type:int;column:inviter_id;index"` - DeletedAt gorm.DeletedAt `gorm:"index"` - LinuxDOId string `json:"linux_do_id" gorm:"column:linux_do_id;index"` - Setting string `json:"setting" gorm:"type:text;column:setting"` - Remark string `json:"remark,omitempty" gorm:"type:varchar(255)" validate:"max=255"` - StripeCustomer string `json:"stripe_customer" gorm:"type:varchar(64);column:stripe_customer;index"` - CreatedAt int64 `json:"created_at" gorm:"autoCreateTime;column:created_at"` - LastLoginAt int64 `json:"last_login_at" gorm:"default:0;column:last_login_at"` + Id int `json:"id"` + Username string `json:"username" gorm:"unique;index" validate:"max=20"` + Password string `json:"password" gorm:"not null;" validate:"min=8,max=20"` + OriginalPassword string `json:"original_password" gorm:"-:all"` // this field is only for Password change verification, don't save it to database! + DisplayName string `json:"display_name" gorm:"index" validate:"max=20"` + Role int `json:"role" gorm:"type:int;default:1"` // admin, common + Status int `json:"status" gorm:"type:int;default:1"` // enabled, disabled + Email string `json:"email" gorm:"index" validate:"max=50"` + GitHubId string `json:"github_id" gorm:"column:github_id;index"` + DiscordId string `json:"discord_id" gorm:"column:discord_id;index"` + OidcId string `json:"oidc_id" gorm:"column:oidc_id;index"` + WeChatId string `json:"wechat_id" gorm:"column:wechat_id;index"` + TelegramId string `json:"telegram_id" gorm:"column:telegram_id;index"` + VerificationCode string `json:"verification_code" gorm:"-:all"` // this field is only for Email verification, don't save it to database! + AccessToken *string `json:"access_token" gorm:"type:char(32);column:access_token;uniqueIndex"` // this token is for system management + Quota int `json:"quota" gorm:"type:int;default:0"` + UsedQuota int `json:"used_quota" gorm:"type:int;default:0;column:used_quota"` // used quota + RequestCount int `json:"request_count" gorm:"type:int;default:0;"` // request number + Group string `json:"group" gorm:"type:varchar(64);default:'default'"` + AffCode string `json:"aff_code" gorm:"type:varchar(32);column:aff_code;uniqueIndex"` + AffCount int `json:"aff_count" gorm:"type:int;default:0;column:aff_count"` + AffQuota int `json:"aff_quota" gorm:"type:int;default:0;column:aff_quota"` // 邀请剩余额度 + AffHistoryQuota int `json:"aff_history_quota" gorm:"type:int;default:0;column:aff_history"` // 邀请历史额度 + AffRebateRatePercent int `json:"aff_rebate_rate_percent" gorm:"type:int;default:0"` + AffRebateFrozenDays int `json:"aff_rebate_frozen_days" gorm:"type:int;default:0"` + InviterId int `json:"inviter_id" gorm:"type:int;column:inviter_id;index"` + DeletedAt gorm.DeletedAt `gorm:"index"` + LinuxDOId string `json:"linux_do_id" gorm:"column:linux_do_id;index"` + Setting string `json:"setting" gorm:"type:text;column:setting"` + Remark string `json:"remark,omitempty" gorm:"type:varchar(255)" validate:"max=255"` + StripeCustomer string `json:"stripe_customer" gorm:"type:varchar(64);column:stripe_customer;index"` + CreatedAt int64 `json:"created_at" gorm:"autoCreateTime;column:created_at"` + LastLoginAt int64 `json:"last_login_at" gorm:"default:0;column:last_login_at"` } func (user *User) ToBaseUser() *UserBase {