diff --git a/apps/carrier-connector/internal/services/rateplan_methods.go b/apps/carrier-connector/internal/services/rateplan_methods.go index c05dc9f..94e7ddf 100644 --- a/apps/carrier-connector/internal/services/rateplan_methods.go +++ b/apps/carrier-connector/internal/services/rateplan_methods.go @@ -7,6 +7,7 @@ import ( "github.com/sirupsen/logrus" + "github.com/nutcas3/telecom-platform/apps/carrier-connector/internal/currency" "github.com/nutcas3/telecom-platform/apps/carrier-connector/internal/rateplan" ) @@ -21,7 +22,12 @@ func (rpci *RatePlanCurrencyIntegrator) GetPlansInCurrency(ctx context.Context, // Convert prices to target currency for _, plan := range plans { if plan.Currency != targetCurrency { - conversion, err := rpci.exchangeService.ConvertAmount(ctx, plan.BasePrice, plan.Currency, targetCurrency) + conversionReq := ¤cy.CurrencyConversionRequest{ + Amount: plan.BasePrice, + FromCurrency: plan.Currency, + ToCurrency: targetCurrency, + } + conversion, err := rpci.billingService.ConvertAmount(ctx, conversionReq) if err != nil { rpci.logger.WithError(err).WithFields(logrus.Fields{ "plan_id": plan.ID, @@ -60,7 +66,11 @@ func (rpci *RatePlanCurrencyIntegrator) UpdatePlanCurrency(ctx context.Context, } // Convert all monetary values to new currency - convertedPrice, err := rpci.exchangeService.ConvertAmount(ctx, plan.BasePrice, plan.Currency, newCurrency) + convertedPrice, err := rpci.billingService.ConvertAmount(ctx, ¤cy.CurrencyConversionRequest{ + Amount: plan.BasePrice, + FromCurrency: plan.Currency, + ToCurrency: newCurrency, + }) if err != nil { return fmt.Errorf("failed to convert base price: %w", err) } @@ -99,37 +109,6 @@ func (rpci *RatePlanCurrencyIntegrator) UpdatePlanCurrency(ctx context.Context, return nil } -// calculateOverageCost calculates overage costs for usage -func (rpci *RatePlanCurrencyIntegrator) calculateOverageCost(ctx context.Context, plan *rateplan.RatePlan, usage *rateplan.RatePlanUsage) (float64, error) { - overageCost := 0.0 - - // Calculate data overage - if plan.DataAllowance != nil && usage.DataUsed > plan.DataAllowance.Amount { - dataOverage := usage.DataUsed - plan.DataAllowance.Amount - if plan.OverageRates != nil { - overageCost += float64(dataOverage) * plan.OverageRates.DataRate - } - } - - // Calculate voice overage - if plan.VoiceAllowance != nil && usage.VoiceUsed > plan.VoiceAllowance.Minutes { - voiceOverage := usage.VoiceUsed - plan.VoiceAllowance.Minutes - if plan.OverageRates != nil { - overageCost += float64(voiceOverage) * plan.OverageRates.VoiceRate - } - } - - // Calculate SMS overage - if plan.SMSAllowance != nil && usage.SMSUsed > plan.SMSAllowance.Messages { - smsOverage := usage.SMSUsed - plan.SMSAllowance.Messages - if plan.OverageRates != nil { - overageCost += float64(smsOverage) * plan.OverageRates.SMSRate - } - } - - return overageCost, nil -} - // GetCurrencyUsageForPlan gets currency usage statistics for a specific rate plan func (rpci *RatePlanCurrencyIntegrator) GetCurrencyUsageForPlan(ctx context.Context, planID string) (map[string]int64, error) { // Get all subscriptions for this plan diff --git a/apps/carrier-connector/internal/services/tenant_core.go b/apps/carrier-connector/internal/services/tenant_core.go index 883fbd9..a8dc2fc 100644 --- a/apps/carrier-connector/internal/services/tenant_core.go +++ b/apps/carrier-connector/internal/services/tenant_core.go @@ -45,7 +45,7 @@ func (s *TenantServiceImpl) CreateTenant(ctx context.Context, req *tenant.Create } // Create tenant - tenant := &tenant.Tenant{ + newTenant := &tenant.Tenant{ ID: uuid.New().String(), Name: req.Name, Domain: req.Domain, @@ -61,21 +61,21 @@ func (s *TenantServiceImpl) CreateTenant(ctx context.Context, req *tenant.Create } // Set default settings if not provided - if tenant.Settings == nil { - tenant.Settings = s.getDefaultSettings(req.Plan) + if newTenant.Settings == nil { + newTenant.Settings = s.getDefaultSettings(req.Plan) } // Save tenant - if err := s.repository.CreateTenant(ctx, tenant); err != nil { + if err := s.repository.CreateTenant(ctx, newTenant); err != nil { s.logger.WithError(err).Error("Failed to create tenant") return nil, fmt.Errorf("failed to create tenant: %w", err) } // Create initial configuration config := &tenant.TenantConfig{ - TenantID: tenant.ID, + TenantID: newTenant.ID, Config: make(map[string]interface{}), - Settings: tenant.Settings, + Settings: newTenant.Settings, Quotas: s.getDefaultQuotas(req.Plan), Features: s.getDefaultFeatures(req.Plan), } @@ -85,12 +85,12 @@ func (s *TenantServiceImpl) CreateTenant(ctx context.Context, req *tenant.Create } s.logger.WithFields(logrus.Fields{ - "tenant_id": tenant.ID, - "name": tenant.Name, - "domain": tenant.Domain, + "tenant_id": newTenant.ID, + "name": newTenant.Name, + "domain": newTenant.Domain, }).Info("Tenant created successfully") - return tenant, nil + return newTenant, nil } // GetTenant retrieves a tenant by ID diff --git a/apps/carrier-connector/internal/services/tenant_user.go b/apps/carrier-connector/internal/services/tenant_user.go index 64090d9..5b48058 100644 --- a/apps/carrier-connector/internal/services/tenant_user.go +++ b/apps/carrier-connector/internal/services/tenant_user.go @@ -3,191 +3,10 @@ package services import ( "context" "errors" - "fmt" - "time" - "github.com/google/uuid" "github.com/nutcas3/telecom-platform/apps/carrier-connector/internal/tenant" - "github.com/sirupsen/logrus" ) -// AddUserToTenant adds a user to a tenant -func (s *TenantServiceImpl) AddUserToTenant(ctx context.Context, req *tenant.CreateTenantUserRequest) (*tenant.TenantUser, error) { - // Validate request - if err := s.validateCreateTenantUserRequest(req); err != nil { - return nil, fmt.Errorf("validation failed: %w", err) - } - - // Check if user already exists - existing, err := s.repository.GetTenantUser(ctx, req.TenantID, req.UserID) - if err == nil && existing != nil { - return nil, errors.New("user already exists in tenant") - } - - // Create tenant user - tenantUser := &tenant.TenantUser{ - ID: uuid.New().String(), - TenantID: req.TenantID, - UserID: req.UserID, - Email: req.Email, - Role: req.Role, - Status: tenant.TenantUserStatusActive, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - } - - // Save tenant user - if err := s.repository.CreateTenantUser(ctx, tenantUser); err != nil { - s.logger.WithError(err).Error("Failed to create tenant user") - return nil, fmt.Errorf("failed to add user to tenant: %w", err) - } - - s.logger.WithFields(logrus.Fields{ - "tenant_id": req.TenantID, - "user_id": req.UserID, - "role": req.Role, - }).Info("User added to tenant successfully") - - return tenantUser, nil -} - -// GetTenantUser retrieves a tenant user -func (s *TenantServiceImpl) GetTenantUser(ctx context.Context, tenantID, userID string) (*tenant.TenantUser, error) { - user, err := s.repository.GetTenantUser(ctx, tenantID, userID) - if err != nil { - s.logger.WithError(err).WithFields(logrus.Fields{ - "tenant_id": tenantID, - "user_id": userID, - }).Error("Failed to get tenant user") - return nil, err - } - - return user, nil -} - -// UpdateTenantUser updates a tenant user -func (s *TenantServiceImpl) UpdateTenantUser(ctx context.Context, tenantID, userID string, req *tenant.UpdateTenantUserRequest) (*tenant.TenantUser, error) { - // Get existing user - user, err := s.repository.GetTenantUser(ctx, tenantID, userID) - if err != nil { - return nil, err - } - - // Apply updates - if req.Role != nil { - user.Role = *req.Role - } - if req.Status != nil { - user.Status = *req.Status - } - - user.UpdatedAt = time.Now() - - // Save user - if err := s.repository.UpdateTenantUser(ctx, user); err != nil { - s.logger.WithError(err).Error("Failed to update tenant user") - return nil, fmt.Errorf("failed to update tenant user: %w", err) - } - - s.logger.WithFields(logrus.Fields{ - "tenant_id": tenantID, - "user_id": userID, - }).Info("Tenant user updated successfully") - - return user, nil -} - -// RemoveUserFromTenant removes a user from a tenant -func (s *TenantServiceImpl) RemoveUserFromTenant(ctx context.Context, tenantID, userID string) error { - // Delete tenant user - if err := s.repository.DeleteTenantUser(ctx, tenantID, userID); err != nil { - s.logger.WithError(err).Error("Failed to remove user from tenant") - return fmt.Errorf("failed to remove user from tenant: %w", err) - } - - s.logger.WithFields(logrus.Fields{ - "tenant_id": tenantID, - "user_id": userID, - }).Info("User removed from tenant successfully") - - return nil -} - -// ListTenantUsers lists tenant users with filtering -func (s *TenantServiceImpl) ListTenantUsers(ctx context.Context, filter *tenant.TenantUserFilter) ([]*tenant.TenantUser, error) { - users, err := s.repository.ListTenantUsers(ctx, filter) - if err != nil { - s.logger.WithError(err).Error("Failed to list tenant users") - return nil, err - } - - return users, nil -} - -// ValidateTenantAccess validates tenant access -func (s *TenantServiceImpl) ValidateTenantAccess(ctx context.Context, tenantID, userID string) (*tenant.TenantContext, error) { - // Get tenant - tenant, err := s.repository.GetTenant(ctx, tenantID) - if err != nil { - return nil, fmt.Errorf("tenant not found: %w", err) - } - - // Check tenant status - if tenant.Status != "active" { - return nil, fmt.Errorf("tenant is not active") - } - - // Get user - user, err := s.repository.GetTenantUser(ctx, tenantID, userID) - if err != nil { - return nil, fmt.Errorf("user not found in tenant: %w", err) - } - - // Check user status - if user.Status != "active" { - return nil, fmt.Errorf("user is not active") - } - - // Create context - context := &tenant.TenantContext{ - TenantID: tenantID, - UserID: userID, - Tenant: tenant, - User: user, - Roles: []string{string(user.Role)}, - Permissions: []string{}, - Settings: tenant.Settings, - Quotas: []tenant.ResourceQuota{}, - Features: map[string]bool{}, - } - - return context, nil -} - -// GetTenantContext retrieves tenant context -func (s *TenantServiceImpl) GetTenantContext(ctx context.Context, tenantID string) (*tenant.TenantContext, error) { - // Get tenant - tenant, err := s.repository.GetTenant(ctx, tenantID) - if err != nil { - return nil, fmt.Errorf("tenant not found: %w", err) - } - - // Create context with basic tenant info - context := &tenant.TenantContext{ - TenantID: tenantID, - UserID: "", - Tenant: tenant, - User: nil, - Roles: []string{}, - Permissions: []string{}, - Settings: tenant.Settings, - Quotas: []tenant.ResourceQuota{}, - Features: map[string]bool{}, - } - - return context, nil -} - // HasPermission checks if user has permission func (s *TenantServiceImpl) HasPermission(ctx context.Context, tenantID, userID, permission string) (bool, error) { // Get tenant user @@ -209,7 +28,6 @@ func (s *TenantServiceImpl) HasPermission(ctx context.Context, tenantID, userID, } } -// Helper methods func (s *TenantServiceImpl) validateCreateTenantUserRequest(req *tenant.CreateTenantUserRequest) error { if req.TenantID == "" { return errors.New("tenant ID is required") diff --git a/apps/carrier-connector/internal/services/tenant_user_methods.go b/apps/carrier-connector/internal/services/tenant_user_methods.go new file mode 100644 index 0000000..44d7271 --- /dev/null +++ b/apps/carrier-connector/internal/services/tenant_user_methods.go @@ -0,0 +1,184 @@ +package services + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/google/uuid" + "github.com/nutcas3/telecom-platform/apps/carrier-connector/internal/tenant" + "github.com/sirupsen/logrus" +) + +// AddUserToTenant adds a user to a tenant +func (s *TenantServiceImpl) AddUserToTenant(ctx context.Context, req *tenant.CreateTenantUserRequest) (*tenant.TenantUser, error) { + // Validate request + if err := s.validateCreateTenantUserRequest(req); err != nil { + return nil, fmt.Errorf("validation failed: %w", err) + } + + // Check if user already exists + existing, err := s.repository.GetTenantUser(ctx, req.TenantID, req.UserID) + if err == nil && existing != nil { + return nil, errors.New("user already exists in tenant") + } + + // Create tenant user + tenantUser := &tenant.TenantUser{ + ID: uuid.New().String(), + TenantID: req.TenantID, + UserID: req.UserID, + Email: req.Email, + Role: req.Role, + Status: tenant.TenantUserStatusActive, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + + // Save tenant user + if err := s.repository.CreateTenantUser(ctx, tenantUser); err != nil { + s.logger.WithError(err).Error("Failed to create tenant user") + return nil, fmt.Errorf("failed to add user to tenant: %w", err) + } + + s.logger.WithFields(logrus.Fields{ + "tenant_id": req.TenantID, + "user_id": req.UserID, + "role": req.Role, + }).Info("User added to tenant successfully") + + return tenantUser, nil +} + +// GetTenantUser retrieves a tenant user +func (s *TenantServiceImpl) GetTenantUser(ctx context.Context, tenantID, userID string) (*tenant.TenantUser, error) { + user, err := s.repository.GetTenantUser(ctx, tenantID, userID) + if err != nil { + s.logger.WithError(err).WithFields(logrus.Fields{ + "tenant_id": tenantID, + "user_id": userID, + }).Error("Failed to get tenant user") + return nil, err + } + + return user, nil +} + +// UpdateTenantUser updates a tenant user +func (s *TenantServiceImpl) UpdateTenantUser(ctx context.Context, tenantID, userID string, req *tenant.UpdateTenantUserRequest) (*tenant.TenantUser, error) { + // Get existing user + user, err := s.repository.GetTenantUser(ctx, tenantID, userID) + if err != nil { + return nil, err + } + + // Apply updates + if req.Role != nil { + user.Role = *req.Role + } + if req.Status != nil { + user.Status = *req.Status + } + + user.UpdatedAt = time.Now() + + // Save user + if err := s.repository.UpdateTenantUser(ctx, user); err != nil { + s.logger.WithError(err).Error("Failed to update tenant user") + return nil, fmt.Errorf("failed to update tenant user: %w", err) + } + + s.logger.WithFields(logrus.Fields{ + "tenant_id": tenantID, + "user_id": userID, + }).Info("Tenant user updated successfully") + + return user, nil +} + +// RemoveUserFromTenant removes a user from a tenant +func (s *TenantServiceImpl) RemoveUserFromTenant(ctx context.Context, tenantID, userID string) error { + // Delete tenant user + if err := s.repository.DeleteTenantUser(ctx, tenantID, userID); err != nil { + s.logger.WithError(err).Error("Failed to remove user from tenant") + return fmt.Errorf("failed to remove user from tenant: %w", err) + } + + s.logger.WithFields(logrus.Fields{ + "tenant_id": tenantID, + "user_id": userID, + }).Info("User removed from tenant successfully") + + return nil +} + +// ListTenantUsers lists tenant users with filtering +func (s *TenantServiceImpl) ListTenantUsers(ctx context.Context, filter *tenant.TenantUserFilter) ([]*tenant.TenantUser, error) { + users, err := s.repository.ListTenantUsers(ctx, filter) + if err != nil { + s.logger.WithError(err).Error("Failed to list tenant users") + return nil, err + } + + return users, nil +} + +// ValidateTenantAccess validates tenant access +func (s *TenantServiceImpl) ValidateTenantAccess(ctx context.Context, tenantID, userID string) (*tenant.TenantContext, error) { + // Get tenant + tenantRecord, err := s.repository.GetTenant(ctx, tenantID) + if err != nil { + return nil, fmt.Errorf("tenant not found: %w", err) + } + + // Check tenant status + if tenantRecord.Status != "active" { + return nil, fmt.Errorf("tenant is not active") + } + + // Get user + user, err := s.repository.GetTenantUser(ctx, tenantID, userID) + if err != nil { + return nil, fmt.Errorf("user not found in tenant: %w", err) + } + + // Check user status + if user.Status != "active" { + return nil, fmt.Errorf("user is not active") + } + + // Create context + tenantCtx := &tenant.TenantContext{ + TenantID: tenantID, + TenantName: tenantRecord.Name, + Plan: tenantRecord.Plan, + UserID: userID, + UserRole: user.Role, + Settings: tenantRecord.Settings, + Metadata: tenantRecord.Metadata, + } + + return tenantCtx, nil +} + +// GetTenantContext retrieves tenant context +func (s *TenantServiceImpl) GetTenantContext(ctx context.Context, tenantID string) (*tenant.TenantContext, error) { + // Get tenant + tenantRecord, err := s.repository.GetTenant(ctx, tenantID) + if err != nil { + return nil, fmt.Errorf("tenant not found: %w", err) + } + + // Create context with basic tenant info + tenantCtx := &tenant.TenantContext{ + TenantID: tenantID, + TenantName: tenantRecord.Name, + Plan: tenantRecord.Plan, + UserID: "", + Settings: tenantRecord.Settings, + Metadata: tenantRecord.Metadata, + } + + return tenantCtx, nil +}