apskel-pos-backend/internal/processor/customer_points_processor.go
2025-09-17 19:30:17 +07:00

197 lines
6.1 KiB
Go

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
}