Files
junhong_cmp_fiber/internal/store/postgres/package_store.go
huang 47aa5f8d25 fix(poll): Series 删除前检查关联套餐 POLL-04
- package_store.go 新增 CountBySeriesID 方法,统计指定系列下的活跃套餐数量
- package_series/service.go Service 注入 packageStore 字段,Delete 前调用 CountBySeriesID 检查
- bootstrap/services.go 更新 PackageSeries 服务初始化,传入 PackageStore
2026-03-28 10:42:58 +08:00

151 lines
5.0 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 postgres
import (
"context"
"gorm.io/gorm"
"github.com/break/junhong_cmp_fiber/internal/model"
"github.com/break/junhong_cmp_fiber/internal/store"
"github.com/break/junhong_cmp_fiber/pkg/constants"
"github.com/break/junhong_cmp_fiber/pkg/errors"
"github.com/break/junhong_cmp_fiber/pkg/middleware"
)
type PackageStore struct {
db *gorm.DB
}
func NewPackageStore(db *gorm.DB) *PackageStore {
return &PackageStore{db: db}
}
func (s *PackageStore) Create(ctx context.Context, pkg *model.Package) error {
return s.db.WithContext(ctx).Create(pkg).Error
}
func (s *PackageStore) GetByID(ctx context.Context, id uint) (*model.Package, error) {
var pkg model.Package
if err := s.db.WithContext(ctx).First(&pkg, id).Error; err != nil {
return nil, err
}
return &pkg, nil
}
func (s *PackageStore) GetByCode(ctx context.Context, code string) (*model.Package, error) {
var pkg model.Package
if err := s.db.WithContext(ctx).Where("package_code = ?", code).First(&pkg).Error; err != nil {
return nil, err
}
return &pkg, nil
}
func (s *PackageStore) Update(ctx context.Context, pkg *model.Package) error {
return s.db.WithContext(ctx).Save(pkg).Error
}
func (s *PackageStore) Delete(ctx context.Context, id uint) error {
return s.db.WithContext(ctx).Delete(&model.Package{}, id).Error
}
func (s *PackageStore) List(ctx context.Context, opts *store.QueryOptions, filters map[string]interface{}) ([]*model.Package, int64, error) {
var packages []*model.Package
var total int64
query := s.db.WithContext(ctx).Model(&model.Package{})
// 代理用户额外过滤只能看到已分配allocation.status=启用)的套餐
// 不按 tb_package.shelf_status 过滤,代理套餐可见性由 allocation.shelf_status 决定
userType := middleware.GetUserTypeFromContext(ctx)
shopID := middleware.GetShopIDFromContext(ctx)
isAgent := userType == constants.UserTypeAgent && shopID > 0
if isAgent {
query = query.Joins("INNER JOIN tb_shop_package_allocation ON tb_shop_package_allocation.package_id = tb_package.id AND tb_shop_package_allocation.deleted_at IS NULL").
Where("tb_shop_package_allocation.shop_id = ? AND tb_shop_package_allocation.status = ?",
shopID, constants.StatusEnabled)
}
if packageName, ok := filters["package_name"].(string); ok && packageName != "" {
query = query.Where("tb_package.package_name LIKE ?", "%"+packageName+"%")
}
if seriesID, ok := filters["series_id"].(uint); ok && seriesID > 0 {
query = query.Where("tb_package.series_id = ?", seriesID)
}
if status, ok := filters["status"]; ok {
query = query.Where("tb_package.status = ?", status)
}
if shelfStatus, ok := filters["shelf_status"]; ok {
if isAgent {
// 代理用户按自己的 allocation.shelf_status 过滤,不使用平台全局值
query = query.Where("tb_shop_package_allocation.shelf_status = ?", shelfStatus)
} else {
query = query.Where("tb_package.shelf_status = ?", shelfStatus)
}
}
if packageType, ok := filters["package_type"].(string); ok && packageType != "" {
query = query.Where("tb_package.package_type = ?", packageType)
}
if err := query.Count(&total).Error; err != nil {
return nil, 0, err
}
if opts == nil {
opts = store.DefaultQueryOptions()
}
offset := (opts.Page - 1) * opts.PageSize
query = query.Offset(offset).Limit(opts.PageSize)
if opts.OrderBy != "" {
query = query.Order(opts.OrderBy)
}
if err := query.Find(&packages).Error; err != nil {
return nil, 0, err
}
return packages, total, nil
}
func (s *PackageStore) UpdateStatus(ctx context.Context, id uint, status int) error {
return s.db.WithContext(ctx).Model(&model.Package{}).Where("id = ?", id).Update("status", status).Error
}
func (s *PackageStore) UpdateShelfStatus(ctx context.Context, id uint, shelfStatus int) error {
return s.db.WithContext(ctx).Model(&model.Package{}).Where("id = ?", id).Update("shelf_status", shelfStatus).Error
}
// GetByIDUnscoped 根据ID获取套餐包括已删除的记录
// 用于关联查询场景,确保已删除的套餐信息仍能被展示
func (s *PackageStore) GetByIDUnscoped(ctx context.Context, id uint) (*model.Package, error) {
var pkg model.Package
if err := s.db.WithContext(ctx).Unscoped().First(&pkg, id).Error; err != nil {
return nil, err
}
return &pkg, nil
}
// GetByIDsUnscoped 批量获取套餐(包括已删除的记录)
func (s *PackageStore) GetByIDsUnscoped(ctx context.Context, ids []uint) ([]*model.Package, error) {
if len(ids) == 0 {
return nil, nil
}
var packages []*model.Package
if err := s.db.WithContext(ctx).Unscoped().Where("id IN ?", ids).Find(&packages).Error; err != nil {
return nil, err
}
return packages, nil
}
// CountBySeriesID 统计指定系列下的活跃套餐数量(未软删除)
func (s *PackageStore) CountBySeriesID(ctx context.Context, seriesID uint) (int64, error) {
var count int64
err := s.db.WithContext(ctx).Model(&model.Package{}).
Where("series_id = ? AND deleted_at IS NULL", seriesID).
Count(&count).Error
if err != nil {
return 0, errors.Wrap(errors.CodeDatabaseError, err, "统计关联套餐失败")
}
return count, nil
}