Files
junhong_cmp_fiber/internal/model/package.go
huang f177c26016
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m27s
快照订单号以及退款订单号
2026-04-23 17:14:10 +08:00

183 lines
12 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package model
import (
"encoding/json"
"time"
"gorm.io/gorm"
)
// PackageSeries 套餐系列模型
// 套餐的分组,用于一次性分佣规则配置
type PackageSeries struct {
gorm.Model
BaseModel `gorm:"embedded"`
SeriesCode string `gorm:"column:series_code;type:varchar(100);uniqueIndex:idx_package_series_code,where:deleted_at IS NULL;not null;comment:系列编码" json:"series_code"`
SeriesName string `gorm:"column:series_name;type:varchar(255);not null;comment:系列名称" json:"series_name"`
Description string `gorm:"column:description;type:text;comment:描述" json:"description"`
Status int `gorm:"column:status;type:int;default:1;not null;comment:状态 0=禁用 1=启用" json:"status"`
OneTimeCommissionConfigJSON string `gorm:"column:one_time_commission_config;type:jsonb;default:'{}';comment:一次性佣金规则配置" json:"-"`
EnableOneTimeCommission bool `gorm:"column:enable_one_time_commission;default:false;comment:是否启用一次性佣金顶层字段支持SQL索引" json:"enable_one_time_commission"`
}
// TableName 指定表名
func (PackageSeries) TableName() string {
return "tb_package_series"
}
// Package 套餐模型
// 只适用于 IoT 卡,支持真流量/虚流量共存机制
type Package struct {
gorm.Model
BaseModel `gorm:"embedded"`
PackageCode string `gorm:"column:package_code;type:varchar(100);uniqueIndex:idx_package_code,where:deleted_at IS NULL;not null;comment:套餐编码" json:"package_code"`
PackageName string `gorm:"column:package_name;type:varchar(255);not null;comment:套餐名称" json:"package_name"`
SeriesID uint `gorm:"column:series_id;index;comment:套餐系列ID" json:"series_id"`
PackageType string `gorm:"column:package_type;type:varchar(50);not null;comment:套餐类型 formal-正式套餐 addon-附加套餐" json:"package_type"`
DurationMonths int `gorm:"column:duration_months;type:int;not null;comment:套餐时长(月数) 1-月套餐 12-年套餐" json:"duration_months"`
RealDataMB int64 `gorm:"column:real_data_mb;type:bigint;default:0;comment:真流量额度(MB)" json:"real_data_mb"`
VirtualDataMB int64 `gorm:"column:virtual_data_mb;type:bigint;default:0;comment:虚流量额度(MB,用于停机判断)" json:"virtual_data_mb"`
EnableVirtualData bool `gorm:"column:enable_virtual_data;type:boolean;default:false;not null;comment:是否启用虚流量" json:"enable_virtual_data"`
Status int `gorm:"column:status;type:int;default:1;not null;comment:状态 0=禁用 1=启用" json:"status"`
CostPrice int64 `gorm:"column:cost_price;type:bigint;default:0;comment:成本价(分为单位)" json:"cost_price"`
SuggestedRetailPrice int64 `gorm:"column:suggested_retail_price;type:bigint;default:0;comment:建议售价(分为单位)" json:"suggested_retail_price"`
ShelfStatus int `gorm:"column:shelf_status;type:int;default:2;not null;comment:上架状态 1-上架 2-下架" json:"shelf_status"`
CalendarType string `gorm:"column:calendar_type;type:varchar(20);default:'by_day';comment:套餐周期类型 natural_month-自然月 by_day-按天" json:"calendar_type"`
DurationDays int `gorm:"column:duration_days;type:int;comment:套餐天数(calendar_type=by_day时必填)" json:"duration_days"`
DataResetCycle string `gorm:"column:data_reset_cycle;type:varchar(20);default:'monthly';comment:流量重置周期 daily-每日 monthly-每月 yearly-每年 none-不重置" json:"data_reset_cycle"`
// ExpiryBase 到期时间基准from_activation-实名激活时起算from_purchase-购买时起算
ExpiryBase string `gorm:"column:expiry_base;type:varchar(30);not null;default:'from_activation';comment:到期时间基准 from_activation-实名激活时起算 from_purchase-购买时起算" json:"expiry_base"`
VirtualRatio float64 `gorm:"column:virtual_ratio;type:decimal(18,6);default:1.0;comment:虚流量比例(real_data_mb/virtual_data_mb),创建套餐时计算存储" json:"virtual_ratio"`
}
// TableName 指定表名
func (Package) TableName() string {
return "tb_package"
}
// PackageUsage 套餐使用情况模型
// 跟踪单卡套餐和设备级套餐的流量使用
type PackageUsage struct {
gorm.Model
BaseModel `gorm:"embedded"`
OrderID uint `gorm:"column:order_id;index;not null;comment:订单ID" json:"order_id"`
OrderNo string `gorm:"column:order_no;type:varchar(30);not null;default:'';comment:订单号快照(从订单复制)" json:"order_no"`
RefundID *uint `gorm:"column:refund_id;index;comment:退款单ID快照退款后写入" json:"refund_id,omitempty"`
RefundNo string `gorm:"column:refund_no;type:varchar(50);not null;default:'';comment:退款单号快照(退款后写入)" json:"refund_no"`
PackageID uint `gorm:"column:package_id;index;not null;comment:套餐ID" json:"package_id"`
UsageType string `gorm:"column:usage_type;type:varchar(20);not null;comment:使用类型 single_card-单卡套餐 device-设备级套餐" json:"usage_type"`
IotCardID uint `gorm:"column:iot_card_id;index;comment:IoT卡ID(单卡套餐时有值)" json:"iot_card_id"`
DeviceID uint `gorm:"column:device_id;index;comment:设备ID(设备级套餐时有值)" json:"device_id"`
DataLimitMB int64 `gorm:"column:data_limit_mb;type:bigint;not null;comment:流量限额(MB)" json:"data_limit_mb"`
DataUsageMB int64 `gorm:"column:data_usage_mb;type:bigint;default:0;comment:已使用流量(MB)" json:"data_usage_mb"`
RealDataUsageMB int64 `gorm:"column:real_data_usage_mb;type:bigint;default:0;comment:真流量使用(MB)" json:"real_data_usage_mb"`
VirtualDataUsageMB int64 `gorm:"column:virtual_data_usage_mb;type:bigint;default:0;comment:虚流量使用(MB)" json:"virtual_data_usage_mb"`
ActivatedAt *time.Time `gorm:"column:activated_at;comment:套餐生效时间" json:"activated_at"`
ExpiresAt *time.Time `gorm:"column:expires_at;comment:套餐过期时间" json:"expires_at"`
Status int `gorm:"column:status;type:int;default:1;not null;comment:状态 0-待生效 1-生效中 2-已用完 3-已过期 4-已失效" json:"status"`
LastPackageCheckAt *time.Time `gorm:"column:last_package_check_at;comment:最后一次套餐流量检查时间" json:"last_package_check_at"`
Priority int `gorm:"column:priority;type:int;default:1;index:idx_package_usage_priority;comment:优先级(主套餐和加油包按此字段排队,数字越小优先级越高)" json:"priority"`
MasterUsageID *uint `gorm:"column:master_usage_id;type:bigint;index:idx_package_usage_master_usage_id;comment:主套餐使用记录ID(加油包关联主套餐,主套餐此字段为NULL)" json:"master_usage_id"`
HasIndependentExpiry bool `gorm:"column:has_independent_expiry;type:boolean;default:false;comment:加油包是否有独立有效期(true-有独立到期时间 false-跟随主套餐)" json:"has_independent_expiry"`
PendingRealnameActivation bool `gorm:"column:pending_realname_activation;type:boolean;default:false;comment:是否等待实名激活(true-待实名后激活 false-已激活或不需实名)" json:"pending_realname_activation"`
PackageName string `gorm:"column:package_name;type:varchar(255);not null;default:'';comment:套餐名称快照(从Package复制,用于历史记录展示)" json:"package_name"`
PaidAmount *int64 `gorm:"column:paid_amount;type:bigint;comment:购买实付金额快照从订单复制无订单或线下支付时为null" json:"paid_amount,omitempty"`
DataResetCycle string `gorm:"column:data_reset_cycle;type:varchar(20);comment:流量重置周期(从Package复制,用于历史记录)" json:"data_reset_cycle"`
LastResetAt *time.Time `gorm:"column:last_reset_at;comment:最后一次流量重置时间" json:"last_reset_at"`
NextResetAt *time.Time `gorm:"column:next_reset_at;index:idx_package_usage_next_reset_at;comment:下次流量重置时间(用于定时任务查询)" json:"next_reset_at"`
Generation int `gorm:"column:generation;type:int;not null;default:1;comment:资产世代编号" json:"generation"`
}
// TableName 指定表名
func (PackageUsage) TableName() string {
return "tb_package_usage"
}
// PackageUsageDailyRecord 套餐流量日记录模型
// 记录每个套餐每天的流量使用情况,用于流量详单查询
type PackageUsageDailyRecord struct {
ID uint `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
PackageUsageID uint `gorm:"column:package_usage_id;not null;uniqueIndex:idx_package_usage_daily_record_unique;index:idx_package_usage_daily_record_date;comment:套餐使用记录ID" json:"package_usage_id"`
Date time.Time `gorm:"column:date;type:date;not null;uniqueIndex:idx_package_usage_daily_record_unique;comment:日期" json:"date"`
DailyUsageMB int `gorm:"column:daily_usage_mb;type:int;default:0;comment:当日流量使用量(MB)" json:"daily_usage_mb"`
CumulativeUsageMB int64 `gorm:"column:cumulative_usage_mb;type:bigint;default:0;comment:截止当日的累计流量(MB)" json:"cumulative_usage_mb"`
CreatedAt time.Time `gorm:"column:created_at;default:CURRENT_TIMESTAMP" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;default:CURRENT_TIMESTAMP" json:"updated_at"`
}
// TableName 指定表名
func (PackageUsageDailyRecord) TableName() string {
return "tb_package_usage_daily_record"
}
// OneTimeCommissionConfig 一次性佣金规则配置
type OneTimeCommissionConfig struct {
Enable bool `json:"enable"`
TriggerType string `json:"trigger_type"`
Threshold int64 `json:"threshold"`
CommissionType string `json:"commission_type"`
CommissionAmount int64 `json:"commission_amount"`
Tiers []OneTimeCommissionTier `json:"tiers,omitempty"`
ValidityType string `json:"validity_type"`
ValidityValue string `json:"validity_value"`
EnableForceRecharge bool `json:"enable_force_recharge"`
ForceCalcType string `json:"force_calc_type"`
ForceAmount int64 `json:"force_amount"`
}
// OneTimeCommissionTier 一次性佣金梯度配置
type OneTimeCommissionTier struct {
Operator string `json:"operator"` // 阈值比较运算符:>、>=、<、<=,空值默认 >=
Dimension string `json:"dimension"`
StatScope string `json:"stat_scope"`
Threshold int64 `json:"threshold"`
Amount int64 `json:"amount"`
}
const (
OneTimeCommissionTriggerFirstRecharge = "first_recharge"
OneTimeCommissionTriggerAccumulatedRecharge = "accumulated_recharge"
OneTimeCommissionValidityPermanent = "permanent"
OneTimeCommissionValidityFixedDate = "fixed_date"
OneTimeCommissionValidityRelative = "relative"
OneTimeCommissionForceCalcFixed = "fixed"
OneTimeCommissionForceCalcDynamic = "dynamic"
OneTimeCommissionStatScopeSelf = "self"
OneTimeCommissionStatScopeSelfAndSub = "self_and_sub"
TierTypeSalesCount = "sales_count"
TierTypeSalesAmount = "sales_amount"
// 阈值运算符常量
TierOperatorGT = ">"
TierOperatorGTE = ">="
TierOperatorLT = "<"
TierOperatorLTE = "<="
)
func (ps *PackageSeries) GetOneTimeCommissionConfig() (*OneTimeCommissionConfig, error) {
if ps.OneTimeCommissionConfigJSON == "" {
return nil, nil
}
var config OneTimeCommissionConfig
if err := json.Unmarshal([]byte(ps.OneTimeCommissionConfigJSON), &config); err != nil {
return nil, err
}
return &config, nil
}
func (ps *PackageSeries) SetOneTimeCommissionConfig(config *OneTimeCommissionConfig) error {
if config == nil {
ps.OneTimeCommissionConfigJSON = ""
return nil
}
data, err := json.Marshal(config)
if err != nil {
return err
}
ps.OneTimeCommissionConfigJSON = string(data)
return nil
}