package entitlement import ( "backend/internal/dto" "backend/internal/model" "backend/utils" "errors" "time" "gorm.io/gorm" ) // EntitlementService 客户权益业务逻辑层 // Logan.Li type EntitlementService struct { db *gorm.DB } // NewEntitlementService 创建 service 实例 // Logan.Li func NewEntitlementService(db *gorm.DB) *EntitlementService { return &EntitlementService{db: db} } // List 分页/筛选查询权益 // Logan.Li func (s *EntitlementService) List(page, pageSize int, customerID, productID uint) ([]dto.EntitlementResponse, int64, error) { var entitlements []model.CustomerEntitlement var total int64 query := s.db.Model(&model.CustomerEntitlement{}).Preload("Customer").Preload("Product").Preload("Plan") if customerID > 0 { query = query.Where("customer_id = ?", customerID) } if productID > 0 { query = query.Where("product_id = ?", productID) } query.Count(&total) if err := query.Order("created_at DESC"). Offset((page - 1) * pageSize).Limit(pageSize). Find(&entitlements).Error; err != nil { return nil, 0, err } results := make([]dto.EntitlementResponse, 0, len(entitlements)) for _, e := range entitlements { results = append(results, s.toResponse(e)) } return results, total, nil } // GetByID 获取权益详情 // Logan.Li func (s *EntitlementService) GetByID(id uint) (*dto.EntitlementResponse, error) { var ent model.CustomerEntitlement if err := s.db.Preload("Customer").Preload("Product").Preload("Plan").First(&ent, id).Error; err != nil { return nil, errors.New("权益记录不存在") } resp := s.toResponse(ent) return &resp, nil } // Revoke 吊销权益 // Logan.Li func (s *EntitlementService) Revoke(id uint) error { var ent model.CustomerEntitlement if err := s.db.First(&ent, id).Error; err != nil { return errors.New("权益记录不存在") } return s.db.Transaction(func(tx *gorm.DB) error { ent.Status = "revoked" if err := tx.Save(&ent).Error; err != nil { return err } // 同步吊销关联 License // Logan.Li if ent.LicenseID > 0 { tx.Model(&model.License{}).Where("id = ?", ent.LicenseID). Updates(map[string]interface{}{"status": model.LicenseStatusRevoked, "revoke_reason": "权益被吊销"}) } return nil }) } // Renew 续费订阅(按计划延长有效期) // Logan.Li func (s *EntitlementService) Renew(id, planID uint) (*dto.EntitlementResponse, error) { var ent model.CustomerEntitlement if err := s.db.First(&ent, id).Error; err != nil { return nil, errors.New("权益记录不存在") } var plan model.Plan if err := s.db.First(&plan, planID).Error; err != nil { return nil, errors.New("定价计划不存在") } now := time.Now() var validUntil *time.Time if plan.Duration == 0 { validUntil = nil // 永久 } else { var base time.Time if ent.ValidUntil != nil && ent.ValidUntil.After(now) { base = *ent.ValidUntil } else { base = now } end := base.AddDate(0, 0, plan.Duration) validUntil = &end } ent.Status = "active" ent.ValidFrom = now ent.ValidUntil = validUntil ent.PlanID = planID ent.PlanType = plan.PlanType if err := s.db.Save(&ent).Error; err != nil { return nil, errors.New("续费失败") } // 同步延长关联 License 有效期 // Logan.Li if ent.LicenseID > 0 { var lic model.License s.db.First(&lic, ent.LicenseID) if plan.Duration == 0 { lic.EndDate = model.PermanentEndDate } else { base := lic.EndDate if utils.IsLicenseExpired(lic.EndDate) { base = now } lic.EndDate = base.AddDate(0, 0, plan.Duration) } lic.Status = model.LicenseStatusActive s.db.Save(&lic) } s.db.Preload("Customer").Preload("Product").Preload("Plan").First(&ent, id) resp := s.toResponse(ent) return &resp, nil } // GetByEmail 按邮箱查询客户权益(客户端接口) // Logan.Li func (s *EntitlementService) GetByEmail(email string) ([]dto.EntitlementResponse, error) { var customer model.Customer if err := s.db.Where("email = ?", email).First(&customer).Error; err != nil { return []dto.EntitlementResponse{}, nil } var entitlements []model.CustomerEntitlement s.db.Where("customer_id = ?", customer.ID). Preload("Product").Preload("Plan"). Find(&entitlements) results := make([]dto.EntitlementResponse, 0, len(entitlements)) for _, e := range entitlements { results = append(results, s.toResponse(e)) } return results, nil } // toResponse 模型转响应 DTO // Logan.Li func (s *EntitlementService) toResponse(e model.CustomerEntitlement) dto.EntitlementResponse { resp := dto.EntitlementResponse{ ID: e.ID, CustomerID: e.CustomerID, ProductID: e.ProductID, PlanID: e.PlanID, PlanType: e.PlanType, LicenseKey: e.LicenseKey, Status: e.Status, ValidFrom: e.ValidFrom.Format("2006-01-02 15:04:05"), Renewable: e.Renewable, } if e.Customer.ID > 0 { resp.CustomerName = e.Customer.Name } if e.Product.ID > 0 { resp.ProductName = e.Product.Name } if e.Plan.ID > 0 { resp.PlanName = e.Plan.Name } if e.ValidUntil != nil { s := e.ValidUntil.Format("2006-01-02 15:04:05") resp.ValidUntil = &s resp.DaysLeft = utils.CalculateDaysLeft(*e.ValidUntil) } else { resp.DaysLeft = 9999 // 永久 } // 查设备数 // Logan.Li if e.LicenseID > 0 { var lic model.License s.db.First(&lic, e.LicenseID) resp.MaxDevices = lic.MaxActivations var count int64 s.db.Model(&model.Activation{}).Where("license_id = ?", e.LicenseID).Count(&count) resp.CurrentDevices = int(count) } return resp }