package processor import ( "apskel-pos-be/internal/mappers" "apskel-pos-be/internal/models" "apskel-pos-be/internal/repository" "context" "errors" "fmt" "github.com/google/uuid" ) type CustomerPointsProcessor struct { customerPointsRepo *repository.CustomerPointsRepository } func NewCustomerPointsProcessor(customerPointsRepo *repository.CustomerPointsRepository) *CustomerPointsProcessor { return &CustomerPointsProcessor{ customerPointsRepo: customerPointsRepo, } } // CreateCustomerPoints creates a new customer points record func (p *CustomerPointsProcessor) CreateCustomerPoints(ctx context.Context, req *models.CreateCustomerPointsRequest) (*models.CustomerPointsResponse, error) { // Convert request to entity customerPoints := mappers.ToCustomerPointsEntity(req) // Create customer points err := p.customerPointsRepo.Create(ctx, customerPoints) if err != nil { return nil, fmt.Errorf("failed to create customer points: %w", err) } return mappers.ToCustomerPointsResponse(customerPoints), nil } // GetCustomerPoints retrieves customer points by ID func (p *CustomerPointsProcessor) GetCustomerPoints(ctx context.Context, id uuid.UUID) (*models.CustomerPointsResponse, error) { customerPoints, err := p.customerPointsRepo.GetByID(ctx, id) if err != nil { return nil, fmt.Errorf("customer points not found: %w", err) } return mappers.ToCustomerPointsResponse(customerPoints), nil } // GetCustomerPointsByCustomerID retrieves customer points by customer ID func (p *CustomerPointsProcessor) GetCustomerPointsByCustomerID(ctx context.Context, customerID uuid.UUID) (*models.CustomerPointsResponse, error) { customerPoints, err := p.customerPointsRepo.EnsureCustomerPoints(ctx, customerID) if err != nil { return nil, fmt.Errorf("failed to get customer points: %w", err) } return mappers.ToCustomerPointsResponse(customerPoints), nil } // ListCustomerPoints retrieves customer points with pagination and filtering func (p *CustomerPointsProcessor) ListCustomerPoints(ctx context.Context, query *models.ListCustomerPointsQuery) (*models.PaginatedResponse[models.CustomerPointsResponse], error) { // Set default values if query.Page <= 0 { query.Page = 1 } if query.Limit <= 0 { query.Limit = 10 } if query.Limit > 100 { query.Limit = 100 } offset := (query.Page - 1) * query.Limit // Get customer points from repository customerPoints, total, err := p.customerPointsRepo.List( ctx, offset, query.Limit, query.Search, query.SortBy, query.SortOrder, ) if err != nil { return nil, fmt.Errorf("failed to list customer points: %w", err) } // Convert to responses responses := mappers.ToCustomerPointsResponses(customerPoints) // Calculate pagination info totalPages := int((total + int64(query.Limit) - 1) / int64(query.Limit)) return &models.PaginatedResponse[models.CustomerPointsResponse]{ Data: responses, Pagination: models.Pagination{ Page: query.Page, Limit: query.Limit, Total: total, TotalPages: totalPages, }, }, nil } // UpdateCustomerPoints updates an existing customer points record func (p *CustomerPointsProcessor) UpdateCustomerPoints(ctx context.Context, id uuid.UUID, req *models.UpdateCustomerPointsRequest) (*models.CustomerPointsResponse, error) { // Get existing customer points customerPoints, err := p.customerPointsRepo.GetByID(ctx, id) if err != nil { return nil, fmt.Errorf("customer points not found: %w", err) } // Update customer points fields mappers.UpdateCustomerPointsEntity(customerPoints, req) // Save updated customer points err = p.customerPointsRepo.Update(ctx, customerPoints) if err != nil { return nil, fmt.Errorf("failed to update customer points: %w", err) } return mappers.ToCustomerPointsResponse(customerPoints), nil } // DeleteCustomerPoints deletes a customer points record func (p *CustomerPointsProcessor) DeleteCustomerPoints(ctx context.Context, id uuid.UUID) error { // Get existing customer points _, err := p.customerPointsRepo.GetByID(ctx, id) if err != nil { return fmt.Errorf("customer points not found: %w", err) } // Delete customer points err = p.customerPointsRepo.Delete(ctx, id) if err != nil { return fmt.Errorf("failed to delete customer points: %w", err) } return nil } // AddPoints adds points to a customer's balance func (p *CustomerPointsProcessor) AddPoints(ctx context.Context, customerID uuid.UUID, points int64) (*models.CustomerPointsResponse, error) { if points <= 0 { return nil, errors.New("points must be greater than 0") } // Ensure customer points record exists _, err := p.customerPointsRepo.EnsureCustomerPoints(ctx, customerID) if err != nil { return nil, fmt.Errorf("failed to ensure customer points: %w", err) } // Add points err = p.customerPointsRepo.AddPoints(ctx, customerID, points) if err != nil { return nil, fmt.Errorf("failed to add points: %w", err) } // Get updated customer points customerPoints, err := p.customerPointsRepo.GetByCustomerID(ctx, customerID) if err != nil { return nil, fmt.Errorf("failed to get updated customer points: %w", err) } return mappers.ToCustomerPointsResponse(customerPoints), nil } // DeductPoints deducts points from a customer's balance func (p *CustomerPointsProcessor) DeductPoints(ctx context.Context, customerID uuid.UUID, points int64) (*models.CustomerPointsResponse, error) { if points <= 0 { return nil, errors.New("points must be greater than 0") } // Get current customer points customerPoints, err := p.customerPointsRepo.GetByCustomerID(ctx, customerID) if err != nil { return nil, fmt.Errorf("customer points not found: %w", err) } if customerPoints.Balance < points { return nil, errors.New("insufficient points balance") } // Deduct points err = p.customerPointsRepo.DeductPoints(ctx, customerID, points) if err != nil { return nil, fmt.Errorf("failed to deduct points: %w", err) } // Get updated customer points updatedCustomerPoints, err := p.customerPointsRepo.GetByCustomerID(ctx, customerID) if err != nil { return nil, fmt.Errorf("failed to get updated customer points: %w", err) } return mappers.ToCustomerPointsResponse(updatedCustomerPoints), nil }