172 lines
4.1 KiB
Go
172 lines
4.1 KiB
Go
package service
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
|
|
"aggios-app/backend/internal/domain"
|
|
"aggios-app/backend/internal/repository"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
var (
|
|
ErrTenantNotFound = errors.New("tenant not found")
|
|
)
|
|
|
|
// TenantService handles tenant business logic
|
|
type TenantService struct {
|
|
tenantRepo *repository.TenantRepository
|
|
db *sql.DB
|
|
}
|
|
|
|
// NewTenantService creates a new tenant service
|
|
func NewTenantService(tenantRepo *repository.TenantRepository, db *sql.DB) *TenantService {
|
|
return &TenantService{
|
|
tenantRepo: tenantRepo,
|
|
db: db,
|
|
}
|
|
}
|
|
|
|
// Create creates a new tenant
|
|
func (s *TenantService) Create(req domain.CreateTenantRequest) (*domain.Tenant, error) {
|
|
// Check if subdomain already exists
|
|
exists, err := s.tenantRepo.SubdomainExists(req.Subdomain)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if exists {
|
|
return nil, ErrSubdomainTaken
|
|
}
|
|
|
|
tenant := &domain.Tenant{
|
|
Name: req.Name,
|
|
Domain: req.Domain,
|
|
Subdomain: req.Subdomain,
|
|
}
|
|
|
|
if err := s.tenantRepo.Create(tenant); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return tenant, nil
|
|
}
|
|
|
|
// GetByID retrieves a tenant by ID
|
|
func (s *TenantService) GetByID(id uuid.UUID) (*domain.Tenant, error) {
|
|
tenant, err := s.tenantRepo.FindByID(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if tenant == nil {
|
|
return nil, ErrTenantNotFound
|
|
}
|
|
return tenant, nil
|
|
}
|
|
|
|
// GetBySubdomain retrieves a tenant by subdomain
|
|
func (s *TenantService) GetBySubdomain(subdomain string) (*domain.Tenant, error) {
|
|
tenant, err := s.tenantRepo.FindBySubdomain(subdomain)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if tenant == nil {
|
|
return nil, ErrTenantNotFound
|
|
}
|
|
return tenant, nil
|
|
}
|
|
|
|
// ListAll retrieves all tenants
|
|
func (s *TenantService) ListAll() ([]*domain.Tenant, error) {
|
|
return s.tenantRepo.FindAll()
|
|
}
|
|
|
|
// ListAllWithDetails retrieves all tenants with their plan and solutions information
|
|
func (s *TenantService) ListAllWithDetails() ([]map[string]interface{}, error) {
|
|
tenants, err := s.tenantRepo.FindAll()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var result []map[string]interface{}
|
|
for _, tenant := range tenants {
|
|
tenantData := map[string]interface{}{
|
|
"id": tenant.ID,
|
|
"name": tenant.Name,
|
|
"subdomain": tenant.Subdomain,
|
|
"domain": tenant.Domain,
|
|
"email": tenant.Email,
|
|
"phone": tenant.Phone,
|
|
"cnpj": tenant.CNPJ,
|
|
"is_active": tenant.IsActive,
|
|
"created_at": tenant.CreatedAt,
|
|
"logo_url": tenant.LogoURL,
|
|
"logo_horizontal_url": tenant.LogoHorizontalURL,
|
|
"primary_color": tenant.PrimaryColor,
|
|
"secondary_color": tenant.SecondaryColor,
|
|
}
|
|
|
|
// Buscar subscription e soluções
|
|
var planName sql.NullString
|
|
var planID string
|
|
query := `
|
|
SELECT
|
|
s.plan_id,
|
|
p.name as plan_name
|
|
FROM agency_subscriptions s
|
|
JOIN plans p ON s.plan_id = p.id
|
|
WHERE s.agency_id = $1 AND s.status = 'active'
|
|
LIMIT 1
|
|
`
|
|
err = s.db.QueryRow(query, tenant.ID).Scan(&planID, &planName)
|
|
if err == nil && planName.Valid {
|
|
tenantData["plan_name"] = planName.String
|
|
|
|
// Buscar soluções do plano
|
|
solutionsQuery := `
|
|
SELECT sol.id, sol.name, sol.slug, sol.icon
|
|
FROM solutions sol
|
|
JOIN plan_solutions ps ON sol.id = ps.solution_id
|
|
WHERE ps.plan_id = $1
|
|
ORDER BY sol.name
|
|
`
|
|
rows, err := s.db.Query(solutionsQuery, planID)
|
|
if err == nil {
|
|
defer rows.Close()
|
|
var solutions []map[string]interface{}
|
|
for rows.Next() {
|
|
var id, name, slug string
|
|
var icon sql.NullString
|
|
if err := rows.Scan(&id, &name, &slug, &icon); err == nil {
|
|
solution := map[string]interface{}{
|
|
"id": id,
|
|
"name": name,
|
|
"slug": slug,
|
|
}
|
|
if icon.Valid {
|
|
solution["icon"] = icon.String
|
|
}
|
|
solutions = append(solutions, solution)
|
|
}
|
|
}
|
|
tenantData["solutions"] = solutions
|
|
}
|
|
}
|
|
|
|
result = append(result, tenantData)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// Delete removes a tenant by ID
|
|
func (s *TenantService) Delete(id uuid.UUID) error {
|
|
if err := s.tenantRepo.Delete(id); err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
return ErrTenantNotFound
|
|
}
|
|
return err
|
|
}
|
|
return nil
|
|
}
|