244 lines
6.8 KiB
Go
244 lines
6.8 KiB
Go
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
|
|
}
|