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 CustomerProcessor struct { customerRepo *repository.CustomerRepository } func NewCustomerProcessor(customerRepo *repository.CustomerRepository) *CustomerProcessor { return &CustomerProcessor{ customerRepo: customerRepo, } } // CreateCustomer creates a new customer func (p *CustomerProcessor) CreateCustomer(ctx context.Context, req *models.CreateCustomerRequest, organizationID uuid.UUID) (*models.CustomerResponse, error) { if req.Email != nil { existingCustomer, err := p.customerRepo.GetByEmail(ctx, *req.Email, organizationID) if err == nil && existingCustomer != nil { return nil, errors.New("email already exists for this organization") } } // Convert request to entity customer := mappers.ToCustomerEntity(req, organizationID) // Create customer err := p.customerRepo.Create(ctx, customer) if err != nil { return nil, fmt.Errorf("failed to create customer: %w", err) } return mappers.ToCustomerResponse(customer), nil } // GetCustomer retrieves a customer by ID func (p *CustomerProcessor) GetCustomer(ctx context.Context, customerID, organizationID uuid.UUID) (*models.CustomerResponse, error) { customer, err := p.customerRepo.GetByIDAndOrganization(ctx, customerID, organizationID) if err != nil { return nil, fmt.Errorf("customer not found: %w", err) } return mappers.ToCustomerResponse(customer), nil } // ListCustomers retrieves customers with pagination and filtering func (p *CustomerProcessor) ListCustomers(ctx context.Context, query *models.ListCustomersQuery, organizationID uuid.UUID) (*models.PaginatedResponse[models.CustomerResponse], 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 customers from repository customers, total, err := p.customerRepo.List( ctx, organizationID, offset, query.Limit, query.Search, query.IsActive, query.IsDefault, query.SortBy, query.SortOrder, ) if err != nil { return nil, fmt.Errorf("failed to list customers: %w", err) } // Convert to responses responses := mappers.ToCustomerResponses(customers) // Calculate pagination info totalPages := int((total + int64(query.Limit) - 1) / int64(query.Limit)) return &models.PaginatedResponse[models.CustomerResponse]{ Data: responses, Pagination: models.Pagination{ Page: query.Page, Limit: query.Limit, Total: total, TotalPages: totalPages, }, }, nil } // UpdateCustomer updates an existing customer func (p *CustomerProcessor) UpdateCustomer(ctx context.Context, customerID, organizationID uuid.UUID, req *models.UpdateCustomerRequest) (*models.CustomerResponse, error) { // Get existing customer customer, err := p.customerRepo.GetByIDAndOrganization(ctx, customerID, organizationID) if err != nil { return nil, fmt.Errorf("customer not found: %w", err) } // Check if email is already taken by another customer within the organization if req.Email != nil && *req.Email != *customer.Email { existingCustomer, err := p.customerRepo.GetByEmail(ctx, *req.Email, organizationID) if err == nil && existingCustomer != nil && existingCustomer.ID != customerID { return nil, errors.New("email already exists for this organization") } } // Update customer fields mappers.UpdateCustomerEntity(customer, req) // Save updated customer err = p.customerRepo.Update(ctx, customer) if err != nil { return nil, fmt.Errorf("failed to update customer: %w", err) } return mappers.ToCustomerResponse(customer), nil } // DeleteCustomer deletes a customer func (p *CustomerProcessor) DeleteCustomer(ctx context.Context, customerID, organizationID uuid.UUID) error { // Get existing customer customer, err := p.customerRepo.GetByIDAndOrganization(ctx, customerID, organizationID) if err != nil { return fmt.Errorf("customer not found: %w", err) } // Prevent deletion of default customer if customer.IsDefault { return errors.New("cannot delete default customer") } // Delete customer err = p.customerRepo.Delete(ctx, customerID) if err != nil { return fmt.Errorf("failed to delete customer: %w", err) } return nil } func (p *CustomerProcessor) SetDefaultCustomer(ctx context.Context, customerID, organizationID uuid.UUID) (*models.CustomerResponse, error) { _, err := p.customerRepo.GetByIDAndOrganization(ctx, customerID, organizationID) if err != nil { return nil, fmt.Errorf("customer not found: %w", err) } // Set as default err = p.customerRepo.SetAsDefault(ctx, customerID, organizationID) if err != nil { return nil, fmt.Errorf("failed to set default customer: %w", err) } // Get updated customer updatedCustomer, err := p.customerRepo.GetByID(ctx, customerID) if err != nil { return nil, fmt.Errorf("failed to get updated customer: %w", err) } return mappers.ToCustomerResponse(updatedCustomer), nil } func (p *CustomerProcessor) GetDefaultCustomer(ctx context.Context, organizationID uuid.UUID) (*models.CustomerResponse, error) { customer, err := p.customerRepo.GetDefaultCustomer(ctx, organizationID) if err != nil { return nil, fmt.Errorf("default customer not found: %w", err) } return mappers.ToCustomerResponse(customer), nil } func (p *CustomerProcessor) EnsureDefaultCustomer(ctx context.Context, organizationID uuid.UUID) (*models.CustomerResponse, error) { customer, err := p.customerRepo.GetDefaultCustomer(ctx, organizationID) if err == nil { return mappers.ToCustomerResponse(customer), nil } defaultCustomer, err := p.customerRepo.CreateDefaultCustomer(ctx, organizationID) if err != nil { return nil, fmt.Errorf("failed to create default customer: %w", err) } return mappers.ToCustomerResponse(defaultCustomer), nil }