139 lines
4.7 KiB
Go
139 lines
4.7 KiB
Go
|
|
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
|
||
|
|
}
|