package service import ( "context" "fmt" "apskel-pos-be/internal/models" "apskel-pos-be/internal/processor" "github.com/google/uuid" ) type AnalyticsService interface { GetPaymentMethodAnalytics(ctx context.Context, req *models.PaymentMethodAnalyticsRequest) (*models.PaymentMethodAnalyticsResponse, error) GetSalesAnalytics(ctx context.Context, req *models.SalesAnalyticsRequest) (*models.SalesAnalyticsResponse, error) GetProductAnalytics(ctx context.Context, req *models.ProductAnalyticsRequest) (*models.ProductAnalyticsResponse, error) GetDashboardAnalytics(ctx context.Context, req *models.DashboardAnalyticsRequest) (*models.DashboardAnalyticsResponse, error) GetProfitLossAnalytics(ctx context.Context, req *models.ProfitLossAnalyticsRequest) (*models.ProfitLossAnalyticsResponse, error) } type AnalyticsServiceImpl struct { analyticsProcessor processor.AnalyticsProcessor } func NewAnalyticsServiceImpl(analyticsProcessor processor.AnalyticsProcessor) *AnalyticsServiceImpl { return &AnalyticsServiceImpl{ analyticsProcessor: analyticsProcessor, } } func (s *AnalyticsServiceImpl) GetPaymentMethodAnalytics(ctx context.Context, req *models.PaymentMethodAnalyticsRequest) (*models.PaymentMethodAnalyticsResponse, error) { // Validate request if err := s.validatePaymentMethodAnalyticsRequest(req); err != nil { return nil, fmt.Errorf("validation error: %w", err) } // Process analytics request response, err := s.analyticsProcessor.GetPaymentMethodAnalytics(ctx, req) if err != nil { return nil, fmt.Errorf("failed to get payment method analytics: %w", err) } return response, nil } func (s *AnalyticsServiceImpl) GetSalesAnalytics(ctx context.Context, req *models.SalesAnalyticsRequest) (*models.SalesAnalyticsResponse, error) { // Validate request if err := s.validateSalesAnalyticsRequest(req); err != nil { return nil, fmt.Errorf("validation error: %w", err) } // Process analytics request response, err := s.analyticsProcessor.GetSalesAnalytics(ctx, req) if err != nil { return nil, fmt.Errorf("failed to get sales analytics: %w", err) } return response, nil } func (s *AnalyticsServiceImpl) GetProductAnalytics(ctx context.Context, req *models.ProductAnalyticsRequest) (*models.ProductAnalyticsResponse, error) { // Validate request if err := s.validateProductAnalyticsRequest(req); err != nil { return nil, fmt.Errorf("validation error: %w", err) } // Process analytics request response, err := s.analyticsProcessor.GetProductAnalytics(ctx, req) if err != nil { return nil, fmt.Errorf("failed to get product analytics: %w", err) } return response, nil } func (s *AnalyticsServiceImpl) GetDashboardAnalytics(ctx context.Context, req *models.DashboardAnalyticsRequest) (*models.DashboardAnalyticsResponse, error) { // Validate request if err := s.validateDashboardAnalyticsRequest(req); err != nil { return nil, fmt.Errorf("validation error: %w", err) } // Process analytics request response, err := s.analyticsProcessor.GetDashboardAnalytics(ctx, req) if err != nil { return nil, fmt.Errorf("failed to get dashboard analytics: %w", err) } return response, nil } // Validation methods func (s *AnalyticsServiceImpl) validatePaymentMethodAnalyticsRequest(req *models.PaymentMethodAnalyticsRequest) error { if req.OrganizationID == uuid.Nil { return fmt.Errorf("organization ID is required") } if req.DateFrom.IsZero() { return fmt.Errorf("date_from is required") } if req.DateTo.IsZero() { return fmt.Errorf("date_to is required") } if req.DateFrom.After(req.DateTo) { return fmt.Errorf("date_from cannot be after date_to") } // Validate groupBy if provided if req.GroupBy != "" { validGroupBy := map[string]bool{ "day": true, "hour": true, "week": true, "month": true, } if !validGroupBy[req.GroupBy] { return fmt.Errorf("invalid group_by value: %s", req.GroupBy) } } return nil } func (s *AnalyticsServiceImpl) validateSalesAnalyticsRequest(req *models.SalesAnalyticsRequest) error { if req.OrganizationID == uuid.Nil { return fmt.Errorf("organization ID is required") } if req.DateFrom.IsZero() { return fmt.Errorf("date_from is required") } if req.DateTo.IsZero() { return fmt.Errorf("date_to is required") } if req.DateFrom.After(req.DateTo) { return fmt.Errorf("date_from cannot be after date_to") } // Validate groupBy if provided if req.GroupBy != "" { validGroupBy := map[string]bool{ "day": true, "hour": true, "week": true, "month": true, } if !validGroupBy[req.GroupBy] { return fmt.Errorf("invalid group_by value: %s", req.GroupBy) } } return nil } func (s *AnalyticsServiceImpl) validateProductAnalyticsRequest(req *models.ProductAnalyticsRequest) error { if req.OrganizationID == uuid.Nil { return fmt.Errorf("organization ID is required") } if req.DateFrom.IsZero() { return fmt.Errorf("date_from is required") } if req.DateTo.IsZero() { return fmt.Errorf("date_to is required") } if req.DateFrom.After(req.DateTo) { return fmt.Errorf("date_from cannot be after date_to") } if req.Limit < 1 || req.Limit > 100 { return fmt.Errorf("limit must be between 1 and 100") } return nil } func (s *AnalyticsServiceImpl) validateDashboardAnalyticsRequest(req *models.DashboardAnalyticsRequest) error { if req.OrganizationID == uuid.Nil { return fmt.Errorf("organization ID is required") } if req.DateFrom.IsZero() { return fmt.Errorf("date_from is required") } if req.DateTo.IsZero() { return fmt.Errorf("date_to is required") } if req.DateFrom.After(req.DateTo) { return fmt.Errorf("date_from cannot be after date_to") } return nil } func (s *AnalyticsServiceImpl) GetProfitLossAnalytics(ctx context.Context, req *models.ProfitLossAnalyticsRequest) (*models.ProfitLossAnalyticsResponse, error) { // Validate request if err := s.validateProfitLossAnalyticsRequest(req); err != nil { return nil, fmt.Errorf("validation error: %w", err) } // Call processor response, err := s.analyticsProcessor.GetProfitLossAnalytics(ctx, req) if err != nil { return nil, fmt.Errorf("failed to get profit/loss analytics: %w", err) } return response, nil } func (s *AnalyticsServiceImpl) validateProfitLossAnalyticsRequest(req *models.ProfitLossAnalyticsRequest) error { if req == nil { return fmt.Errorf("request cannot be nil") } if req.OrganizationID == uuid.Nil { return fmt.Errorf("organization_id is required") } if req.DateFrom.IsZero() { return fmt.Errorf("date_from is required") } if req.DateTo.IsZero() { return fmt.Errorf("date_to is required") } if req.DateFrom.After(req.DateTo) { return fmt.Errorf("date_from cannot be after date_to") } if req.GroupBy != "" && req.GroupBy != "hour" && req.GroupBy != "day" && req.GroupBy != "week" && req.GroupBy != "month" { return fmt.Errorf("invalid group_by value, must be one of: hour, day, week, month") } return nil }