package processor import ( "context" "fmt" "apskel-pos-be/internal/mappers" "apskel-pos-be/internal/models" "apskel-pos-be/internal/repository" "github.com/google/uuid" ) type ProductVariantProcessor interface { CreateProductVariant(ctx context.Context, req *models.CreateProductVariantRequest) (*models.ProductVariantResponse, error) UpdateProductVariant(ctx context.Context, id uuid.UUID, req *models.UpdateProductVariantRequest) (*models.ProductVariantResponse, error) DeleteProductVariant(ctx context.Context, id uuid.UUID) error GetProductVariantByID(ctx context.Context, id uuid.UUID) (*models.ProductVariantResponse, error) GetProductVariantsByProductID(ctx context.Context, productID uuid.UUID) ([]models.ProductVariantResponse, error) } type ProductVariantProcessorImpl struct { productVariantRepo repository.ProductVariantRepository productRepo ProductRepository } func NewProductVariantProcessorImpl( productVariantRepo repository.ProductVariantRepository, productRepo ProductRepository, ) *ProductVariantProcessorImpl { return &ProductVariantProcessorImpl{ productVariantRepo: productVariantRepo, productRepo: productRepo, } } func (p *ProductVariantProcessorImpl) CreateProductVariant(ctx context.Context, req *models.CreateProductVariantRequest) (*models.ProductVariantResponse, error) { // Validate product exists _, err := p.productRepo.GetByID(ctx, req.ProductID) if err != nil { return nil, fmt.Errorf("invalid product: %w", err) } // Check name uniqueness within the same product exists, err := p.productVariantRepo.ExistsByName(ctx, req.ProductID, req.Name, nil) if err != nil { return nil, fmt.Errorf("failed to check variant name uniqueness: %w", err) } if exists { return nil, fmt.Errorf("variant with name '%s' already exists for this product", req.Name) } // Map request to entity variantEntity := mappers.CreateProductVariantRequestToEntity(req) // Create variant if err := p.productVariantRepo.Create(ctx, variantEntity); err != nil { return nil, fmt.Errorf("failed to create product variant: %w", err) } // Map entity to response model response := mappers.ProductVariantEntityToResponse(variantEntity) return response, nil } func (p *ProductVariantProcessorImpl) UpdateProductVariant(ctx context.Context, id uuid.UUID, req *models.UpdateProductVariantRequest) (*models.ProductVariantResponse, error) { // Get existing variant existingVariant, err := p.productVariantRepo.GetByID(ctx, id) if err != nil { return nil, fmt.Errorf("product variant not found: %w", err) } // Check name uniqueness if being updated if req.Name != nil && *req.Name != existingVariant.Name { exists, err := p.productVariantRepo.ExistsByName(ctx, existingVariant.ProductID, *req.Name, &id) if err != nil { return nil, fmt.Errorf("failed to check variant name uniqueness: %w", err) } if exists { return nil, fmt.Errorf("variant with name '%s' already exists for this product", *req.Name) } } // Apply updates to entity mappers.UpdateProductVariantEntityFromRequest(existingVariant, req) // Update variant if err := p.productVariantRepo.Update(ctx, existingVariant); err != nil { return nil, fmt.Errorf("failed to update product variant: %w", err) } // Map entity to response model response := mappers.ProductVariantEntityToResponse(existingVariant) return response, nil } func (p *ProductVariantProcessorImpl) DeleteProductVariant(ctx context.Context, id uuid.UUID) error { // Check if variant exists _, err := p.productVariantRepo.GetByID(ctx, id) if err != nil { return fmt.Errorf("product variant not found: %w", err) } // TODO: Check if variant is used in any order items before deletion // This would require checking the order_items table // Delete variant if err := p.productVariantRepo.Delete(ctx, id); err != nil { return fmt.Errorf("failed to delete product variant: %w", err) } return nil } func (p *ProductVariantProcessorImpl) GetProductVariantByID(ctx context.Context, id uuid.UUID) (*models.ProductVariantResponse, error) { variant, err := p.productVariantRepo.GetByID(ctx, id) if err != nil { return nil, fmt.Errorf("product variant not found: %w", err) } response := mappers.ProductVariantEntityToResponse(variant) return response, nil } func (p *ProductVariantProcessorImpl) GetProductVariantsByProductID(ctx context.Context, productID uuid.UUID) ([]models.ProductVariantResponse, error) { variants, err := p.productVariantRepo.GetByProductID(ctx, productID) if err != nil { return nil, fmt.Errorf("failed to get product variants: %w", err) } responses := make([]models.ProductVariantResponse, len(variants)) for i, variant := range variants { response := mappers.ProductVariantEntityToResponse(variant) responses[i] = *response } return responses, nil }