Files
tm_back/internal/company_category/service.go
T
n.nakhostin 991771ee19 Add Company Category Management Functionality and Update API Documentation
- Introduced a new company category management feature, including CRUD operations for categories in both admin and public API endpoints.
- Implemented category entity, service, repository, and handler layers following clean architecture principles.
- Added new API routes for searching, retrieving, updating, deleting, and toggling publish status of categories, enhancing the overall functionality of the system.
- Updated Swagger and YAML documentation to include detailed descriptions and examples for the new category endpoints, ensuring clarity for API consumers.
- Enhanced error handling for duplicate categories and validation, improving the robustness of the category management process.
- Updated existing routes to integrate category handling, ensuring a seamless user experience across the application.
2025-09-08 12:31:49 +03:30

225 lines
6.3 KiB
Go

package company_category
import (
"context"
"errors"
"tm/pkg/logger"
"tm/pkg/response"
)
// Service defines business logic for category operations
type Service interface {
// Core category operations
Create(ctx context.Context, form *CategoryForm) (*CategoryResponse, error)
Update(ctx context.Context, id string, form *CategoryForm) (*CategoryResponse, error)
GetByID(ctx context.Context, id string) (*CategoryResponse, error)
GetByIDs(ctx context.Context, ids []string) ([]*CategoryResponse, error)
Delete(ctx context.Context, id string) error
// Category listing and search
SearchCategories(ctx context.Context, form *SearchForm, pagination *response.Pagination) (*CategoryListResponse, error)
// Category management
TogglePublish(ctx context.Context, id string) (bool, error)
}
// categoryService implements the Service interface
type categoryService struct {
repository Repository
logger logger.Logger
}
// NewCategoryService creates a new category service
func NewCategoryService(repository Repository, logger logger.Logger) Service {
return &categoryService{
repository: repository,
logger: logger,
}
}
// Create creates a new category
func (s *categoryService) Create(ctx context.Context, form *CategoryForm) (*CategoryResponse, error) {
// Check if category name already exists
existingCategory, _ := s.repository.GetByName(ctx, form.Name)
if existingCategory != nil {
return nil, errors.New("category with this name already exists")
}
// Create category
category := &Category{
Name: form.Name,
Description: form.Description,
Thumbnail: form.Thumbnail,
Published: false, // Default to unpublished
}
// Save to database
err := s.repository.Create(ctx, category)
if err != nil {
s.logger.Error("Failed to create category", map[string]interface{}{
"error": err.Error(),
"name": form.Name,
})
return nil, err
}
s.logger.Info("Category created successfully", map[string]interface{}{
"category_id": category.ID,
"name": category.Name,
"published": category.Published,
})
return category.ToResponse(), nil
}
// GetByIDs retrieves categories by IDs
func (s *categoryService) GetByIDs(ctx context.Context, ids []string) ([]*CategoryResponse, error) {
categories, err := s.repository.GetByIDs(ctx, ids)
if err != nil {
return nil, err
}
var categoryResponses []*CategoryResponse
for _, category := range categories {
categoryResponses = append(categoryResponses, category.ToResponse())
}
return categoryResponses, nil
}
// GetByID retrieves a category by ID
func (s *categoryService) GetByID(ctx context.Context, id string) (*CategoryResponse, error) {
category, err := s.repository.GetByID(ctx, id)
if err != nil {
s.logger.Error("Failed to get category by ID", map[string]interface{}{
"error": err.Error(),
"category_id": id,
})
return nil, err
}
s.logger.Info("Category retrieved successfully", map[string]interface{}{
"category_id": category.ID,
"name": category.Name,
})
return category.ToResponse(), nil
}
// Update updates a category
func (s *categoryService) Update(ctx context.Context, id string, form *CategoryForm) (*CategoryResponse, error) {
// Get existing category
category, err := s.repository.GetByID(ctx, id)
if err != nil {
s.logger.Error("Failed to get category for update", map[string]interface{}{
"error": err.Error(),
"category_id": id,
})
return nil, errors.New("category not found")
}
// Check if name already exists (if changing name)
if form.Name != "" && form.Name != category.Name {
existingCategory, _ := s.repository.GetByName(ctx, form.Name)
if existingCategory != nil {
return nil, errors.New("category with this name already exists")
}
category.Name = form.Name
}
// Update fields if provided
if form.Description != nil {
category.Description = form.Description
}
if form.Thumbnail != nil {
category.Thumbnail = form.Thumbnail
}
// Update in database
err = s.repository.Update(ctx, category)
if err != nil {
s.logger.Error("Failed to update category", map[string]interface{}{
"error": err.Error(),
"category_id": id,
})
return nil, errors.New("failed to update category")
}
s.logger.Info("Category updated successfully", map[string]interface{}{
"category_id": category.ID,
"name": category.Name,
})
return category.ToResponse(), nil
}
// Delete deletes a category
func (s *categoryService) Delete(ctx context.Context, id string) error {
// Delete category
err := s.repository.Delete(ctx, id)
if err != nil {
s.logger.Error("Failed to delete category", map[string]interface{}{
"error": err.Error(),
"category_id": id,
})
return errors.New("failed to delete category")
}
s.logger.Info("Category deleted successfully", map[string]interface{}{
"category_id": id,
})
return nil
}
// SearchCategories searches categories with filters
func (s *categoryService) SearchCategories(ctx context.Context, form *SearchForm, pagination *response.Pagination) (*CategoryListResponse, error) {
// Get categories using search
categories, total, err := s.repository.Search(ctx, form, pagination)
if err != nil {
s.logger.Error("Failed to search categories", map[string]interface{}{
"error": err.Error(),
})
return nil, errors.New("failed to search categories")
}
// Convert to responses
var categoryResponses []*CategoryResponse
for _, category := range categories {
categoryResponses = append(categoryResponses, category.ToResponse())
}
return &CategoryListResponse{
Categories: categoryResponses,
Meta: pagination.Response(total),
}, nil
}
// TogglePublish toggles category publish status
func (s *categoryService) TogglePublish(ctx context.Context, id string) (bool, error) {
// Get category to check if exists
_, err := s.repository.GetByID(ctx, id)
if err != nil {
return false, errors.New("category not found")
}
// Toggle publish status
published, err := s.repository.TogglePublish(ctx, id)
if err != nil {
s.logger.Error("Failed to toggle category publish status", map[string]interface{}{
"error": err.Error(),
"category_id": id,
})
return false, errors.New("failed to toggle category publish status")
}
s.logger.Info("Category publish status updated successfully", map[string]interface{}{
"category_id": id,
"published": published,
})
return published, nil
}