feat: implement coupon management and receive flow

This commit is contained in:
2026-01-13 18:19:29 +08:00
parent 9b06f768ab
commit 4f315cc2db
18 changed files with 1787 additions and 246 deletions

View File

@@ -48,6 +48,10 @@ field_type:
status: consts.ContentAccessStatus
tenant_ledgers:
type: consts.TenantLedgerType
coupons:
type: consts.CouponType
user_coupons:
status: consts.UserCouponStatus
field_relate:
contents:
Author:

View File

@@ -40,9 +40,9 @@ type Content struct {
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;type:timestamp with time zone" json:"deleted_at"`
Key string `gorm:"column:key;type:character varying(32);comment:Musical key/tone" json:"key"` // Musical key/tone
IsPinned bool `gorm:"column:is_pinned;type:boolean;comment:Whether content is pinned/featured" json:"is_pinned"` // Whether content is pinned/featured
Comments []*Comment `gorm:"foreignKey:ContentID;references:ID" json:"comments,omitempty"`
Author *User `gorm:"foreignKey:UserID;references:ID" json:"author,omitempty"`
ContentAssets []*ContentAsset `gorm:"foreignKey:ContentID;references:ID" json:"content_assets,omitempty"`
Comments []*Comment `gorm:"foreignKey:ContentID;references:ID" json:"comments,omitempty"`
}
// Quick operations without importing query package

View File

