apskel-pos-backend/internal/processor/customer_processor.go

196 lines
5.8 KiB
Go
Raw Normal View History

2025-07-18 20:10:29 +07:00
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
}