Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5fb396f880 |
+1
-1
@@ -149,7 +149,7 @@ type (
|
|||||||
ExpiredAt int64 `json:"expired_at"`
|
ExpiredAt int64 `json:"expired_at"`
|
||||||
Upload int64 `json:"upload"`
|
Upload int64 `json:"upload"`
|
||||||
Download int64 `json:"download"`
|
Download int64 `json:"download"`
|
||||||
SpeedLimit *int64 `json:"speed_limit,omitempty"`
|
SpeedLimit *int64 `json:"speed_limit,omitempty" validate:"omitempty,gte=0"`
|
||||||
TrafficLimit *string `json:"traffic_limit,omitempty"`
|
TrafficLimit *string `json:"traffic_limit,omitempty"`
|
||||||
}
|
}
|
||||||
GetUserLoginLogsRequest {
|
GetUserLoginLogsRequest {
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
ALTER TABLE `order`
|
|
||||||
DROP COLUMN IF EXISTS `promo_discount`,
|
|
||||||
DROP COLUMN IF EXISTS `promo_rule_id`;
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `promo_usage`;
|
|
||||||
DROP TABLE IF EXISTS `subscribe_promo`;
|
|
||||||
DROP TABLE IF EXISTS `promo_rule`;
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
CREATE TABLE IF NOT EXISTS `promo_rule` (
|
|
||||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
||||||
`name` VARCHAR(100) NOT NULL DEFAULT '' COMMENT '规则名称,如"新客7天优惠"',
|
|
||||||
`type` VARCHAR(32) NOT NULL DEFAULT '' COMMENT '规则类型:new_user / inactive_user / campaign',
|
|
||||||
`params` JSON NOT NULL COMMENT '类型专属参数',
|
|
||||||
`priority` INT NOT NULL DEFAULT 0 COMMENT '优先级,数值越大越优先匹配',
|
|
||||||
`enabled` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
|
|
||||||
`start_time` DATETIME DEFAULT NULL COMMENT '生效开始时间,NULL=立即生效',
|
|
||||||
`end_time` DATETIME DEFAULT NULL COMMENT '生效结束时间,NULL=永不过期',
|
|
||||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
||||||
`deleted_at` DATETIME DEFAULT NULL COMMENT '软删除时间',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `idx_enabled_priority` (`enabled`, `priority` DESC)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='促销规则表';
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `subscribe_promo` (
|
|
||||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
||||||
`subscribe_id` BIGINT UNSIGNED NOT NULL COMMENT '套餐规格 ID',
|
|
||||||
`promo_rule_id` BIGINT UNSIGNED NOT NULL COMMENT '促销规则 ID',
|
|
||||||
`promo_price` BIGINT NOT NULL DEFAULT 0 COMMENT '该规格在此规则下的优惠价(分)',
|
|
||||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
UNIQUE KEY `uk_subscribe_rule` (`subscribe_id`, `promo_rule_id`),
|
|
||||||
KEY `idx_promo_rule_id` (`promo_rule_id`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='规格促销价表';
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `promo_usage` (
|
|
||||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
||||||
`user_id` BIGINT UNSIGNED NOT NULL COMMENT '用户 ID',
|
|
||||||
`promo_rule_id` BIGINT UNSIGNED NOT NULL COMMENT '使用的规则 ID',
|
|
||||||
`subscribe_id` BIGINT UNSIGNED NOT NULL COMMENT '购买的规格 ID',
|
|
||||||
`order_no` VARCHAR(255) NOT NULL DEFAULT '' COMMENT '关联订单号',
|
|
||||||
`promo_price` BIGINT NOT NULL DEFAULT 0 COMMENT '使用时的促销单价(分)',
|
|
||||||
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `idx_user_rule` (`user_id`, `promo_rule_id`),
|
|
||||||
KEY `idx_order_no` (`order_no`)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='促销使用记录表';
|
|
||||||
|
|
||||||
SET @promo_rule_id_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'order' AND COLUMN_NAME = 'promo_rule_id');
|
|
||||||
SET @promo_rule_id_sql = IF(@promo_rule_id_exists = 0, 'ALTER TABLE `order` ADD COLUMN `promo_rule_id` BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT ''促销规则ID, 0=未使用促销'' AFTER `discount`', 'SELECT 1');
|
|
||||||
PREPARE stmt FROM @promo_rule_id_sql;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
|
|
||||||
SET @promo_discount_exists = (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'order' AND COLUMN_NAME = 'promo_discount');
|
|
||||||
SET @promo_discount_sql = IF(@promo_discount_exists = 0, 'ALTER TABLE `order` ADD COLUMN `promo_discount` BIGINT NOT NULL DEFAULT 0 COMMENT ''促销优惠金额(分)'' AFTER `promo_rule_id`', 'SELECT 1');
|
|
||||||
PREPARE stmt FROM @promo_discount_sql;
|
|
||||||
EXECUTE stmt;
|
|
||||||
DEALLOCATE PREPARE stmt;
|
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
package user
|
package user
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/perfect-panel/server/internal/logic/admin/user"
|
"github.com/perfect-panel/server/internal/logic/admin/user"
|
||||||
"github.com/perfect-panel/server/internal/svc"
|
"github.com/perfect-panel/server/internal/svc"
|
||||||
@@ -18,9 +21,25 @@ func UpdateUserSubscribeHandler(svcCtx *svc.ServiceContext) func(c *gin.Context)
|
|||||||
result.ParamErrorResult(c, validateErr)
|
result.ParamErrorResult(c, validateErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if err := validateUpdateUserSubscribeTrafficLimit(&req); err != nil {
|
||||||
|
result.ParamErrorResult(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
l := user.NewUpdateUserSubscribeLogic(c.Request.Context(), svcCtx)
|
l := user.NewUpdateUserSubscribeLogic(c.Request.Context(), svcCtx)
|
||||||
err := l.UpdateUserSubscribe(&req)
|
err := l.UpdateUserSubscribe(&req)
|
||||||
result.HttpResult(c, nil, err)
|
result.HttpResult(c, nil, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateUpdateUserSubscribeTrafficLimit(req *types.UpdateUserSubscribeRequest) error {
|
||||||
|
if req.TrafficLimit == nil || *req.TrafficLimit == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var rules []types.TrafficLimit
|
||||||
|
if err := json.Unmarshal([]byte(*req.TrafficLimit), &rules); err != nil {
|
||||||
|
return errors.New("traffic_limit must be a valid JSON array")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/perfect-panel/server/internal/svc"
|
||||||
|
"github.com/perfect-panel/server/pkg/xerr"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUpdateUserSubscribeHandlerRejectsInvalidLimits(t *testing.T) {
|
||||||
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
body string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "negative speed limit",
|
||||||
|
body: `{"user_subscribe_id":1,"subscribe_id":1,"traffic":0,"expired_at":4102444800000,"upload":0,"download":0,"speed_limit":-1}`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid traffic limit json",
|
||||||
|
body: `{"user_subscribe_id":1,"subscribe_id":1,"traffic":0,"expired_at":4102444800000,"upload":0,"download":0,"traffic_limit":"not-json"}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
router := gin.New()
|
||||||
|
router.PUT("/v1/admin/user/subscribe", UpdateUserSubscribeHandler(&svc.ServiceContext{}))
|
||||||
|
|
||||||
|
req := httptest.NewRequest(http.MethodPut, "/v1/admin/user/subscribe", bytes.NewBufferString(tt.body))
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
rec := httptest.NewRecorder()
|
||||||
|
|
||||||
|
router.ServeHTTP(rec, req)
|
||||||
|
|
||||||
|
if rec.Code != http.StatusOK {
|
||||||
|
t.Fatalf("expected HTTP 200, got %d", rec.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
var resp struct {
|
||||||
|
Code uint32 `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
||||||
|
t.Fatalf("unmarshal response: %v", err)
|
||||||
|
}
|
||||||
|
if resp.Code != xerr.InvalidParams {
|
||||||
|
t.Fatalf("expected code %d, got %d (%s)", xerr.InvalidParams, resp.Code, resp.Msg)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,6 +39,14 @@ func (l *UpdateUserSubscribeLogic) UpdateUserSubscribe(req *types.UpdateUserSubs
|
|||||||
} else {
|
} else {
|
||||||
userSub.Status = 1
|
userSub.Status = 1
|
||||||
}
|
}
|
||||||
|
speedLimit := userSub.SpeedLimit
|
||||||
|
if req.SpeedLimit != nil {
|
||||||
|
speedLimit = *req.SpeedLimit
|
||||||
|
}
|
||||||
|
trafficLimit := userSub.TrafficLimit
|
||||||
|
if req.TrafficLimit != nil {
|
||||||
|
trafficLimit = *req.TrafficLimit
|
||||||
|
}
|
||||||
|
|
||||||
err = l.svcCtx.UserModel.UpdateSubscribe(l.ctx, &user.Subscribe{
|
err = l.svcCtx.UserModel.UpdateSubscribe(l.ctx, &user.Subscribe{
|
||||||
Id: userSub.Id,
|
Id: userSub.Id,
|
||||||
@@ -50,6 +58,8 @@ func (l *UpdateUserSubscribeLogic) UpdateUserSubscribe(req *types.UpdateUserSubs
|
|||||||
Traffic: req.Traffic,
|
Traffic: req.Traffic,
|
||||||
Download: req.Download,
|
Download: req.Download,
|
||||||
Upload: req.Upload,
|
Upload: req.Upload,
|
||||||
|
SpeedLimit: speedLimit,
|
||||||
|
TrafficLimit: trafficLimit,
|
||||||
Token: userSub.Token,
|
Token: userSub.Token,
|
||||||
UUID: userSub.UUID,
|
UUID: userSub.UUID,
|
||||||
Status: userSub.Status,
|
Status: userSub.Status,
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ type Details struct {
|
|||||||
Price int64 `gorm:"type:int;not null;default:0;comment:Original price"`
|
Price int64 `gorm:"type:int;not null;default:0;comment:Original price"`
|
||||||
Amount int64 `gorm:"type:int;not null;default:0;comment:Order Amount"`
|
Amount int64 `gorm:"type:int;not null;default:0;comment:Order Amount"`
|
||||||
Discount int64 `gorm:"type:int;not null;default:0;comment:Order Discount"`
|
Discount int64 `gorm:"type:int;not null;default:0;comment:Order Discount"`
|
||||||
PromoRuleID int64 `gorm:"type:bigint unsigned;not null;default:0;comment:Promo Rule ID, 0 means no promo"`
|
|
||||||
PromoDiscount int64 `gorm:"type:bigint;not null;default:0;comment:Promo Discount Amount"`
|
|
||||||
Coupon string `gorm:"type:varchar(255);default:null;comment:Coupon"`
|
Coupon string `gorm:"type:varchar(255);default:null;comment:Coupon"`
|
||||||
CouponDiscount int64 `gorm:"type:int;not null;default:0;comment:Coupon Discount"`
|
CouponDiscount int64 `gorm:"type:int;not null;default:0;comment:Coupon Discount"`
|
||||||
PaymentId int64 `gorm:"type:bigint;not null;default:0;comment:Payment Id"`
|
PaymentId int64 `gorm:"type:bigint;not null;default:0;comment:Payment Id"`
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ type Order struct {
|
|||||||
Amount int64 `gorm:"type:int;not null;default:0;comment:Order Amount"`
|
Amount int64 `gorm:"type:int;not null;default:0;comment:Order Amount"`
|
||||||
GiftAmount int64 `gorm:"type:int;not null;default:0;comment:User Gift Amount"`
|
GiftAmount int64 `gorm:"type:int;not null;default:0;comment:User Gift Amount"`
|
||||||
Discount int64 `gorm:"type:int;not null;default:0;comment:Discount Amount"`
|
Discount int64 `gorm:"type:int;not null;default:0;comment:Discount Amount"`
|
||||||
PromoRuleID int64 `gorm:"type:bigint unsigned;not null;default:0;comment:Promo Rule ID, 0 means no promo"`
|
|
||||||
PromoDiscount int64 `gorm:"type:bigint;not null;default:0;comment:Promo Discount Amount"`
|
|
||||||
Coupon string `gorm:"type:varchar(255);default:null;comment:Coupon"`
|
Coupon string `gorm:"type:varchar(255);default:null;comment:Coupon"`
|
||||||
CouponDiscount int64 `gorm:"type:int;not null;default:0;comment:Coupon Discount Amount"`
|
CouponDiscount int64 `gorm:"type:int;not null;default:0;comment:Coupon Discount Amount"`
|
||||||
Commission int64 `gorm:"type:int;not null;default:0;comment:Order Commission"`
|
Commission int64 `gorm:"type:int;not null;default:0;comment:Order Commission"`
|
||||||
|
|||||||
@@ -1,106 +0,0 @@
|
|||||||
package promo_rule
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/perfect-panel/server/pkg/cache"
|
|
||||||
"github.com/redis/go-redis/v9"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ Model = (*customPromoRuleModel)(nil)
|
|
||||||
|
|
||||||
var cachePromoRuleIdPrefix = "cache:promo_rule:id:"
|
|
||||||
|
|
||||||
type (
|
|
||||||
Model interface {
|
|
||||||
promoRuleModel
|
|
||||||
customPromoRuleLogicModel
|
|
||||||
}
|
|
||||||
|
|
||||||
promoRuleModel interface {
|
|
||||||
Insert(ctx context.Context, data *PromoRule, tx ...*gorm.DB) error
|
|
||||||
FindOne(ctx context.Context, id int64) (*PromoRule, error)
|
|
||||||
Update(ctx context.Context, data *PromoRule, tx ...*gorm.DB) error
|
|
||||||
Delete(ctx context.Context, id int64, tx ...*gorm.DB) error
|
|
||||||
Transaction(ctx context.Context, fn func(db *gorm.DB) error) error
|
|
||||||
}
|
|
||||||
|
|
||||||
customPromoRuleModel struct {
|
|
||||||
*defaultPromoRuleModel
|
|
||||||
}
|
|
||||||
defaultPromoRuleModel struct {
|
|
||||||
cache.CachedConn
|
|
||||||
table string
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func newPromoRuleModel(db *gorm.DB, c *redis.Client) *defaultPromoRuleModel {
|
|
||||||
return &defaultPromoRuleModel{
|
|
||||||
CachedConn: cache.NewConn(db, c),
|
|
||||||
table: "`promo_rule`",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultPromoRuleModel) getCacheKeys(data *PromoRule) []string {
|
|
||||||
if data == nil {
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
return []string{fmt.Sprintf("%s%v", cachePromoRuleIdPrefix, data.Id)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultPromoRuleModel) Insert(ctx context.Context, data *PromoRule, tx ...*gorm.DB) error {
|
|
||||||
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
|
|
||||||
if len(tx) > 0 {
|
|
||||||
conn = tx[0]
|
|
||||||
}
|
|
||||||
return conn.Create(data).Error
|
|
||||||
}, m.getCacheKeys(data)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultPromoRuleModel) FindOne(ctx context.Context, id int64) (*PromoRule, error) {
|
|
||||||
key := fmt.Sprintf("%s%v", cachePromoRuleIdPrefix, id)
|
|
||||||
var resp PromoRule
|
|
||||||
err := m.QueryCtx(ctx, &resp, key, func(conn *gorm.DB, v interface{}) error {
|
|
||||||
return conn.Model(&PromoRule{}).Where("`id` = ?", id).First(v).Error
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultPromoRuleModel) Update(ctx context.Context, data *PromoRule, tx ...*gorm.DB) error {
|
|
||||||
old, err := m.FindOne(ctx, data.Id)
|
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
|
|
||||||
if len(tx) > 0 {
|
|
||||||
conn = tx[0]
|
|
||||||
}
|
|
||||||
return conn.Save(data).Error
|
|
||||||
}, m.getCacheKeys(old)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultPromoRuleModel) Delete(ctx context.Context, id int64, tx ...*gorm.DB) error {
|
|
||||||
data, err := m.FindOne(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
|
|
||||||
if len(tx) > 0 {
|
|
||||||
conn = tx[0]
|
|
||||||
}
|
|
||||||
return conn.Delete(&PromoRule{}, id).Error
|
|
||||||
}, m.getCacheKeys(data)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultPromoRuleModel) Transaction(ctx context.Context, fn func(db *gorm.DB) error) error {
|
|
||||||
return m.TransactCtx(ctx, fn)
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package promo_rule
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/redis/go-redis/v9"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type customPromoRuleLogicModel interface {
|
|
||||||
QueryEnabledByPriority(ctx context.Context) ([]*PromoRule, error)
|
|
||||||
QueryAvailableByPriority(ctx context.Context, now time.Time) ([]*PromoRule, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewModel(conn *gorm.DB, c *redis.Client) Model {
|
|
||||||
return &customPromoRuleModel{
|
|
||||||
defaultPromoRuleModel: newPromoRuleModel(conn, c),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *customPromoRuleModel) QueryEnabledByPriority(ctx context.Context) ([]*PromoRule, error) {
|
|
||||||
var list []*PromoRule
|
|
||||||
err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error {
|
|
||||||
return conn.Model(&PromoRule{}).
|
|
||||||
Where("enabled = ?", true).
|
|
||||||
Order("priority DESC, id DESC").
|
|
||||||
Find(v).Error
|
|
||||||
})
|
|
||||||
return list, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *customPromoRuleModel) QueryAvailableByPriority(ctx context.Context, now time.Time) ([]*PromoRule, error) {
|
|
||||||
var list []*PromoRule
|
|
||||||
err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error {
|
|
||||||
return conn.Model(&PromoRule{}).
|
|
||||||
Where("enabled = ?", true).
|
|
||||||
Where("(start_time IS NULL OR start_time <= ?)", now).
|
|
||||||
Where("(end_time IS NULL OR end_time >= ?)", now).
|
|
||||||
Order("priority DESC, id DESC").
|
|
||||||
Find(v).Error
|
|
||||||
})
|
|
||||||
return list, err
|
|
||||||
}
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
package promo_rule
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql/driver"
|
|
||||||
"encoding/json"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type JSONRawMessage json.RawMessage
|
|
||||||
|
|
||||||
func (j *JSONRawMessage) Scan(value interface{}) error {
|
|
||||||
if value == nil {
|
|
||||||
*j = JSONRawMessage([]byte("{}"))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
switch v := value.(type) {
|
|
||||||
case []byte:
|
|
||||||
*j = JSONRawMessage(v)
|
|
||||||
case string:
|
|
||||||
*j = JSONRawMessage([]byte(v))
|
|
||||||
default:
|
|
||||||
*j = JSONRawMessage([]byte("{}"))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j JSONRawMessage) Value() (driver.Value, error) {
|
|
||||||
if len(j) == 0 {
|
|
||||||
return "{}", nil
|
|
||||||
}
|
|
||||||
data, err := json.RawMessage(j).MarshalJSON()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return string(data), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j JSONRawMessage) MarshalJSON() ([]byte, error) {
|
|
||||||
if len(j) == 0 {
|
|
||||||
return []byte("{}"), nil
|
|
||||||
}
|
|
||||||
return json.RawMessage(j).MarshalJSON()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j *JSONRawMessage) UnmarshalJSON(data []byte) error {
|
|
||||||
if len(data) == 0 {
|
|
||||||
*j = JSONRawMessage([]byte("{}"))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
*j = JSONRawMessage(data)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type PromoRule struct {
|
|
||||||
Id int64 `gorm:"type:bigint unsigned;primaryKey"`
|
|
||||||
Name string `gorm:"type:varchar(100);not null;default:'';comment:Rule Name"`
|
|
||||||
Type string `gorm:"type:varchar(32);not null;default:'';comment:Rule Type: new_user, inactive_user, campaign"`
|
|
||||||
Params JSONRawMessage `gorm:"type:json;not null;comment:Rule Params"`
|
|
||||||
Priority int64 `gorm:"type:int;not null;default:0;index:idx_enabled_priority,priority:2,sort:desc;comment:Priority"`
|
|
||||||
Enabled bool `gorm:"type:tinyint(1);not null;default:1;index:idx_enabled_priority,priority:1;comment:Enabled"`
|
|
||||||
StartTime *time.Time `gorm:"type:datetime;default:null;comment:Start Time"`
|
|
||||||
EndTime *time.Time `gorm:"type:datetime;default:null;comment:End Time"`
|
|
||||||
CreatedAt time.Time `gorm:"<-:create;comment:Create Time"`
|
|
||||||
UpdatedAt time.Time `gorm:"comment:Update Time"`
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"index;comment:Delete Time"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (PromoRule) TableName() string {
|
|
||||||
return "promo_rule"
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
package promo_usage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/perfect-panel/server/pkg/cache"
|
|
||||||
"github.com/redis/go-redis/v9"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ Model = (*customPromoUsageModel)(nil)
|
|
||||||
|
|
||||||
var cachePromoUsageIdPrefix = "cache:promo_usage:id:"
|
|
||||||
|
|
||||||
type (
|
|
||||||
Model interface {
|
|
||||||
promoUsageModel
|
|
||||||
customPromoUsageLogicModel
|
|
||||||
}
|
|
||||||
|
|
||||||
promoUsageModel interface {
|
|
||||||
Insert(ctx context.Context, data *PromoUsage, tx ...*gorm.DB) error
|
|
||||||
FindOne(ctx context.Context, id int64) (*PromoUsage, error)
|
|
||||||
Update(ctx context.Context, data *PromoUsage, tx ...*gorm.DB) error
|
|
||||||
Delete(ctx context.Context, id int64, tx ...*gorm.DB) error
|
|
||||||
Transaction(ctx context.Context, fn func(db *gorm.DB) error) error
|
|
||||||
}
|
|
||||||
|
|
||||||
customPromoUsageModel struct {
|
|
||||||
*defaultPromoUsageModel
|
|
||||||
}
|
|
||||||
defaultPromoUsageModel struct {
|
|
||||||
cache.CachedConn
|
|
||||||
table string
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func newPromoUsageModel(db *gorm.DB, c *redis.Client) *defaultPromoUsageModel {
|
|
||||||
return &defaultPromoUsageModel{
|
|
||||||
CachedConn: cache.NewConn(db, c),
|
|
||||||
table: "`promo_usage`",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultPromoUsageModel) getCacheKeys(data *PromoUsage) []string {
|
|
||||||
if data == nil {
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
return []string{fmt.Sprintf("%s%v", cachePromoUsageIdPrefix, data.Id)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultPromoUsageModel) Insert(ctx context.Context, data *PromoUsage, tx ...*gorm.DB) error {
|
|
||||||
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
|
|
||||||
if len(tx) > 0 {
|
|
||||||
conn = tx[0]
|
|
||||||
}
|
|
||||||
return conn.Create(data).Error
|
|
||||||
}, m.getCacheKeys(data)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultPromoUsageModel) FindOne(ctx context.Context, id int64) (*PromoUsage, error) {
|
|
||||||
key := fmt.Sprintf("%s%v", cachePromoUsageIdPrefix, id)
|
|
||||||
var resp PromoUsage
|
|
||||||
err := m.QueryCtx(ctx, &resp, key, func(conn *gorm.DB, v interface{}) error {
|
|
||||||
return conn.Model(&PromoUsage{}).Where("`id` = ?", id).First(v).Error
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultPromoUsageModel) Update(ctx context.Context, data *PromoUsage, tx ...*gorm.DB) error {
|
|
||||||
old, err := m.FindOne(ctx, data.Id)
|
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
|
|
||||||
if len(tx) > 0 {
|
|
||||||
conn = tx[0]
|
|
||||||
}
|
|
||||||
return conn.Save(data).Error
|
|
||||||
}, m.getCacheKeys(old)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultPromoUsageModel) Delete(ctx context.Context, id int64, tx ...*gorm.DB) error {
|
|
||||||
data, err := m.FindOne(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
|
|
||||||
if len(tx) > 0 {
|
|
||||||
conn = tx[0]
|
|
||||||
}
|
|
||||||
return conn.Delete(&PromoUsage{}, id).Error
|
|
||||||
}, m.getCacheKeys(data)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultPromoUsageModel) Transaction(ctx context.Context, fn func(db *gorm.DB) error) error {
|
|
||||||
return m.TransactCtx(ctx, fn)
|
|
||||||
}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
package promo_usage
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/redis/go-redis/v9"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type customPromoUsageLogicModel interface {
|
|
||||||
FindByOrderNo(ctx context.Context, orderNo string) ([]*PromoUsage, error)
|
|
||||||
FindByUserAndRule(ctx context.Context, userId, promoRuleId int64) ([]*PromoUsage, error)
|
|
||||||
QueryListByPage(ctx context.Context, page, size int, userId, promoRuleId, subscribeId int64) (int64, []*PromoUsage, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewModel(conn *gorm.DB, c *redis.Client) Model {
|
|
||||||
return &customPromoUsageModel{
|
|
||||||
defaultPromoUsageModel: newPromoUsageModel(conn, c),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *customPromoUsageModel) FindByOrderNo(ctx context.Context, orderNo string) ([]*PromoUsage, error) {
|
|
||||||
var list []*PromoUsage
|
|
||||||
err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error {
|
|
||||||
return conn.Model(&PromoUsage{}).
|
|
||||||
Where("order_no = ?", orderNo).
|
|
||||||
Order("id DESC").
|
|
||||||
Find(v).Error
|
|
||||||
})
|
|
||||||
return list, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *customPromoUsageModel) FindByUserAndRule(ctx context.Context, userId, promoRuleId int64) ([]*PromoUsage, error) {
|
|
||||||
var list []*PromoUsage
|
|
||||||
err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error {
|
|
||||||
return conn.Model(&PromoUsage{}).
|
|
||||||
Where("user_id = ? AND promo_rule_id = ?", userId, promoRuleId).
|
|
||||||
Order("id DESC").
|
|
||||||
Find(v).Error
|
|
||||||
})
|
|
||||||
return list, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *customPromoUsageModel) QueryListByPage(ctx context.Context, page, size int, userId, promoRuleId, subscribeId int64) (int64, []*PromoUsage, error) {
|
|
||||||
var list []*PromoUsage
|
|
||||||
var total int64
|
|
||||||
if page <= 0 {
|
|
||||||
page = 1
|
|
||||||
}
|
|
||||||
if size <= 0 {
|
|
||||||
size = 20
|
|
||||||
}
|
|
||||||
|
|
||||||
err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error {
|
|
||||||
db := conn.Model(&PromoUsage{})
|
|
||||||
if userId > 0 {
|
|
||||||
db = db.Where("user_id = ?", userId)
|
|
||||||
}
|
|
||||||
if promoRuleId > 0 {
|
|
||||||
db = db.Where("promo_rule_id = ?", promoRuleId)
|
|
||||||
}
|
|
||||||
if subscribeId > 0 {
|
|
||||||
db = db.Where("subscribe_id = ?", subscribeId)
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package promo_usage
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type PromoUsage struct {
|
|
||||||
Id int64 `gorm:"type:bigint unsigned;primaryKey"`
|
|
||||||
UserId int64 `gorm:"type:bigint unsigned;not null;index:idx_user_rule,priority:1;comment:User Id"`
|
|
||||||
PromoRuleId int64 `gorm:"type:bigint unsigned;not null;index:idx_user_rule,priority:2;comment:Promo Rule Id"`
|
|
||||||
SubscribeId int64 `gorm:"type:bigint unsigned;not null;comment:Subscribe Id"`
|
|
||||||
OrderNo string `gorm:"type:varchar(255);not null;default:'';index:idx_order_no;comment:Order No"`
|
|
||||||
PromoPrice int64 `gorm:"type:bigint;not null;default:0;comment:Promo Price"`
|
|
||||||
CreatedAt time.Time `gorm:"<-:create;comment:Create Time"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (PromoUsage) TableName() string {
|
|
||||||
return "promo_usage"
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
package subscribe_promo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/perfect-panel/server/pkg/cache"
|
|
||||||
"github.com/redis/go-redis/v9"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ Model = (*customSubscribePromoModel)(nil)
|
|
||||||
|
|
||||||
var cacheSubscribePromoIdPrefix = "cache:subscribe_promo:id:"
|
|
||||||
|
|
||||||
type (
|
|
||||||
Model interface {
|
|
||||||
subscribePromoModel
|
|
||||||
customSubscribePromoLogicModel
|
|
||||||
}
|
|
||||||
|
|
||||||
subscribePromoModel interface {
|
|
||||||
Insert(ctx context.Context, data *SubscribePromo, tx ...*gorm.DB) error
|
|
||||||
FindOne(ctx context.Context, id int64) (*SubscribePromo, error)
|
|
||||||
Update(ctx context.Context, data *SubscribePromo, tx ...*gorm.DB) error
|
|
||||||
Delete(ctx context.Context, id int64, tx ...*gorm.DB) error
|
|
||||||
Transaction(ctx context.Context, fn func(db *gorm.DB) error) error
|
|
||||||
}
|
|
||||||
|
|
||||||
customSubscribePromoModel struct {
|
|
||||||
*defaultSubscribePromoModel
|
|
||||||
}
|
|
||||||
defaultSubscribePromoModel struct {
|
|
||||||
cache.CachedConn
|
|
||||||
table string
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
func newSubscribePromoModel(db *gorm.DB, c *redis.Client) *defaultSubscribePromoModel {
|
|
||||||
return &defaultSubscribePromoModel{
|
|
||||||
CachedConn: cache.NewConn(db, c),
|
|
||||||
table: "`subscribe_promo`",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultSubscribePromoModel) getCacheKeys(data *SubscribePromo) []string {
|
|
||||||
if data == nil {
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
return []string{fmt.Sprintf("%s%v", cacheSubscribePromoIdPrefix, data.Id)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultSubscribePromoModel) Insert(ctx context.Context, data *SubscribePromo, tx ...*gorm.DB) error {
|
|
||||||
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
|
|
||||||
if len(tx) > 0 {
|
|
||||||
conn = tx[0]
|
|
||||||
}
|
|
||||||
return conn.Create(data).Error
|
|
||||||
}, m.getCacheKeys(data)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultSubscribePromoModel) FindOne(ctx context.Context, id int64) (*SubscribePromo, error) {
|
|
||||||
key := fmt.Sprintf("%s%v", cacheSubscribePromoIdPrefix, id)
|
|
||||||
var resp SubscribePromo
|
|
||||||
err := m.QueryCtx(ctx, &resp, key, 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 *defaultSubscribePromoModel) Update(ctx context.Context, data *SubscribePromo, tx ...*gorm.DB) error {
|
|
||||||
old, err := m.FindOne(ctx, data.Id)
|
|
||||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
|
|
||||||
if len(tx) > 0 {
|
|
||||||
conn = tx[0]
|
|
||||||
}
|
|
||||||
return conn.Save(data).Error
|
|
||||||
}, m.getCacheKeys(old)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultSubscribePromoModel) Delete(ctx context.Context, id int64, tx ...*gorm.DB) error {
|
|
||||||
data, err := m.FindOne(ctx, id)
|
|
||||||
if err != nil {
|
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return m.ExecCtx(ctx, func(conn *gorm.DB) error {
|
|
||||||
if len(tx) > 0 {
|
|
||||||
conn = tx[0]
|
|
||||||
}
|
|
||||||
return conn.Delete(&SubscribePromo{}, id).Error
|
|
||||||
}, m.getCacheKeys(data)...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *defaultSubscribePromoModel) Transaction(ctx context.Context, fn func(db *gorm.DB) error) error {
|
|
||||||
return m.TransactCtx(ctx, fn)
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
package subscribe_promo
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/perfect-panel/server/internal/model/promo_rule"
|
|
||||||
"github.com/redis/go-redis/v9"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type RulePromo struct {
|
|
||||||
Id int64
|
|
||||||
SubscribeId int64
|
|
||||||
PromoRuleId int64
|
|
||||||
PromoPrice int64
|
|
||||||
RuleName string
|
|
||||||
RuleType string
|
|
||||||
Params promo_rule.JSONRawMessage
|
|
||||||
Priority int64
|
|
||||||
StartTime *time.Time
|
|
||||||
EndTime *time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type customSubscribePromoLogicModel interface {
|
|
||||||
FindOneBySubscribeAndRule(ctx context.Context, subscribeId, promoRuleId int64) (*SubscribePromo, error)
|
|
||||||
FindBySubscribeId(ctx context.Context, subscribeId int64) ([]*SubscribePromo, error)
|
|
||||||
FindByPromoRuleId(ctx context.Context, promoRuleId int64) ([]*SubscribePromo, error)
|
|
||||||
QueryEnabledBySubscribeId(ctx context.Context, subscribeId int64) ([]*RulePromo, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewModel(conn *gorm.DB, c *redis.Client) Model {
|
|
||||||
return &customSubscribePromoModel{
|
|
||||||
defaultSubscribePromoModel: newSubscribePromoModel(conn, c),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *customSubscribePromoModel) FindOneBySubscribeAndRule(ctx context.Context, subscribeId, promoRuleId int64) (*SubscribePromo, error) {
|
|
||||||
var resp SubscribePromo
|
|
||||||
err := m.QueryNoCacheCtx(ctx, &resp, func(conn *gorm.DB, v interface{}) error {
|
|
||||||
return conn.Model(&SubscribePromo{}).
|
|
||||||
Where("subscribe_id = ? AND promo_rule_id = ?", subscribeId, promoRuleId).
|
|
||||||
First(v).Error
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *customSubscribePromoModel) FindBySubscribeId(ctx context.Context, subscribeId int64) ([]*SubscribePromo, error) {
|
|
||||||
var list []*SubscribePromo
|
|
||||||
err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error {
|
|
||||||
return conn.Model(&SubscribePromo{}).
|
|
||||||
Where("subscribe_id = ?", subscribeId).
|
|
||||||
Order("id DESC").
|
|
||||||
Find(v).Error
|
|
||||||
})
|
|
||||||
return list, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *customSubscribePromoModel) FindByPromoRuleId(ctx context.Context, promoRuleId int64) ([]*SubscribePromo, error) {
|
|
||||||
var list []*SubscribePromo
|
|
||||||
err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error {
|
|
||||||
return conn.Model(&SubscribePromo{}).
|
|
||||||
Where("promo_rule_id = ?", promoRuleId).
|
|
||||||
Order("id DESC").
|
|
||||||
Find(v).Error
|
|
||||||
})
|
|
||||||
return list, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *customSubscribePromoModel) QueryEnabledBySubscribeId(ctx context.Context, subscribeId int64) ([]*RulePromo, error) {
|
|
||||||
var list []*RulePromo
|
|
||||||
err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error {
|
|
||||||
return conn.Table("subscribe_promo AS sp").
|
|
||||||
Select("sp.id, sp.subscribe_id, sp.promo_rule_id, sp.promo_price, pr.name AS rule_name, pr.type AS rule_type, pr.params, pr.priority, pr.start_time, pr.end_time").
|
|
||||||
Joins("JOIN promo_rule AS pr ON pr.id = sp.promo_rule_id AND pr.deleted_at IS NULL").
|
|
||||||
Where("sp.subscribe_id = ? AND pr.enabled = ?", subscribeId, true).
|
|
||||||
Order("pr.priority DESC, pr.id DESC").
|
|
||||||
Scan(v).Error
|
|
||||||
})
|
|
||||||
return list, err
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package subscribe_promo
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type SubscribePromo struct {
|
|
||||||
Id int64 `gorm:"type:bigint unsigned;primaryKey"`
|
|
||||||
SubscribeId int64 `gorm:"type:bigint unsigned;not null;index:uk_subscribe_rule,unique,priority:1;comment:Subscribe Id"`
|
|
||||||
PromoRuleId int64 `gorm:"type:bigint unsigned;not null;index:uk_subscribe_rule,unique,priority:2;index:idx_promo_rule_id;comment:Promo Rule Id"`
|
|
||||||
PromoPrice int64 `gorm:"type:bigint;not null;default:0;comment:Promo Price"`
|
|
||||||
CreatedAt time.Time `gorm:"<-:create;comment:Create Time"`
|
|
||||||
UpdatedAt time.Time `gorm:"comment:Update Time"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (SubscribePromo) TableName() string {
|
|
||||||
return "subscribe_promo"
|
|
||||||
}
|
|
||||||
@@ -21,10 +21,7 @@ import (
|
|||||||
logmessage "github.com/perfect-panel/server/internal/model/logmessage"
|
logmessage "github.com/perfect-panel/server/internal/model/logmessage"
|
||||||
"github.com/perfect-panel/server/internal/model/order"
|
"github.com/perfect-panel/server/internal/model/order"
|
||||||
"github.com/perfect-panel/server/internal/model/payment"
|
"github.com/perfect-panel/server/internal/model/payment"
|
||||||
"github.com/perfect-panel/server/internal/model/promo_rule"
|
|
||||||
"github.com/perfect-panel/server/internal/model/promo_usage"
|
|
||||||
"github.com/perfect-panel/server/internal/model/subscribe"
|
"github.com/perfect-panel/server/internal/model/subscribe"
|
||||||
"github.com/perfect-panel/server/internal/model/subscribe_promo"
|
|
||||||
"github.com/perfect-panel/server/internal/model/system"
|
"github.com/perfect-panel/server/internal/model/system"
|
||||||
"github.com/perfect-panel/server/internal/model/ticket"
|
"github.com/perfect-panel/server/internal/model/ticket"
|
||||||
"github.com/perfect-panel/server/internal/model/traffic"
|
"github.com/perfect-panel/server/internal/model/traffic"
|
||||||
@@ -68,9 +65,6 @@ type ServiceContext struct {
|
|||||||
PaymentModel payment.Model
|
PaymentModel payment.Model
|
||||||
DocumentModel document.Model
|
DocumentModel document.Model
|
||||||
SubscribeModel subscribe.Model
|
SubscribeModel subscribe.Model
|
||||||
PromoRuleModel promo_rule.Model
|
|
||||||
SubscribePromoModel subscribe_promo.Model
|
|
||||||
PromoUsageModel promo_usage.Model
|
|
||||||
TrafficLogModel traffic.Model
|
TrafficLogModel traffic.Model
|
||||||
AnnouncementModel announcement.Model
|
AnnouncementModel announcement.Model
|
||||||
IAPAppleTransactionModel iapapple.Model
|
IAPAppleTransactionModel iapapple.Model
|
||||||
@@ -146,9 +140,6 @@ func NewServiceContext(c config.Config) *ServiceContext {
|
|||||||
PaymentModel: payment.NewModel(db, rds),
|
PaymentModel: payment.NewModel(db, rds),
|
||||||
DocumentModel: document.NewModel(db, rds),
|
DocumentModel: document.NewModel(db, rds),
|
||||||
SubscribeModel: subscribe.NewModel(db, rds),
|
SubscribeModel: subscribe.NewModel(db, rds),
|
||||||
PromoRuleModel: promo_rule.NewModel(db, rds),
|
|
||||||
SubscribePromoModel: subscribe_promo.NewModel(db, rds),
|
|
||||||
PromoUsageModel: promo_usage.NewModel(db, rds),
|
|
||||||
TrafficLogModel: traffic.NewModel(db),
|
TrafficLogModel: traffic.NewModel(db),
|
||||||
AnnouncementModel: announcement.NewModel(db, rds),
|
AnnouncementModel: announcement.NewModel(db, rds),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3325,7 +3325,7 @@ type UpdateUserSubscribeRequest struct {
|
|||||||
ExpiredAt int64 `json:"expired_at"`
|
ExpiredAt int64 `json:"expired_at"`
|
||||||
Upload int64 `json:"upload"`
|
Upload int64 `json:"upload"`
|
||||||
Download int64 `json:"download"`
|
Download int64 `json:"download"`
|
||||||
SpeedLimit *int64 `json:"speed_limit,omitempty"`
|
SpeedLimit *int64 `json:"speed_limit,omitempty" validate:"omitempty,gte=0"`
|
||||||
TrafficLimit *string `json:"traffic_limit,omitempty"`
|
TrafficLimit *string `json:"traffic_limit,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user