mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-25 14:12:16 +00:00
- Move calculateElasticity, calculateCompetitiveIndex, and calculateOptimizationROI to optimization_opt_service.go - Move generateAnalysis, calculateConfidence, and calculateChurnRate to optimization_opt_service.go - Simplify calculatePriceElasticity by removing comments and consolidating logic - Simplify optimizeForRevenue, optimizeForMarketShare, optimizeForProfitMargin, optimizeForCompetitive, and optimizeForChurn
212 lines
6.6 KiB
Go
212 lines
6.6 KiB
Go
package pricing
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// OptimizationStrategy represents pricing optimization strategies
|
|
type OptimizationStrategy string
|
|
|
|
const (
|
|
StrategyRevenueMax OptimizationStrategy = "revenue_maximization"
|
|
StrategyMarketShare OptimizationStrategy = "market_share"
|
|
StrategyProfitMargin OptimizationStrategy = "profit_margin"
|
|
StrategyCompetitive OptimizationStrategy = "competitive"
|
|
StrategyChurnReduction OptimizationStrategy = "churn_reduction"
|
|
)
|
|
|
|
// PricingOptimizationService provides automated pricing optimization
|
|
type PricingOptimizationService struct {
|
|
db *gorm.DB
|
|
logger *logrus.Logger
|
|
}
|
|
|
|
// NewPricingOptimizationService creates a new pricing optimization service
|
|
func NewPricingOptimizationService(db *gorm.DB, logger *logrus.Logger) *PricingOptimizationService {
|
|
return &PricingOptimizationService{
|
|
db: db,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
// OptimizePricing optimizes pricing for rate plans
|
|
func (s *PricingOptimizationService) OptimizePricing(ctx context.Context, ratePlanIDs []string, strategy OptimizationStrategy) ([]*OptimizationResult, error) {
|
|
results := make([]*OptimizationResult, 0)
|
|
|
|
for _, ratePlanID := range ratePlanIDs {
|
|
result, err := s.optimizeRatePlan(ctx, ratePlanID, strategy)
|
|
if err != nil {
|
|
s.logger.WithError(err).Error("Failed to optimize rate plan", "rate_plan_id", ratePlanID)
|
|
continue
|
|
}
|
|
results = append(results, result)
|
|
}
|
|
|
|
return results, nil
|
|
}
|
|
|
|
// optimizeRatePlan optimizes a single rate plan
|
|
func (s *PricingOptimizationService) optimizeRatePlan(ctx context.Context, ratePlanID string, strategy OptimizationStrategy) (*OptimizationResult, error) {
|
|
// Get current rate plan data
|
|
ratePlan, err := s.getRatePlan(ctx, ratePlanID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Get historical data
|
|
historicalData, err := s.getHistoricalData(ctx, ratePlanID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Calculate optimal price based on strategy
|
|
optimalPrice := s.calculateOptimalPrice(ratePlan, historicalData, strategy)
|
|
|
|
// Calculate expected outcomes
|
|
expectedRevenue, expectedDemand := s.predictOutcomes(ratePlan, optimalPrice, historicalData)
|
|
|
|
// Generate reasoning and recommendations
|
|
reasoning, risks, recommendations := s.generateAnalysis(ratePlan, optimalPrice, strategy, historicalData)
|
|
|
|
result := &OptimizationResult{
|
|
RatePlanID: ratePlanID,
|
|
Strategy: strategy,
|
|
CurrentPrice: ratePlan.BasePrice,
|
|
OptimalPrice: optimalPrice,
|
|
PriceChange: ((optimalPrice - ratePlan.BasePrice) / ratePlan.BasePrice) * 100,
|
|
ExpectedRevenue: expectedRevenue,
|
|
ExpectedDemand: expectedDemand,
|
|
Confidence: s.calculateConfidence(historicalData),
|
|
Reasoning: reasoning,
|
|
Risks: risks,
|
|
Recommendations: recommendations,
|
|
GeneratedAt: time.Now(),
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// GetPricingMetrics returns pricing performance metrics
|
|
func (s *PricingOptimizationService) GetPricingMetrics(ctx context.Context, period string) (*PricingMetrics, error) {
|
|
metrics := &PricingMetrics{
|
|
Period: period,
|
|
GeneratedAt: time.Now(),
|
|
}
|
|
|
|
// Calculate total revenue
|
|
var totalRevenue float64
|
|
s.db.WithContext(ctx).Table("billing_transactions").
|
|
Where("status = ? AND created_at BETWEEN ? AND ?", "completed",
|
|
s.getPeriodStart(period), s.getPeriodEnd(period)).
|
|
Select("COALESCE(SUM(amount), 0)").
|
|
Scan(&totalRevenue)
|
|
metrics.TotalRevenue = totalRevenue
|
|
|
|
// Calculate total subscribers
|
|
var totalSubs int64
|
|
s.db.WithContext(ctx).Table("profiles").
|
|
Where("status = ?", "active").
|
|
Count(&totalSubs)
|
|
metrics.TotalSubscribers = totalSubs
|
|
|
|
// Calculate ARPU
|
|
if totalSubs > 0 {
|
|
metrics.ARPU = totalRevenue / float64(totalSubs)
|
|
}
|
|
|
|
// Calculate churn rate
|
|
metrics.ChurnRate = s.calculateChurnRate(ctx, period)
|
|
|
|
// Calculate price elasticity
|
|
metrics.PriceElasticity = s.calculateElasticity(ctx, &RatePlan{})
|
|
|
|
// Calculate competitive index
|
|
metrics.CompetitiveIndex = s.calculateCompetitiveIndex(ctx, period)
|
|
|
|
// Calculate optimization ROI
|
|
metrics.OptimizationROI = s.calculateOptimizationROI(ctx, period)
|
|
|
|
return metrics, nil
|
|
}
|
|
|
|
// ApplyOptimization applies pricing optimization
|
|
func (s *PricingOptimizationService) ApplyOptimization(ctx context.Context, result *OptimizationResult) error {
|
|
// Update rate plan price
|
|
err := s.db.WithContext(ctx).Table("rate_plans").
|
|
Where("id = ?", result.RatePlanID).
|
|
Updates(map[string]interface{}{
|
|
"base_price": result.OptimalPrice,
|
|
"updated_at": time.Now(),
|
|
}).Error
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("failed to update rate plan: %w", err)
|
|
}
|
|
|
|
// Log the optimization
|
|
s.logger.WithFields(logrus.Fields{
|
|
"rate_plan_id": result.RatePlanID,
|
|
"strategy": result.Strategy,
|
|
"old_price": result.CurrentPrice,
|
|
"new_price": result.OptimalPrice,
|
|
"price_change": result.PriceChange,
|
|
"expected_revenue": result.ExpectedRevenue,
|
|
}).Info("Pricing optimization applied")
|
|
|
|
return nil
|
|
}
|
|
|
|
// getRatePlan retrieves rate plan data
|
|
func (s *PricingOptimizationService) getRatePlan(ctx context.Context, ratePlanID string) (*RatePlan, error) {
|
|
var ratePlan RatePlan
|
|
err := s.db.WithContext(ctx).Where("id = ?", ratePlanID).First(&ratePlan).Error
|
|
if err != nil {
|
|
return nil, fmt.Errorf("rate plan not found: %w", err)
|
|
}
|
|
return &ratePlan, nil
|
|
}
|
|
|
|
// getHistoricalData retrieves historical pricing and demand data
|
|
func (s *PricingOptimizationService) getHistoricalData(_ context.Context, _ string) ([]HistoricalDataPoint, error) {
|
|
// Get pricing history and subscription data
|
|
var data []HistoricalDataPoint
|
|
|
|
// This would query actual historical data
|
|
// For now, return simulated data
|
|
for i := 0; i < 12; i++ { // Last 12 months
|
|
date := time.Now().AddDate(0, -i, 0)
|
|
point := HistoricalDataPoint{
|
|
Date: date,
|
|
Price: 10.0 + float64(i)*0.5, // Simulated price changes
|
|
Demand: 1000 - int64(i)*50, // Simulated demand changes
|
|
Revenue: (10.0 + float64(i)*0.5) * float64(1000-int64(i)*50),
|
|
}
|
|
data = append(data, point)
|
|
}
|
|
|
|
return data, nil
|
|
}
|
|
|
|
// calculateOptimalPrice calculates optimal price based on strategy
|
|
func (s *PricingOptimizationService) calculateOptimalPrice(ratePlan *RatePlan, data []HistoricalDataPoint, strategy OptimizationStrategy) float64 {
|
|
switch strategy {
|
|
case StrategyRevenueMax:
|
|
return s.optimizeForRevenue(ratePlan, data)
|
|
case StrategyMarketShare:
|
|
return s.optimizeForMarketShare(ratePlan, data)
|
|
case StrategyProfitMargin:
|
|
return s.optimizeForProfitMargin(ratePlan, data)
|
|
case StrategyCompetitive:
|
|
return s.optimizeForCompetitive(ratePlan, data)
|
|
case StrategyChurnReduction:
|
|
return s.optimizeForChurnReduction(ratePlan, data)
|
|
default:
|
|
return ratePlan.BasePrice
|
|
}
|
|
}
|