Files
hi-server/internal/model/promo/model.go
T
2026-05-26 22:49:46 -07:00

219 lines
6.2 KiB
Go

package promo
import (
"context"
"errors"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type RuleWithPrice struct {
Rule
PromoPrice int64 `gorm:"column:promo_price"`
}
type RuleFilter struct {
Page int
Size int
Type string
Enabled *bool
Search string
}
type SubscribePromoFilter struct {
Page int
Size int
PromoRuleId int64
}
type UsageFilter struct {
Page int
Size int
PromoRuleId int64
UserId int64
SubscribeId int64
OrderNo string
}
type Model interface {
QueryEligibleRules(ctx context.Context, subscribeId int64) ([]*RuleWithPrice, error)
InsertUsage(ctx context.Context, data *Usage, tx ...*gorm.DB) error
InsertRule(ctx context.Context, data *Rule) error
FindRule(ctx context.Context, id int64) (*Rule, error)
UpdateRule(ctx context.Context, data *Rule) error
DeleteRule(ctx context.Context, id int64) error
QueryRuleList(ctx context.Context, filter RuleFilter) (int64, []*Rule, error)
UpsertSubscribePromos(ctx context.Context, data []*SubscribePromo) error
FindSubscribePromo(ctx context.Context, id int64) (*SubscribePromo, error)
DeleteSubscribePromo(ctx context.Context, id int64) error
QuerySubscribePromoList(ctx context.Context, filter SubscribePromoFilter) (int64, []*SubscribePromo, error)
QueryUsageList(ctx context.Context, filter UsageFilter) (int64, []*Usage, error)
}
type defaultPromoModel struct {
db *gorm.DB
}
func NewModel(db *gorm.DB, _ *redis.Client) Model {
return &defaultPromoModel{db: db}
}
func normalizePage(page, size int) (int, int) {
if page <= 0 {
page = 1
}
if size <= 0 {
size = 10
}
if size > 100 {
size = 100
}
return page, size
}
func (m *defaultPromoModel) QueryEligibleRules(ctx context.Context, subscribeId int64) ([]*RuleWithPrice, error) {
var list []*RuleWithPrice
err := m.db.WithContext(ctx).
Table("promo_rule AS pr").
Select("pr.*, sp.promo_price").
Joins("JOIN subscribe_promo AS sp ON sp.promo_rule_id = pr.id").
Where("sp.subscribe_id = ? AND sp.promo_price > 0 AND pr.enabled = ?", subscribeId, true).
Where("pr.deleted_at IS NULL").
Order("pr.priority DESC").
Order("pr.id ASC").
Find(&list).Error
return list, err
}
func (m *defaultPromoModel) InsertUsage(ctx context.Context, data *Usage, tx ...*gorm.DB) error {
db := m.db.WithContext(ctx)
if len(tx) > 0 {
db = tx[0].WithContext(ctx)
}
return db.Model(&Usage{}).Create(data).Error
}
func (m *defaultPromoModel) InsertRule(ctx context.Context, data *Rule) error {
return m.db.WithContext(ctx).Create(data).Error
}
func (m *defaultPromoModel) FindRule(ctx context.Context, id int64) (*Rule, error) {
var data Rule
err := m.db.WithContext(ctx).Model(&Rule{}).Where("id = ?", id).First(&data).Error
return &data, err
}
func (m *defaultPromoModel) UpdateRule(ctx context.Context, data *Rule) error {
return m.db.WithContext(ctx).Save(data).Error
}
func (m *defaultPromoModel) DeleteRule(ctx context.Context, id int64) error {
result := m.db.WithContext(ctx).Delete(&Rule{}, id)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return gorm.ErrRecordNotFound
}
return nil
}
func (m *defaultPromoModel) QueryRuleList(ctx context.Context, filter RuleFilter) (int64, []*Rule, error) {
page, size := normalizePage(filter.Page, filter.Size)
var total int64
var list []*Rule
query := m.db.WithContext(ctx).Model(&Rule{})
if filter.Type != "" {
query = query.Where("type = ?", filter.Type)
}
if filter.Enabled != nil {
query = query.Where("enabled = ?", *filter.Enabled)
}
if filter.Search != "" {
search := "%" + filter.Search + "%"
query = query.Where("name LIKE ?", search)
}
if err := query.Count(&total).Error; err != nil {
return 0, nil, err
}
err := query.Order("priority DESC").Order("id DESC").
Limit(size).Offset((page - 1) * size).
Find(&list).Error
return total, list, err
}
func (m *defaultPromoModel) UpsertSubscribePromos(ctx context.Context, data []*SubscribePromo) error {
if len(data) == 0 {
return nil
}
return m.db.WithContext(ctx).Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "subscribe_id"}, {Name: "promo_rule_id"}},
DoUpdates: clause.AssignmentColumns([]string{"promo_price", "updated_at"}),
}).Create(&data).Error
}
func (m *defaultPromoModel) FindSubscribePromo(ctx context.Context, id int64) (*SubscribePromo, error) {
var data SubscribePromo
err := m.db.WithContext(ctx).Model(&SubscribePromo{}).Where("id = ?", id).First(&data).Error
return &data, err
}
func (m *defaultPromoModel) DeleteSubscribePromo(ctx context.Context, id int64) error {
result := m.db.WithContext(ctx).Delete(&SubscribePromo{}, id)
if result.Error != nil {
return result.Error
}
if result.RowsAffected == 0 {
return gorm.ErrRecordNotFound
}
return nil
}
func (m *defaultPromoModel) QuerySubscribePromoList(ctx context.Context, filter SubscribePromoFilter) (int64, []*SubscribePromo, error) {
page, size := normalizePage(filter.Page, filter.Size)
var total int64
var list []*SubscribePromo
query := m.db.WithContext(ctx).Model(&SubscribePromo{})
if filter.PromoRuleId > 0 {
query = query.Where("promo_rule_id = ?", filter.PromoRuleId)
}
if err := query.Count(&total).Error; err != nil {
return 0, nil, err
}
err := query.Order("id DESC").Limit(size).Offset((page - 1) * size).Find(&list).Error
return total, list, err
}
func (m *defaultPromoModel) QueryUsageList(ctx context.Context, filter UsageFilter) (int64, []*Usage, error) {
page, size := normalizePage(filter.Page, filter.Size)
var total int64
var list []*Usage
query := m.db.WithContext(ctx).Model(&Usage{})
if filter.PromoRuleId > 0 {
query = query.Where("promo_rule_id = ?", filter.PromoRuleId)
}
if filter.UserId > 0 {
query = query.Where("user_id = ?", filter.UserId)
}
if filter.SubscribeId > 0 {
query = query.Where("subscribe_id = ?", filter.SubscribeId)
}
if filter.OrderNo != "" {
query = query.Where("order_no LIKE ?", "%"+filter.OrderNo+"%")
}
if err := query.Count(&total).Error; err != nil {
return 0, nil, err
}
err := query.Order("id DESC").Limit(size).Offset((page - 1) * size).Find(&list).Error
return total, list, err
}
func IsNotFound(err error) bool {
return errors.Is(err, gorm.ErrRecordNotFound)
}