@@ -46,6 +46,12 @@ func newContent(db *gorm.DB, opts ...gen.DOOption) contentQuery {
_contentQuery.DeletedAt = field.NewField(tableName, "deleted_at")
_contentQuery.Key = field.NewString(tableName, "key")
_contentQuery.IsPinned = field.NewBool(tableName, "is_pinned")
_contentQuery.Comments = contentQueryHasManyComments{
db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("Comments", "Comment"),
}
_contentQuery.Author = contentQueryBelongsToAuthor{
db: db.Session(&gorm.Session{}),
@@ -58,12 +64,6 @@ func newContent(db *gorm.DB, opts ...gen.DOOption) contentQuery {
RelationField: field.NewRelation("ContentAssets", "ContentAsset"),
}
_contentQuery.Comments = contentQueryHasManyComments{
db: db.Session(&gorm.Session{}),
RelationField: field.NewRelation("Comments", "Comment"),
}
_contentQuery.fillFieldMap()
return _contentQuery
@@ -94,12 +94,12 @@ type contentQuery struct {
DeletedAt field.Field
Key field.String // Musical key/tone
IsPinned field.Bool // Whether content is pinned/featured
Author contentQueryBelongsToAuthor
Comments contentQueryHasManyComments
Author contentQueryBelongsToAuthor
ContentAssets contentQueryHasManyContentAssets
Comments contentQueryHasManyComments
fieldMap map[string]field.Expr
}
@@ -195,23 +195,104 @@ func (c *contentQuery) fillFieldMap() {
func (c contentQuery) clone(db *gorm.DB) contentQuery {
c.contentQueryDo.ReplaceConnPool(db.Statement.ConnPool)
c.Comments.db = db.Session(&gorm.Session{Initialized: true})
c.Comments.db.Statement.ConnPool = db.Statement.ConnPool
c.Author.db = db.Session(&gorm.Session{Initialized: true})
c.Author.db.Statement.ConnPool = db.Statement.ConnPool
c.ContentAssets.db = db.Session(&gorm.Session{Initialized: true})
c.ContentAssets.db.Statement.ConnPool = db.Statement.ConnPool
c.Comments.db = db.Session(&gorm.Session{Initialized: true})
c.Comments.db.Statement.ConnPool = db.Statement.ConnPool
return c
}
func (c contentQuery) replaceDB(db *gorm.DB) contentQuery {
c.contentQueryDo.ReplaceDB(db)
c.Comments.db = db.Session(&gorm.Session{})
c.Author.db = db.Session(&gorm.Session{})
c.ContentAssets.db = db.Session(&gorm.Session{})
c.Comments.db = db.Session(&gorm.Session{})
return c
}
type contentQueryHasManyComments struct {
db *gorm.DB
field.RelationField
}
func (a contentQueryHasManyComments) Where(conds ...field.Expr) *contentQueryHasManyComments {
if len(conds) == 0 {
return &a
}
exprs := make([]clause.Expression, 0, len(conds))
for _, cond := range conds {
exprs = append(exprs, cond.BeCond().(clause.Expression))
}
a.db = a.db.Clauses(clause.Where{Exprs: exprs})
return &a
}
func (a contentQueryHasManyComments) WithContext(ctx context.Context) *contentQueryHasManyComments {
a.db = a.db.WithContext(ctx)
return &a
}
func (a contentQueryHasManyComments) Session(session *gorm.Session) *contentQueryHasManyComments {
a.db = a.db.Session(session)
return &a
}
func (a contentQueryHasManyComments) Model(m *Content) *contentQueryHasManyCommentsTx {
return &contentQueryHasManyCommentsTx{a.db.Model(m).Association(a.Name())}
}
func (a contentQueryHasManyComments) Unscoped() *contentQueryHasManyComments {
a.db = a.db.Unscoped()
return &a
}
type contentQueryHasManyCommentsTx struct{ tx *gorm.Association }
func (a contentQueryHasManyCommentsTx) Find() (result []*Comment, err error) {
return result, a.tx.Find(&result)
}
func (a contentQueryHasManyCommentsTx) Append(values ...*Comment) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Append(targetValues...)
}
func (a contentQueryHasManyCommentsTx) Replace(values ...*Comment) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Replace(targetValues...)
}
func (a contentQueryHasManyCommentsTx) Delete(values ...*Comment) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Delete(targetValues...)
}
func (a contentQueryHasManyCommentsTx) Clear() error {
return a.tx.Clear()
}
func (a contentQueryHasManyCommentsTx) Count() int64 {
return a.tx.Count()
}
func (a contentQueryHasManyCommentsTx) Unscoped() *contentQueryHasManyCommentsTx {
a.tx = a.tx.Unscoped()
return &a
}
type contentQueryBelongsToAuthor struct {
db *gorm.DB
@@ -374,87 +455,6 @@ func (a contentQueryHasManyContentAssetsTx) Unscoped() *contentQueryHasManyConte
return &a
}
type contentQueryHasManyComments struct {
db *gorm.DB
field.RelationField
}
func (a contentQueryHasManyComments) Where(conds ...field.Expr) *contentQueryHasManyComments {
if len(conds) == 0 {
return &a
}
exprs := make([]clause.Expression, 0, len(conds))
for _, cond := range conds {
exprs = append(exprs, cond.BeCond().(clause.Expression))
}
a.db = a.db.Clauses(clause.Where{Exprs: exprs})
return &a
}
func (a contentQueryHasManyComments) WithContext(ctx context.Context) *contentQueryHasManyComments {
a.db = a.db.WithContext(ctx)
return &a
}
func (a contentQueryHasManyComments) Session(session *gorm.Session) *contentQueryHasManyComments {
a.db = a.db.Session(session)
return &a
}
func (a contentQueryHasManyComments) Model(m *Content) *contentQueryHasManyCommentsTx {
return &contentQueryHasManyCommentsTx{a.db.Model(m).Association(a.Name())}
}
func (a contentQueryHasManyComments) Unscoped() *contentQueryHasManyComments {
a.db = a.db.Unscoped()
return &a
}
type contentQueryHasManyCommentsTx struct{ tx *gorm.Association }
func (a contentQueryHasManyCommentsTx) Find() (result []*Comment, err error) {
return result, a.tx.Find(&result)
}
func (a contentQueryHasManyCommentsTx) Append(values ...*Comment) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Append(targetValues...)
}
func (a contentQueryHasManyCommentsTx) Replace(values ...*Comment) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Replace(targetValues...)
}
func (a contentQueryHasManyCommentsTx) Delete(values ...*Comment) (err error) {
targetValues := make([]interface{}, len(values))
for i, v := range values {
targetValues[i] = v
}
return a.tx.Delete(targetValues...)
}
func (a contentQueryHasManyCommentsTx) Clear() error {
return a.tx.Clear()
}
func (a contentQueryHasManyCommentsTx) Count() int64 {
return a.tx.Count()
}
func (a contentQueryHasManyCommentsTx) Unscoped() *contentQueryHasManyCommentsTx {
a.tx = a.tx.Unscoped()
return &a
}
type contentQueryDo struct{ gen.DO }
func (c contentQueryDo) Debug() *contentQueryDo {

View File

@@ -8,6 +8,8 @@ import (
"context"
"time"
"quyun/v2/pkg/consts"
"go.ipao.vip/gen"
)
@@ -15,20 +17,20 @@ const TableNameCoupon = "coupons"
// Coupon mapped from table <coupons>
type Coupon struct {
ID int64 `gorm:"column:id;type:bigint;primaryKey;autoIncrement:true" json:"id"`
TenantID int64 `gorm:"column:tenant_id;type:bigint;not null" json:"tenant_id"`
Title string `gorm:"column:title;type:character varying(255);not null" json:"title"`
Description string `gorm:"column:description;type:text" json:"description"`
Type string `gorm:"column:type;type:character varying(32);not null" json:"type"`
Value int64 `gorm:"column:value;type:bigint;not null" json:"value"`
MinOrderAmount int64 `gorm:"column:min_order_amount;type:bigint;not null" json:"min_order_amount"`
MaxDiscount int64 `gorm:"column:max_discount;type:bigint" json:"max_discount"`
TotalQuantity int32 `gorm:"column:total_quantity;type:integer;not null" json:"total_quantity"`
UsedQuantity int32 `gorm:"column:used_quantity;type:integer;not null" json:"used_quantity"`
StartAt time.Time `gorm:"column:start_at;type:timestamp with time zone" json:"start_at"`
EndAt time.Time `gorm:"column:end_at;type:timestamp with time zone" json:"end_at"`
CreatedAt time.Time `gorm:"column:created_at;type:timestamp with time zone;not null;default:now()" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp with time zone;not null;default:now()" json:"updated_at"`
ID int64 `gorm:"column:id;type:bigint;primaryKey;autoIncrement:true" json:"id"`
TenantID int64 `gorm:"column:tenant_id;type:bigint;not null" json:"tenant_id"`
Title string `gorm:"column:title;type:character varying(255);not null" json:"title"`
Description string `gorm:"column:description;type:text" json:"description"`
Type consts.CouponType `gorm:"column:type;type:character varying(32);not null" json:"type"`
Value int64 `gorm:"column:value;type:bigint;not null" json:"value"`
MinOrderAmount int64 `gorm:"column:min_order_amount;type:bigint;not null" json:"min_order_amount"`
MaxDiscount int64 `gorm:"column:max_discount;type:bigint" json:"max_discount"`
TotalQuantity int32 `gorm:"column:total_quantity;type:integer;not null" json:"total_quantity"`
UsedQuantity int32 `gorm:"column:used_quantity;type:integer;not null" json:"used_quantity"`
StartAt time.Time `gorm:"column:start_at;type:timestamp with time zone" json:"start_at"`
EndAt time.Time `gorm:"column:end_at;type:timestamp with time zone" json:"end_at"`
CreatedAt time.Time `gorm:"column:created_at;type:timestamp with time zone;not null;default:now()" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp with time zone;not null;default:now()" json:"updated_at"`
}
// Quick operations without importing query package

View File

@@ -29,7 +29,7 @@ func newCoupon(db *gorm.DB, opts ...gen.DOOption) couponQuery {
_couponQuery.TenantID = field.NewInt64(tableName, "tenant_id")
_couponQuery.Title = field.NewString(tableName, "title")
_couponQuery.Description = field.NewString(tableName, "description")
_couponQuery.Type = field.NewString(tableName, "type")
_couponQuery.Type = field.NewField(tableName, "type")
_couponQuery.Value = field.NewInt64(tableName, "value")
_couponQuery.MinOrderAmount = field.NewInt64(tableName, "min_order_amount")
_couponQuery.MaxDiscount = field.NewInt64(tableName, "max_discount")
@@ -53,7 +53,7 @@ type couponQuery struct {
TenantID field.Int64
Title field.String
Description field.String
Type field.String
Type field.Field
Value field.Int64
MinOrderAmount field.Int64
MaxDiscount field.Int64
@@ -83,7 +83,7 @@ func (c *couponQuery) updateTableName(table string) *couponQuery {
c.TenantID = field.NewInt64(table, "tenant_id")
c.Title = field.NewString(table, "title")
c.Description = field.NewString(table, "description")
c.Type = field.NewString(table, "type")
c.Type = field.NewField(table, "type")
c.Value = field.NewInt64(table, "value")
c.MinOrderAmount = field.NewInt64(table, "min_order_amount")
c.MaxDiscount = field.NewInt64(table, "max_discount")

View File

@@ -8,6 +8,8 @@ import (
"context"
"time"
"quyun/v2/pkg/consts"
"go.ipao.vip/gen"
)
@@ -15,13 +17,13 @@ const TableNameUserCoupon = "user_coupons"
// UserCoupon mapped from table <user_coupons>
type UserCoupon struct {
ID int64 `gorm:"column:id;type:bigint;primaryKey;autoIncrement:true" json:"id"`
UserID int64 `gorm:"column:user_id;type:bigint;not null" json:"user_id"`
CouponID int64 `gorm:"column:coupon_id;type:bigint;not null" json:"coupon_id"`
OrderID int64 `gorm:"column:order_id;type:bigint" json:"order_id"`
Status string `gorm:"column:status;type:character varying(32);not null;default:unused" json:"status"`
UsedAt time.Time `gorm:"column:used_at;type:timestamp with time zone" json:"used_at"`
CreatedAt time.Time `gorm:"column:created_at;type:timestamp with time zone;not null;default:now()" json:"created_at"`
ID int64 `gorm:"column:id;type:bigint;primaryKey;autoIncrement:true" json:"id"`
UserID int64 `gorm:"column:user_id;type:bigint;not null" json:"user_id"`
CouponID int64 `gorm:"column:coupon_id;type:bigint;not null" json:"coupon_id"`
OrderID int64 `gorm:"column:order_id;type:bigint" json:"order_id"`
Status consts.UserCouponStatus `gorm:"column:status;type:character varying(32);not null;default:unused" json:"status"`
UsedAt time.Time `gorm:"column:used_at;type:timestamp with time zone" json:"used_at"`
CreatedAt time.Time `gorm:"column:created_at;type:timestamp with time zone;not null;default:now()" json:"created_at"`
}
// Quick operations without importing query package

View File

@@ -29,7 +29,7 @@ func newUserCoupon(db *gorm.DB, opts ...gen.DOOption) userCouponQuery {
_userCouponQuery.UserID = field.NewInt64(tableName, "user_id")
_userCouponQuery.CouponID = field.NewInt64(tableName, "coupon_id")
_userCouponQuery.OrderID = field.NewInt64(tableName, "order_id")
_userCouponQuery.Status = field.NewString(tableName, "status")
_userCouponQuery.Status = field.NewField(tableName, "status")
_userCouponQuery.UsedAt = field.NewTime(tableName, "used_at")
_userCouponQuery.CreatedAt = field.NewTime(tableName, "created_at")
@@ -46,7 +46,7 @@ type userCouponQuery struct {
UserID field.Int64
CouponID field.Int64
OrderID field.Int64
Status field.String
Status field.Field
UsedAt field.Time
CreatedAt field.Time
@@ -69,7 +69,7 @@ func (u *userCouponQuery) updateTableName(table string) *userCouponQuery {
u.UserID = field.NewInt64(table, "user_id")
u.CouponID = field.NewInt64(table, "coupon_id")
u.OrderID = field.NewInt64(table, "order_id")
u.Status = field.NewString(table, "status")
u.Status = field.NewField(table, "status")
u.UsedAt = field.NewTime(table, "used_at")
u.CreatedAt = field.NewTime(table, "created_at")