153 lines
5.5 KiB
Go
153 lines
5.5 KiB
Go
|
|
package processor
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"fmt"
|
||
|
|
|
||
|
|
"apskel-pos-be/internal/entities"
|
||
|
|
"apskel-pos-be/internal/mappers"
|
||
|
|
"apskel-pos-be/internal/models"
|
||
|
|
|
||
|
|
"github.com/google/uuid"
|
||
|
|
)
|
||
|
|
|
||
|
|
type CategoryProcessor interface {
|
||
|
|
CreateCategory(ctx context.Context, req *models.CreateCategoryRequest) (*models.CategoryResponse, error)
|
||
|
|
UpdateCategory(ctx context.Context, id uuid.UUID, req *models.UpdateCategoryRequest) (*models.CategoryResponse, error)
|
||
|
|
DeleteCategory(ctx context.Context, id uuid.UUID) error
|
||
|
|
GetCategoryByID(ctx context.Context, id uuid.UUID) (*models.CategoryResponse, error)
|
||
|
|
ListCategories(ctx context.Context, filters map[string]interface{}, page, limit int) ([]models.CategoryResponse, int, error)
|
||
|
|
}
|
||
|
|
|
||
|
|
type CategoryRepository interface {
|
||
|
|
Create(ctx context.Context, category *entities.Category) error
|
||
|
|
GetByID(ctx context.Context, id uuid.UUID) (*entities.Category, error)
|
||
|
|
GetWithProducts(ctx context.Context, id uuid.UUID) (*entities.Category, error)
|
||
|
|
GetByOrganization(ctx context.Context, organizationID uuid.UUID) ([]*entities.Category, error)
|
||
|
|
GetByBusinessType(ctx context.Context, businessType string) ([]*entities.Category, error)
|
||
|
|
Update(ctx context.Context, category *entities.Category) error
|
||
|
|
Delete(ctx context.Context, id uuid.UUID) error
|
||
|
|
List(ctx context.Context, filters map[string]interface{}, limit, offset int) ([]*entities.Category, int64, error)
|
||
|
|
Count(ctx context.Context, filters map[string]interface{}) (int64, error)
|
||
|
|
GetByName(ctx context.Context, organizationID uuid.UUID, name string) (*entities.Category, error)
|
||
|
|
ExistsByName(ctx context.Context, organizationID uuid.UUID, name string, excludeID *uuid.UUID) (bool, error)
|
||
|
|
}
|
||
|
|
|
||
|
|
type CategoryProcessorImpl struct {
|
||
|
|
categoryRepo CategoryRepository
|
||
|
|
}
|
||
|
|
|
||
|
|
func NewCategoryProcessorImpl(categoryRepo CategoryRepository) *CategoryProcessorImpl {
|
||
|
|
return &CategoryProcessorImpl{
|
||
|
|
categoryRepo: categoryRepo,
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func (p *CategoryProcessorImpl) CreateCategory(ctx context.Context, req *models.CreateCategoryRequest) (*models.CategoryResponse, error) {
|
||
|
|
// Check if category with same name exists for this organization
|
||
|
|
exists, err := p.categoryRepo.ExistsByName(ctx, req.OrganizationID, req.Name, nil)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to check category name uniqueness: %w", err)
|
||
|
|
}
|
||
|
|
if exists {
|
||
|
|
return nil, fmt.Errorf("category with name '%s' already exists for this organization", req.Name)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Map request to entity
|
||
|
|
categoryEntity := mappers.CreateCategoryRequestToEntity(req)
|
||
|
|
|
||
|
|
// Create category
|
||
|
|
if err := p.categoryRepo.Create(ctx, categoryEntity); err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to create category: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Map entity to response model
|
||
|
|
response := mappers.CategoryEntityToResponse(categoryEntity)
|
||
|
|
return response, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (p *CategoryProcessorImpl) UpdateCategory(ctx context.Context, id uuid.UUID, req *models.UpdateCategoryRequest) (*models.CategoryResponse, error) {
|
||
|
|
// Get existing category
|
||
|
|
existingCategory, err := p.categoryRepo.GetByID(ctx, id)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("category not found: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check name uniqueness if name is being updated
|
||
|
|
if req.Name != nil && *req.Name != existingCategory.Name {
|
||
|
|
exists, err := p.categoryRepo.ExistsByName(ctx, existingCategory.OrganizationID, *req.Name, &id)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to check category name uniqueness: %w", err)
|
||
|
|
}
|
||
|
|
if exists {
|
||
|
|
return nil, fmt.Errorf("category with name '%s' already exists for this organization", *req.Name)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Apply updates to entity
|
||
|
|
mappers.UpdateCategoryEntityFromRequest(existingCategory, req)
|
||
|
|
|
||
|
|
// Update category
|
||
|
|
if err := p.categoryRepo.Update(ctx, existingCategory); err != nil {
|
||
|
|
return nil, fmt.Errorf("failed to update category: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Map entity to response model
|
||
|
|
response := mappers.CategoryEntityToResponse(existingCategory)
|
||
|
|
return response, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (p *CategoryProcessorImpl) DeleteCategory(ctx context.Context, id uuid.UUID) error {
|
||
|
|
// Check if category exists
|
||
|
|
_, err := p.categoryRepo.GetByID(ctx, id)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("category not found: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Check if category has products
|
||
|
|
categoryWithProducts, err := p.categoryRepo.GetWithProducts(ctx, id)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("failed to check category products: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(categoryWithProducts.Products) > 0 {
|
||
|
|
return fmt.Errorf("cannot delete category: it has %d products associated with it", len(categoryWithProducts.Products))
|
||
|
|
}
|
||
|
|
|
||
|
|
// Delete category
|
||
|
|
if err := p.categoryRepo.Delete(ctx, id); err != nil {
|
||
|
|
return fmt.Errorf("failed to delete category: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (p *CategoryProcessorImpl) GetCategoryByID(ctx context.Context, id uuid.UUID) (*models.CategoryResponse, error) {
|
||
|
|
categoryEntity, err := p.categoryRepo.GetByID(ctx, id)
|
||
|
|
if err != nil {
|
||
|
|
return nil, fmt.Errorf("category not found: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
response := mappers.CategoryEntityToResponse(categoryEntity)
|
||
|
|
return response, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func (p *CategoryProcessorImpl) ListCategories(ctx context.Context, filters map[string]interface{}, page, limit int) ([]models.CategoryResponse, int, error) {
|
||
|
|
offset := (page - 1) * limit
|
||
|
|
|
||
|
|
categoryEntities, total, err := p.categoryRepo.List(ctx, filters, limit, offset)
|
||
|
|
if err != nil {
|
||
|
|
return nil, 0, fmt.Errorf("failed to list categories: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
responses := make([]models.CategoryResponse, len(categoryEntities))
|
||
|
|
for i, entity := range categoryEntities {
|
||
|
|
response := mappers.CategoryEntityToResponse(entity)
|
||
|
|
if response != nil {
|
||
|
|
responses[i] = *response
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return responses, int(total), nil
|
||
|
|
}
|