Files
hi-server/internal/model/promo/default.go
T

240 lines
6.7 KiB
Go

package promo
import (
"context"
"errors"
"fmt"
"github.com/perfect-panel/server/pkg/cache"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
)
const (
cachePromoRuleIdPrefix = "cache:promo_rule:id:"
cacheSubscribePromoIdPrefix = "cache:subscribe_promo:id:"
)
type Model interface {
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, page, size int, ruleType string, enabled *bool, search string) (int64, []*Rule, error)
UpsertPrices(ctx context.Context, ruleId int64, items []*SubscribePromo) error
FindPrice(ctx context.Context, id int64) (*SubscribePromo, error)
DeletePrice(ctx context.Context, id int64) error
QueryPriceList(ctx context.Context, ruleId int64, page, size int) (int64, []*SubscribePromo, error)
QueryUsageList(ctx context.Context, params UsageFilter) (int64, []*Usage, error)
Transaction(ctx context.Context, fn func(db *gorm.DB) error) error
}
type UsageFilter struct {
Page int
Size int
RuleId int64
UserId int64
SubscribeId int64
OrderNo string
}
type customPromoModel struct {
cache.CachedConn
table string
}
func NewModel(db *gorm.DB, c *redis.Client) Model {
return &customPromoModel{
CachedConn: cache.NewConn(db, c),
table: "`promo_rule`",
}
}
func (m *customPromoModel) ruleCacheKey(id int64) string {
return fmt.Sprintf("%s%d", cachePromoRuleIdPrefix, id)
}
func (m *customPromoModel) priceCacheKey(id int64) string {
return fmt.Sprintf("%s%d", cacheSubscribePromoIdPrefix, id)
}
func (m *customPromoModel) InsertRule(ctx context.Context, data *Rule) error {
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
return conn.Create(data).Error
}, m.ruleCacheKey(data.Id))
}
func (m *customPromoModel) FindRule(ctx context.Context, id int64) (*Rule, error) {
var resp Rule
err := m.QueryCtx(ctx, &resp, m.ruleCacheKey(id), func(conn *gorm.DB, v interface{}) error {
return conn.Model(&Rule{}).Where("id = ?", id).First(v).Error
})
if err != nil {
return nil, err
}
return &resp, nil
}
func (m *customPromoModel) UpdateRule(ctx context.Context, data *Rule) error {
old, err := m.FindRule(ctx, data.Id)
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
keys := []string{m.ruleCacheKey(data.Id)}
if old != nil {
keys = append(keys, m.ruleCacheKey(old.Id))
}
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
return conn.Save(data).Error
}, keys...)
}
func (m *customPromoModel) DeleteRule(ctx context.Context, id int64) error {
data, err := m.FindRule(ctx, id)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil
}
return err
}
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
return conn.Delete(&Rule{}, id).Error
}, m.ruleCacheKey(data.Id))
}
func (m *customPromoModel) QueryRuleList(ctx context.Context, page, size int, ruleType string, enabled *bool, search string) (int64, []*Rule, error) {
if page <= 0 {
page = 1
}
if size <= 0 {
size = 10
}
var total int64
var list []*Rule
err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error {
db := conn.Model(&Rule{})
if ruleType != "" {
db = db.Where("type = ?", ruleType)
}
if enabled != nil {
db = db.Where("enabled = ?", *enabled)
}
if search != "" {
db = db.Where("name LIKE ?", "%"+search+"%")
}
if err := db.Count(&total).Error; err != nil {
return err
}
return db.Order("priority DESC").Order("id DESC").Limit(size).Offset((page - 1) * size).Find(v).Error
})
return total, list, err
}
func (m *customPromoModel) UpsertPrices(ctx context.Context, ruleId int64, items []*SubscribePromo) error {
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
for _, item := range items {
if item == nil {
continue
}
item.PromoRuleId = ruleId
var existing SubscribePromo
err := conn.Model(&SubscribePromo{}).
Where("subscribe_id = ? AND quantity = ? AND promo_rule_id = ?", item.SubscribeId, item.Quantity, ruleId).
First(&existing).Error
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
if errors.Is(err, gorm.ErrRecordNotFound) {
if err := conn.Create(item).Error; err != nil {
return err
}
continue
}
existing.Quantity = item.Quantity
existing.PromoPrice = item.PromoPrice
if err := conn.Save(&existing).Error; err != nil {
return err
}
}
return nil
})
}
func (m *customPromoModel) FindPrice(ctx context.Context, id int64) (*SubscribePromo, error) {
var resp SubscribePromo
err := m.QueryCtx(ctx, &resp, m.priceCacheKey(id), func(conn *gorm.DB, v interface{}) error {
return conn.Model(&SubscribePromo{}).Where("id = ?", id).First(v).Error
})
if err != nil {
return nil, err
}
return &resp, nil
}
func (m *customPromoModel) DeletePrice(ctx context.Context, id int64) error {
data, err := m.FindPrice(ctx, id)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil
}
return err
}
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
return conn.Delete(&SubscribePromo{}, id).Error
}, m.priceCacheKey(data.Id))
}
func (m *customPromoModel) QueryPriceList(ctx context.Context, ruleId int64, page, size int) (int64, []*SubscribePromo, error) {
if page <= 0 {
page = 1
}
if size <= 0 {
size = 10
}
var total int64
var list []*SubscribePromo
err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error {
db := conn.Model(&SubscribePromo{}).Where("promo_rule_id = ?", ruleId)
if err := db.Count(&total).Error; err != nil {
return err
}
return db.Order("id DESC").Limit(size).Offset((page - 1) * size).Find(v).Error
})
return total, list, err
}
func (m *customPromoModel) QueryUsageList(ctx context.Context, params UsageFilter) (int64, []*Usage, error) {
if params.Page <= 0 {
params.Page = 1
}
if params.Size <= 0 {
params.Size = 10
}
var total int64
var list []*Usage
err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error {
db := conn.Model(&Usage{})
if params.RuleId > 0 {
db = db.Where("promo_rule_id = ?", params.RuleId)
}
if params.UserId > 0 {
db = db.Where("user_id = ?", params.UserId)
}
if params.SubscribeId > 0 {
db = db.Where("subscribe_id = ?", params.SubscribeId)
}
if params.OrderNo != "" {
db = db.Where("order_no = ?", params.OrderNo)
}
if err := db.Count(&total).Error; err != nil {
return err
}
return db.Order("id DESC").Limit(params.Size).Offset((params.Page - 1) * params.Size).Find(v).Error
})
return total, list, err
}
func (m *customPromoModel) Transaction(ctx context.Context, fn func(db *gorm.DB) error) error {
return m.TransactCtx(ctx, fn)
}