refactor: Replace map[string]interface{} with map[string]any across currency, handlers, integration, and rateplan packages

- Update BillingSummary.Breakdown field type from map[string]interface{} to map[string]any
- Update Transaction.Metadata field type from map[string]interface{} to map[string]any
- Update RatePlanCurrencyIntegrator subscription and billing metadata to use map[string]any
- Update handler request/response types to use map[string]any (CreateRatePlanRequest, UpdateRatePlanRequest,
This commit is contained in:
nutcas3
2026-05-02 03:21:42 +03:00
parent 31a8886bc0
commit f112aa4c52
27 changed files with 759 additions and 433 deletions
@@ -68,15 +68,15 @@ type AnalyticsService interface {
// BillingSummary represents a billing summary for a profile
type BillingSummary struct {
ProfileID string `json:"profile_id"`
TotalAmount float64 `json:"total_amount"`
Currency string `json:"currency"`
BaseTotalAmount float64 `json:"base_total_amount"`
BaseCurrency string `json:"base_currency"`
TransactionCount int `json:"transaction_count"`
FromDate time.Time `json:"from_date"`
ToDate time.Time `json:"to_date"`
Breakdown map[string]interface{} `json:"breakdown"`
ProfileID string `json:"profile_id"`
TotalAmount float64 `json:"total_amount"`
Currency string `json:"currency"`
BaseTotalAmount float64 `json:"base_total_amount"`
BaseCurrency string `json:"base_currency"`
TransactionCount int `json:"transaction_count"`
FromDate time.Time `json:"from_date"`
ToDate time.Time `json:"to_date"`
Breakdown map[string]any `json:"breakdown"`
}
// CurrencyUsageStats represents statistics about currency usage
@@ -69,7 +69,7 @@ func (rpci *RatePlanCurrencyIntegrator) SubscribeToPlanWithCurrency(ctx context.
RatePlanID: planID,
Status: rateplan.SubscriptionStatusActive,
StartedAt: time.Now(),
Metadata: map[string]interface{}{
Metadata: map[string]any{
"original_currency": plan.Currency,
"subscription_currency": targetCurrency,
"original_price": plan.BasePrice,
@@ -163,7 +163,7 @@ func (rpci *RatePlanCurrencyIntegrator) CalculatePlanCostInCurrency(ctx context.
TransactionCount: 1,
FromDate: time.Now().AddDate(0, -1, 0),
ToDate: time.Now(),
Breakdown: map[string]interface{}{
Breakdown: map[string]any{
"plan_id": planID,
"plan_name": plan.Name,
"base_cost": plan.BasePrice,
@@ -32,20 +32,20 @@ type ExchangeRate struct {
// Transaction represents a financial transaction in multi-currency context
type Transaction struct {
ID string `json:"id" db:"id"`
ProfileID string `json:"profile_id" db:"profile_id"`
SubscriptionID string `json:"subscription_id" db:"subscription_id"`
Type TransactionType `json:"type" db:"type"`
Amount float64 `json:"amount" db:"amount"`
Currency string `json:"currency" db:"currency"`
BaseAmount float64 `json:"base_amount" db:"base_amount"` // Amount in base currency (USD)
BaseCurrency string `json:"base_currency" db:"base_currency"` // Base currency for reporting
ExchangeRate float64 `json:"exchange_rate" db:"exchange_rate"` // Rate used for conversion
Description string `json:"description" db:"description"`
Status TransactionStatus `json:"status" db:"status"`
Metadata map[string]interface{} `json:"metadata,omitempty" db:"metadata"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
ID string `json:"id" db:"id"`
ProfileID string `json:"profile_id" db:"profile_id"`
SubscriptionID string `json:"subscription_id" db:"subscription_id"`
Type TransactionType `json:"type" db:"type"`
Amount float64 `json:"amount" db:"amount"`
Currency string `json:"currency" db:"currency"`
BaseAmount float64 `json:"base_amount" db:"base_amount"` // Amount in base currency (USD)
BaseCurrency string `json:"base_currency" db:"base_currency"` // Base currency for reporting
ExchangeRate float64 `json:"exchange_rate" db:"exchange_rate"` // Rate used for conversion
Description string `json:"description" db:"description"`
Status TransactionStatus `json:"status" db:"status"`
Metadata map[string]any `json:"metadata,omitempty" db:"metadata"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}
// TransactionType defines the type of transaction
@@ -12,9 +12,9 @@ import (
// AnalyticsResponse represents the response for analytics operations
type AnalyticsResponse struct {
Success bool `json:"success"`
Message string `json:"message,omitempty"`
Data interface{} `json:"data,omitempty"`
Success bool `json:"success"`
Message string `json:"message,omitempty"`
Data any `json:"data,omitempty"`
}
// GetUsageAnalytics handles retrieving usage analytics
@@ -169,11 +169,11 @@ func (h *RatePlanHandler) GetDashboardData(c *gin.Context) {
return
}
dashboardData := map[string]interface{}{
dashboardData := map[string]any{
"popular_plans": popularPlans,
"usage_analytics": usageAnalytics,
"revenue_analytics": revenueAnalytics,
"generated_at": time.Now().Format(time.RFC3339),
"usage_analytics": usageAnalytics,
"revenue_analytics": revenueAnalytics,
"generated_at": time.Now().Format(time.RFC3339),
}
response := AnalyticsResponse{
@@ -48,7 +48,7 @@ type CreateRatePlanRequest struct {
ValidTo *time.Time `json:"valid_to,omitempty"`
Priority int `json:"priority"`
IsActive bool `json:"is_active"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
// UpdateRatePlanRequest represents the request to update a rate plan
@@ -72,7 +72,7 @@ type UpdateRatePlanRequest struct {
ValidTo *time.Time `json:"valid_to,omitempty"`
Priority int `json:"priority,omitempty"`
IsActive *bool `json:"is_active,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
// RatePlanResponse represents the response for rate plan operations
@@ -91,7 +91,7 @@ type RatePlansResponse struct {
}
// writeJSONResponse writes a JSON response
func (h *RatePlanHandler) writeJSONResponse(c *gin.Context, statusCode int, data interface{}) {
func (h *RatePlanHandler) writeJSONResponse(c *gin.Context, statusCode int, data any) {
c.JSON(statusCode, data)
}
@@ -15,7 +15,7 @@ func (h *RatePlanHandler) RegisterManagementRoutes(router *gin.RouterGroup) {
// Dashboard endpoints
management.GET("/dashboard", h.GetManagementDashboard)
management.GET("/overview", h.GetSystemOverview)
// Rate plan management
management.POST("/plans/bulk", h.BulkCreateRatePlans)
management.PUT("/plans/bulk", h.BulkUpdateRatePlans)
@@ -23,19 +23,19 @@ func (h *RatePlanHandler) RegisterManagementRoutes(router *gin.RouterGroup) {
management.POST("/plans/:id/activate", h.ActivateRatePlan)
management.POST("/plans/:id/deactivate", h.DeactivateRatePlan)
management.POST("/plans/:id/duplicate", h.DuplicateRatePlan)
// Subscription management
management.POST("/subscriptions/bulk-cancel", h.BulkCancelSubscriptions)
management.POST("/subscriptions/:id/suspend", h.SuspendSubscription)
management.POST("/subscriptions/:id/reactivate", h.ReactivateSubscription)
management.POST("/subscriptions/:id/change-plan", h.ChangeSubscriptionPlan)
// Analytics and reporting
management.GET("/reports/usage", h.GetUsageReport)
management.GET("/reports/revenue", h.GetRevenueReport)
management.GET("/reports/performance", h.GetPerformanceReport)
management.POST("/reports/export", h.ExportReport)
// Configuration and settings
management.GET("/config/pricing", h.GetPricingConfiguration)
management.PUT("/config/pricing", h.UpdatePricingConfiguration)
@@ -47,23 +47,23 @@ func (h *RatePlanHandler) RegisterManagementRoutes(router *gin.RouterGroup) {
// GetManagementDashboard handles the management dashboard endpoint
func (h *RatePlanHandler) GetManagementDashboard(c *gin.Context) {
// Get comprehensive dashboard data
dashboardData := map[string]interface{}{
"total_plans": 0,
"active_plans": 0,
"total_subscriptions": 0,
dashboardData := map[string]any{
"total_plans": 0,
"active_plans": 0,
"total_subscriptions": 0,
"active_subscriptions": 0,
"monthly_revenue": 0.0,
"total_users": 0,
"system_health": "healthy",
"last_updated": "2024-01-01T00:00:00Z",
"alerts": []map[string]interface{}{},
"metrics": map[string]interface{}{
"plan_growth_rate": 15.5,
"subscription_growth": 23.8,
"revenue_growth": 18.2,
"monthly_revenue": 0.0,
"total_users": 0,
"system_health": "healthy",
"last_updated": "2024-01-01T00:00:00Z",
"alerts": []map[string]any{},
"metrics": map[string]any{
"plan_growth_rate": 15.5,
"subscription_growth": 23.8,
"revenue_growth": 18.2,
"churn_rate": 2.1,
},
"recent_activities": []map[string]interface{}{
"recent_activities": []map[string]any{
{"type": "plan_created", "description": "New plan 'Premium Plus' created", "time": "2024-01-01T10:30:00Z"},
{"type": "subscription", "description": "25 new subscriptions today", "time": "2024-01-01T09:15:00Z"},
{"type": "revenue", "description": "Revenue target achieved", "time": "2024-01-01T08:45:00Z"},
@@ -71,8 +71,8 @@ func (h *RatePlanHandler) GetManagementDashboard(c *gin.Context) {
}
response := struct {
Success bool `json:"success"`
Data map[string]interface{} `json:"data"`
Success bool `json:"success"`
Data map[string]any `json:"data"`
}{
Success: true,
Data: dashboardData,
@@ -83,38 +83,38 @@ func (h *RatePlanHandler) GetManagementDashboard(c *gin.Context) {
// GetSystemOverview handles the system overview endpoint
func (h *RatePlanHandler) GetSystemOverview(c *gin.Context) {
overview := map[string]interface{}{
"rate_plans": map[string]interface{}{
"total": 156,
"active": 142,
"draft": 8,
overview := map[string]any{
"rate_plans": map[string]any{
"total": 156,
"active": 142,
"draft": 8,
"archived": 6,
},
"subscriptions": map[string]interface{}{
"total": 12543,
"active": 11892,
"subscriptions": map[string]any{
"total": 12543,
"active": 11892,
"suspended": 456,
"cancelled": 195,
},
"carriers": map[string]interface{}{
"carriers": map[string]any{
"total": 12,
"active": 11,
"healthy": 10,
},
"regions": map[string]interface{}{
"total": 45,
"regions": map[string]any{
"total": 45,
"active": 42,
},
"performance": map[string]interface{}{
"performance": map[string]any{
"avg_response_time": "145ms",
"success_rate": "99.8%",
"uptime": "99.9%",
"success_rate": "99.8%",
"uptime": "99.9%",
},
}
response := struct {
Success bool `json:"success"`
Data map[string]interface{} `json:"data"`
Success bool `json:"success"`
Data map[string]any `json:"data"`
}{
Success: true,
Data: overview,
@@ -134,41 +134,41 @@ func (h *RatePlanHandler) BulkCreateRatePlans(c *gin.Context) {
return
}
results := make([]map[string]interface{}, 0)
results := make([]map[string]any, 0)
for _, planReq := range req.Plans {
plan := &rateplan.RatePlan{
Name: planReq.Name,
Description: planReq.Description,
CarrierID: planReq.CarrierID,
Region: planReq.Region,
PlanType: planReq.PlanType,
BasePrice: planReq.BasePrice,
Currency: planReq.Currency,
BillingCycle: planReq.BillingCycle,
DataAllowance: planReq.DataAllowance,
VoiceAllowance: planReq.VoiceAllowance,
SMSAllowance: planReq.SMSAllowance,
OverageRates: planReq.OverageRates,
Features: planReq.Features,
ActivationFee: planReq.ActivationFee,
EarlyTermination: planReq.EarlyTermination,
Discounts: planReq.Discounts,
ValidFrom: planReq.ValidFrom,
ValidTo: planReq.ValidTo,
Priority: planReq.Priority,
IsActive: planReq.IsActive,
Metadata: planReq.Metadata,
Name: planReq.Name,
Description: planReq.Description,
CarrierID: planReq.CarrierID,
Region: planReq.Region,
PlanType: planReq.PlanType,
BasePrice: planReq.BasePrice,
Currency: planReq.Currency,
BillingCycle: planReq.BillingCycle,
DataAllowance: planReq.DataAllowance,
VoiceAllowance: planReq.VoiceAllowance,
SMSAllowance: planReq.SMSAllowance,
OverageRates: planReq.OverageRates,
Features: planReq.Features,
ActivationFee: planReq.ActivationFee,
EarlyTermination: planReq.EarlyTermination,
Discounts: planReq.Discounts,
ValidFrom: planReq.ValidFrom,
ValidTo: planReq.ValidTo,
Priority: planReq.Priority,
IsActive: planReq.IsActive,
Metadata: planReq.Metadata,
}
createdPlan, err := h.service.CreateRatePlan(c.Request.Context(), plan)
if err != nil {
results = append(results, map[string]interface{}{
results = append(results, map[string]any{
"success": false,
"error": err.Error(),
"plan": planReq.Name,
})
} else {
results = append(results, map[string]interface{}{
results = append(results, map[string]any{
"success": true,
"plan_id": createdPlan.ID,
"plan": planReq.Name,
@@ -177,9 +177,9 @@ func (h *RatePlanHandler) BulkCreateRatePlans(c *gin.Context) {
}
response := struct {
Success bool `json:"success"`
Message string `json:"message"`
Results []map[string]interface{} `json:"results"`
Success bool `json:"success"`
Message string `json:"message"`
Results []map[string]any `json:"results"`
}{
Success: true,
Message: "Bulk creation completed",
@@ -284,28 +284,28 @@ func (h *RatePlanHandler) DuplicateRatePlan(c *gin.Context) {
// Create duplicate
duplicatePlan := &rateplan.RatePlan{
Name: req.Name,
Description: req.Description,
CarrierID: originalPlan.CarrierID,
Region: originalPlan.Region,
PlanType: originalPlan.PlanType,
Status: rateplan.PlanStatusDraft,
BasePrice: originalPlan.BasePrice,
Currency: originalPlan.Currency,
BillingCycle: originalPlan.BillingCycle,
DataAllowance: originalPlan.DataAllowance,
VoiceAllowance: originalPlan.VoiceAllowance,
SMSAllowance: originalPlan.SMSAllowance,
OverageRates: originalPlan.OverageRates,
Features: originalPlan.Features,
ActivationFee: originalPlan.ActivationFee,
Name: req.Name,
Description: req.Description,
CarrierID: originalPlan.CarrierID,
Region: originalPlan.Region,
PlanType: originalPlan.PlanType,
Status: rateplan.PlanStatusDraft,
BasePrice: originalPlan.BasePrice,
Currency: originalPlan.Currency,
BillingCycle: originalPlan.BillingCycle,
DataAllowance: originalPlan.DataAllowance,
VoiceAllowance: originalPlan.VoiceAllowance,
SMSAllowance: originalPlan.SMSAllowance,
OverageRates: originalPlan.OverageRates,
Features: originalPlan.Features,
ActivationFee: originalPlan.ActivationFee,
EarlyTermination: originalPlan.EarlyTermination,
Discounts: originalPlan.Discounts,
ValidFrom: originalPlan.ValidFrom,
ValidTo: originalPlan.ValidTo,
Priority: originalPlan.Priority,
IsActive: false,
Metadata: originalPlan.Metadata,
Discounts: originalPlan.Discounts,
ValidFrom: originalPlan.ValidFrom,
ValidTo: originalPlan.ValidTo,
Priority: originalPlan.Priority,
IsActive: false,
Metadata: originalPlan.Metadata,
}
createdPlan, err := h.service.CreateRatePlan(c.Request.Context(), duplicatePlan)
@@ -315,9 +315,9 @@ func (h *RatePlanHandler) DuplicateRatePlan(c *gin.Context) {
}
response := struct {
Success bool `json:"success"`
Message string `json:"message"`
Data *rateplan.RatePlan `json:"data"`
Success bool `json:"success"`
Message string `json:"message"`
Data *rateplan.RatePlan `json:"data"`
}{
Success: true,
Message: "Rate plan duplicated successfully",
@@ -11,11 +11,11 @@ import (
// SubscribeRequest represents the request to subscribe to a rate plan
type SubscribeRequest struct {
ProfileID string `json:"profile_id" binding:"required"`
RatePlanID string `json:"rate_plan_id" binding:"required"`
AutoRenew bool `json:"auto_renew"`
AppliedDiscounts []string `json:"applied_discounts,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
ProfileID string `json:"profile_id" binding:"required"`
RatePlanID string `json:"rate_plan_id" binding:"required"`
AutoRenew bool `json:"auto_renew"`
AppliedDiscounts []string `json:"applied_discounts,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
// CancelSubscriptionRequest represents the request to cancel a subscription
@@ -234,7 +234,7 @@ func (l *TenantEventLogger) LogResourceAccess(ctx context.Context, tenantID, use
TenantID: tenantID,
UserID: userID,
EventType: tenant.TenantEventType("resource_access"),
EventData: map[string]interface{}{
EventData: map[string]any{
"resource_type": resourceType,
"resource_id": resourceID,
"action": action,
@@ -254,7 +254,7 @@ func (l *TenantEventLogger) LogQuotaViolation(ctx context.Context, tenantID, res
TenantID: tenantID,
UserID: "",
EventType: tenant.TenantEventQuotaExceeded,
EventData: map[string]interface{}{
EventData: map[string]any{
"resource_type": resourceType,
"usage": usage,
"limit": limit,
@@ -5,27 +5,27 @@ import (
)
type DataAllowance struct {
Type DataAllowanceType `json:"type"`
Amount int64 `json:"amount"` // in MB or GB depending on type
Unit string `json:"unit"` // "MB", "GB", "TB"
Unlimited bool `json:"unlimited"`
SpeedLimit *int64 `json:"speed_limit,omitempty"` // in Kbps
Type DataAllowanceType `json:"type"`
Amount int64 `json:"amount"` // in MB or GB depending on type
Unit string `json:"unit"` // "MB", "GB", "TB"
Unlimited bool `json:"unlimited"`
SpeedLimit *int64 `json:"speed_limit,omitempty"` // in Kbps
}
type DataAllowanceType string
const (
DataAllowanceTypeDaily DataAllowanceType = "daily"
DataAllowanceTypeMonthly DataAllowanceType = "monthly"
DataAllowanceTypeCycle DataAllowanceType = "cycle"
DataAllowanceTypeLifetime DataAllowanceType = "lifetime"
DataAllowanceTypeDaily DataAllowanceType = "daily"
DataAllowanceTypeMonthly DataAllowanceType = "monthly"
DataAllowanceTypeCycle DataAllowanceType = "cycle"
DataAllowanceTypeLifetime DataAllowanceType = "lifetime"
)
type VoiceAllowance struct {
Type VoiceAllowanceType `json:"type"`
Minutes int64 `json:"minutes"`
Unlimited bool `json:"unlimited"`
Destinations []string `json:"destinations,omitempty"` // country codes
Type VoiceAllowanceType `json:"type"`
Minutes int64 `json:"minutes"`
Unlimited bool `json:"unlimited"`
Destinations []string `json:"destinations,omitempty"` // country codes
}
type VoiceAllowanceType string
@@ -38,10 +38,10 @@ const (
)
type SMSAllowance struct {
Type SMSAllowanceType `json:"type"`
Messages int64 `json:"messages"`
Unlimited bool `json:"unlimited"`
Destinations []string `json:"destinations,omitempty"` // country codes
Type SMSAllowanceType `json:"type"`
Messages int64 `json:"messages"`
Unlimited bool `json:"unlimited"`
Destinations []string `json:"destinations,omitempty"` // country codes
}
type SMSAllowanceType string
@@ -54,17 +54,17 @@ const (
)
type OverageRates struct {
DataRate float64 `json:"data_rate"` // per MB
VoiceRate float64 `json:"voice_rate"` // per minute
SMSRate float64 `json:"sms_rate"` // per message
Currency string `json:"currency"`
DataRate float64 `json:"data_rate"` // per MB
VoiceRate float64 `json:"voice_rate"` // per minute
SMSRate float64 `json:"sms_rate"` // per message
Currency string `json:"currency"`
}
type PlanFeature struct {
Name string `json:"name"`
Description string `json:"description"`
Enabled bool `json:"enabled"`
Config map[string]interface{} `json:"config,omitempty"`
Name string `json:"name"`
Description string `json:"description"`
Enabled bool `json:"enabled"`
Config map[string]any `json:"config,omitempty"`
}
type EarlyTermination struct {
@@ -76,91 +76,91 @@ type EarlyTermination struct {
}
type Discount struct {
ID string `json:"id"`
Name string `json:"name"`
Type DiscountType `json:"type"`
Value float64 `json:"value"`
ValidFrom time.Time `json:"valid_from"`
ValidTo *time.Time `json:"valid_to,omitempty"`
Conditions string `json:"conditions,omitempty"`
IsActive bool `json:"is_active"`
ID string `json:"id"`
Name string `json:"name"`
Type DiscountType `json:"type"`
Value float64 `json:"value"`
ValidFrom time.Time `json:"valid_from"`
ValidTo *time.Time `json:"valid_to,omitempty"`
Conditions string `json:"conditions,omitempty"`
IsActive bool `json:"is_active"`
}
type DiscountType string
const (
DiscountTypePercentage DiscountType = "percentage"
DiscountTypeFixed DiscountType = "fixed"
DiscountTypeRecurring DiscountType = "recurring"
DiscountTypeFixed DiscountType = "fixed"
DiscountTypeRecurring DiscountType = "recurring"
)
// RatePlanUsage tracks actual usage against a rate plan
type RatePlanUsage struct {
ID string `json:"id" db:"id"`
RatePlanID string `json:"rate_plan_id" db:"rate_plan_id"`
ProfileID string `json:"profile_id" db:"profile_id"`
CycleStart time.Time `json:"cycle_start" db:"cycle_start"`
CycleEnd time.Time `json:"cycle_end" db:"cycle_end"`
DataUsed int64 `json:"data_used" db:"data_used"` // in MB
VoiceUsed int64 `json:"voice_used" db:"voice_used"` // in minutes
SMSUsed int64 `json:"sms_used" db:"sms_used"` // count
LastUpdated time.Time `json:"last_updated" db:"last_updated"`
ID string `json:"id" db:"id"`
RatePlanID string `json:"rate_plan_id" db:"rate_plan_id"`
ProfileID string `json:"profile_id" db:"profile_id"`
CycleStart time.Time `json:"cycle_start" db:"cycle_start"`
CycleEnd time.Time `json:"cycle_end" db:"cycle_end"`
DataUsed int64 `json:"data_used" db:"data_used"` // in MB
VoiceUsed int64 `json:"voice_used" db:"voice_used"` // in minutes
SMSUsed int64 `json:"sms_used" db:"sms_used"` // count
LastUpdated time.Time `json:"last_updated" db:"last_updated"`
}
// RatePlanSubscription represents an active subscription to a rate plan
type RatePlanSubscription struct {
ID string `json:"id" db:"id"`
ProfileID string `json:"profile_id" db:"profile_id"`
RatePlanID string `json:"rate_plan_id" db:"rate_plan_id"`
Status SubscriptionStatus `json:"status" db:"status"`
StartedAt time.Time `json:"started_at" db:"started_at"`
EndedAt *time.Time `json:"ended_at,omitempty" db:"ended_at"`
BillingCycle BillingCycle `json:"billing_cycle" db:"billing_cycle"`
NextBillingDate time.Time `json:"next_billing_date" db:"next_billing_date"`
AutoRenew bool `json:"auto_renew" db:"auto_renew"`
CurrentCycle time.Time `json:"current_cycle" db:"current_cycle"`
AppliedDiscounts []string `json:"applied_discounts,omitempty" db:"applied_discounts"`
Metadata map[string]any `json:"metadata,omitempty" db:"metadata"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
ID string `json:"id" db:"id"`
ProfileID string `json:"profile_id" db:"profile_id"`
RatePlanID string `json:"rate_plan_id" db:"rate_plan_id"`
Status SubscriptionStatus `json:"status" db:"status"`
StartedAt time.Time `json:"started_at" db:"started_at"`
EndedAt *time.Time `json:"ended_at,omitempty" db:"ended_at"`
BillingCycle BillingCycle `json:"billing_cycle" db:"billing_cycle"`
NextBillingDate time.Time `json:"next_billing_date" db:"next_billing_date"`
AutoRenew bool `json:"auto_renew" db:"auto_renew"`
CurrentCycle time.Time `json:"current_cycle" db:"current_cycle"`
AppliedDiscounts []string `json:"applied_discounts,omitempty" db:"applied_discounts"`
Metadata map[string]any `json:"metadata,omitempty" db:"metadata"`
CreatedAt time.Time `json:"created_at" db:"created_at"`
UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}
// SubscriptionStatus defines the status of a subscription
type SubscriptionStatus string
const (
SubscriptionStatusActive SubscriptionStatus = "active"
SubscriptionStatusSuspended SubscriptionStatus = "suspended"
SubscriptionStatusCancelled SubscriptionStatus = "cancelled"
SubscriptionStatusExpired SubscriptionStatus = "expired"
SubscriptionStatusPending SubscriptionStatus = "pending"
SubscriptionStatusActive SubscriptionStatus = "active"
SubscriptionStatusSuspended SubscriptionStatus = "suspended"
SubscriptionStatusCancelled SubscriptionStatus = "cancelled"
SubscriptionStatusExpired SubscriptionStatus = "expired"
SubscriptionStatusPending SubscriptionStatus = "pending"
)
// RatePlanFilter defines filtering options for rate plan queries
type RatePlanFilter struct {
CarrierID string `json:"carrier_id,omitempty"`
Region string `json:"region,omitempty"`
PlanType PlanType `json:"plan_type,omitempty"`
Status PlanStatus `json:"status,omitempty"`
MinPrice float64 `json:"min_price,omitempty"`
MaxPrice float64 `json:"max_price,omitempty"`
IsActive *bool `json:"is_active,omitempty"`
ValidFrom *time.Time `json:"valid_from,omitempty"`
ValidTo *time.Time `json:"valid_to,omitempty"`
Limit int `json:"limit,omitempty"`
Offset int `json:"offset,omitempty"`
SortBy string `json:"sort_by,omitempty"`
SortOrder string `json:"sort_order,omitempty"`
CarrierID string `json:"carrier_id,omitempty"`
Region string `json:"region,omitempty"`
PlanType PlanType `json:"plan_type,omitempty"`
Status PlanStatus `json:"status,omitempty"`
MinPrice float64 `json:"min_price,omitempty"`
MaxPrice float64 `json:"max_price,omitempty"`
IsActive *bool `json:"is_active,omitempty"`
ValidFrom *time.Time `json:"valid_from,omitempty"`
ValidTo *time.Time `json:"valid_to,omitempty"`
Limit int `json:"limit,omitempty"`
Offset int `json:"offset,omitempty"`
SortBy string `json:"sort_by,omitempty"`
SortOrder string `json:"sort_order,omitempty"`
}
// RatePlanCostCalculation represents the result of cost calculation
type RatePlanCostCalculation struct {
RatePlanID string `json:"rate_plan_id"`
BaseCost float64 `json:"base_cost"`
OverageCost float64 `json:"overage_cost"`
DiscountCost float64 `json:"discount_cost"`
TotalCost float64 `json:"total_cost"`
Currency string `json:"currency"`
Breakdown map[string]any `json:"breakdown"`
CalculatedAt time.Time `json:"calculated_at"`
RatePlanID string `json:"rate_plan_id"`
BaseCost float64 `json:"base_cost"`
OverageCost float64 `json:"overage_cost"`
DiscountCost float64 `json:"discount_cost"`
TotalCost float64 `json:"total_cost"`
Currency string `json:"currency"`
Breakdown map[string]any `json:"breakdown"`
CalculatedAt time.Time `json:"calculated_at"`
}
@@ -8,54 +8,54 @@ import (
// SubscriptionFilter defines filtering options for subscription queries
type SubscriptionFilter struct {
Status SubscriptionStatus `json:"status,omitempty"`
RatePlanID string `json:"rate_plan_id,omitempty"`
StartedAfter *time.Time `json:"started_after,omitempty"`
StartedBefore *time.Time `json:"started_before,omitempty"`
Limit int `json:"limit,omitempty"`
Offset int `json:"offset,omitempty"`
Status SubscriptionStatus `json:"status,omitempty"`
RatePlanID string `json:"rate_plan_id,omitempty"`
StartedAfter *time.Time `json:"started_after,omitempty"`
StartedBefore *time.Time `json:"started_before,omitempty"`
Limit int `json:"limit,omitempty"`
Offset int `json:"offset,omitempty"`
}
// UsageAnalyticsFilter defines filtering options for usage analytics
type UsageAnalyticsFilter struct {
RatePlanID string `json:"rate_plan_id,omitempty"`
CarrierID string `json:"carrier_id,omitempty"`
Region string `json:"region,omitempty"`
StartDate time.Time `json:"start_date"`
EndDate time.Time `json:"end_date"`
GroupBy string `json:"group_by,omitempty"` // "day", "week", "month"
RatePlanID string `json:"rate_plan_id,omitempty"`
CarrierID string `json:"carrier_id,omitempty"`
Region string `json:"region,omitempty"`
StartDate time.Time `json:"start_date"`
EndDate time.Time `json:"end_date"`
GroupBy string `json:"group_by,omitempty"` // "day", "week", "month"
}
// RevenueAnalyticsFilter defines filtering options for revenue analytics
type RevenueAnalyticsFilter struct {
RatePlanID string `json:"rate_plan_id,omitempty"`
CarrierID string `json:"carrier_id,omitempty"`
Region string `json:"region,omitempty"`
StartDate time.Time `json:"start_date"`
EndDate time.Time `json:"end_date"`
GroupBy string `json:"group_by,omitempty"` // "day", "week", "month"
RatePlanID string `json:"rate_plan_id,omitempty"`
CarrierID string `json:"carrier_id,omitempty"`
Region string `json:"region,omitempty"`
StartDate time.Time `json:"start_date"`
EndDate time.Time `json:"end_date"`
GroupBy string `json:"group_by,omitempty"` // "day", "week", "month"
}
// UsageAnalytics contains usage statistics
type UsageAnalytics struct {
TotalDataUsed int64 `json:"total_data_used"`
TotalVoiceUsed int64 `json:"total_voice_used"`
TotalSMSUsed int64 `json:"total_sms_used"`
ActiveUsers int `json:"active_users"`
AverageUsage map[string]float64 `json:"average_usage"`
UsageByPlan map[string]int64 `json:"usage_by_plan"`
UsageByRegion map[string]int64 `json:"usage_by_region"`
TimelineData []TimelineDataPoint `json:"timeline_data"`
TotalDataUsed int64 `json:"total_data_used"`
TotalVoiceUsed int64 `json:"total_voice_used"`
TotalSMSUsed int64 `json:"total_sms_used"`
ActiveUsers int `json:"active_users"`
AverageUsage map[string]float64 `json:"average_usage"`
UsageByPlan map[string]int64 `json:"usage_by_plan"`
UsageByRegion map[string]int64 `json:"usage_by_region"`
TimelineData []TimelineDataPoint `json:"timeline_data"`
}
// RevenueAnalytics contains revenue statistics
type RevenueAnalytics struct {
TotalRevenue float64 `json:"total_revenue"`
RevenueByPlan map[string]float64 `json:"revenue_by_plan"`
RevenueByCarrier map[string]float64 `json:"revenue_by_carrier"`
RevenueByRegion map[string]float64 `json:"revenue_by_region"`
AverageRevenue map[string]float64 `json:"average_revenue"`
TimelineData []TimelineDataPoint `json:"timeline_data"`
TotalRevenue float64 `json:"total_revenue"`
RevenueByPlan map[string]float64 `json:"revenue_by_plan"`
RevenueByCarrier map[string]float64 `json:"revenue_by_carrier"`
RevenueByRegion map[string]float64 `json:"revenue_by_region"`
AverageRevenue map[string]float64 `json:"average_revenue"`
TimelineData []TimelineDataPoint `json:"timeline_data"`
}
// TimelineDataPoint represents a data point in time series
@@ -78,11 +78,11 @@ type SearchCriteria struct {
}
type SubscribeRequest struct {
ProfileID string `json:"profile_id"`
RatePlanID string `json:"rate_plan_id"`
AutoRenew bool `json:"auto_renew"`
AppliedDiscounts []string `json:"applied_discounts,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
ProfileID string `json:"profile_id"`
RatePlanID string `json:"rate_plan_id"`
AutoRenew bool `json:"auto_renew"`
AppliedDiscounts []string `json:"applied_discounts,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
type RecordUsageRequest struct {
@@ -127,55 +127,55 @@ type CostItem struct {
}
type CarrierRatePlanCriteria struct {
Region string `json:"region"`
PlanType PlanType `json:"plan_type"`
MaxBudget float64 `json:"max_budget"`
Urgency string `json:"urgency"`
Preferences map[string]interface{} `json:"preferences,omitempty"`
Region string `json:"region"`
PlanType PlanType `json:"plan_type"`
MaxBudget float64 `json:"max_budget"`
Urgency string `json:"urgency"`
Preferences map[string]any `json:"preferences,omitempty"`
}
type RecommendationCriteria struct {
Region string `json:"region"`
Region string `json:"region"`
PlanType PlanType `json:"plan_type"`
MaxBudget float64 `json:"max_budget"`
PreferredData int64 `json:"preferred_data"`
PreferredVoice int64 `json:"preferred_voice"`
PreferredSMS int64 `json:"preferred_sms"`
MaxResults int `json:"max_results"`
MaxBudget float64 `json:"max_budget"`
PreferredData int64 `json:"preferred_data"`
PreferredVoice int64 `json:"preferred_voice"`
PreferredSMS int64 `json:"preferred_sms"`
MaxResults int `json:"max_results"`
}
type CarrierRatePlanResult struct {
Carrier *smdp.Carrier `json:"carrier"`
RatePlan *RatePlan `json:"rate_plan"`
TotalScore float64 `json:"total_score"`
SelectedAt time.Time `json:"selected_at"`
RatePlan *RatePlan `json:"rate_plan"`
TotalScore float64 `json:"total_score"`
SelectedAt time.Time `json:"selected_at"`
}
type RatePlanRecommendation struct {
RatePlanID string `json:"rate_plan_id"`
RatePlanName string `json:"rate_plan_name"`
CarrierID string `json:"carrier_id"`
CarrierName string `json:"carrier_name"`
Price float64 `json:"price"`
Currency string `json:"currency"`
Relevance float64 `json:"relevance"`
Features []PlanFeature `json:"features"`
DataAllowance *DataAllowance `json:"data_allowance"`
VoiceAllowance *VoiceAllowance `json:"voice_allowance"`
SMSAllowance *SMSAllowance `json:"sms_allowance"`
RecommendedAt time.Time `json:"recommended_at"`
RatePlanID string `json:"rate_plan_id"`
RatePlanName string `json:"rate_plan_name"`
CarrierID string `json:"carrier_id"`
CarrierName string `json:"carrier_name"`
Price float64 `json:"price"`
Currency string `json:"currency"`
Relevance float64 `json:"relevance"`
Features []PlanFeature `json:"features"`
DataAllowance *DataAllowance `json:"data_allowance"`
VoiceAllowance *VoiceAllowance `json:"voice_allowance"`
SMSAllowance *SMSAllowance `json:"sms_allowance"`
RecommendedAt time.Time `json:"recommended_at"`
}
type CarrierRatePlanAnalytics struct {
CarrierID string `json:"carrier_id"`
CarrierName string `json:"carrier_name"`
Region string `json:"region"`
HealthStatus string `json:"health_status"`
Priority int `json:"priority"`
TotalPlans int `json:"total_plans"`
ActivePlans int `json:"active_plans"`
GeneratedAt time.Time `json:"generated_at"`
PlanAnalytics []RatePlanAnalytics `json:"plan_analytics"`
CarrierID string `json:"carrier_id"`
CarrierName string `json:"carrier_name"`
Region string `json:"region"`
HealthStatus string `json:"health_status"`
Priority int `json:"priority"`
TotalPlans int `json:"total_plans"`
ActivePlans int `json:"active_plans"`
GeneratedAt time.Time `json:"generated_at"`
PlanAnalytics []RatePlanAnalytics `json:"plan_analytics"`
}
type RatePlanAnalytics struct {
@@ -102,7 +102,7 @@ func (r *GormRepository) transactionToModel(transaction *currency.Transaction) *
// modelToTransaction converts database model to transaction domain model
func (r *GormRepository) modelToTransaction(model *currency.TransactionModel) (*currency.Transaction, error) {
var metadata map[string]interface{}
var metadata map[string]any
if model.Metadata != "" {
if err := json.Unmarshal([]byte(model.Metadata), &metadata); err != nil {
return nil, fmt.Errorf("failed to parse metadata: %w", err)
@@ -54,7 +54,7 @@ func (r *TenantAwareRepository) ValidateTenant(ctx context.Context) error {
}
// TenantScopedQuery creates a query scoped to the current tenant
func (r *TenantAwareRepository) TenantScopedQuery(ctx context.Context, model interface{}) *gorm.DB {
func (r *TenantAwareRepository) TenantScopedQuery(ctx context.Context, model any) *gorm.DB {
query := r.db.WithContext(ctx).Model(model)
if r.tenantID != "" {
query = query.Where("tenant_id = ?", r.tenantID)
@@ -48,7 +48,7 @@ func (r *GormTenantRepository) GetConfig(ctx context.Context, tenantID string) (
// Create basic config
config := &tenant.TenantConfig{
TenantID: tenantID,
Config: make(map[string]interface{}),
Config: make(map[string]any),
Settings: tenantRecord.Settings,
Quotas: []tenant.ResourceQuota{},
Features: make(map[string]bool),
@@ -8,7 +8,7 @@ import (
)
// TenantAwareQuery adds tenant filtering to database queries
func (r *GormTenantRepository) TenantAwareQuery(ctx context.Context, model interface{}, tenantID string) *gorm.DB {
func (r *GormTenantRepository) TenantAwareQuery(ctx context.Context, model any, tenantID string) *gorm.DB {
query := r.db.WithContext(ctx).Model(model)
// Add tenant filter if the model has tenant_id field
@@ -8,7 +8,7 @@ import (
"gorm.io/gorm"
)
func (r *TenantAwareRepository) CreateWithTenant(ctx context.Context, model interface{}) error {
func (r *TenantAwareRepository) CreateWithTenant(ctx context.Context, model any) error {
if err := r.ValidateTenant(ctx); err != nil {
return err
}
@@ -21,7 +21,7 @@ func (r *TenantAwareRepository) CreateWithTenant(ctx context.Context, model inte
return r.db.WithContext(ctx).Create(model).Error
}
func (r *TenantAwareRepository) GetByTenantID(ctx context.Context, model interface{}, id string) error {
func (r *TenantAwareRepository) GetByTenantID(ctx context.Context, model any, id string) error {
if err := r.ValidateTenant(ctx); err != nil {
return err
}
@@ -29,7 +29,7 @@ func (r *TenantAwareRepository) GetByTenantID(ctx context.Context, model interfa
return r.TenantScopedQuery(ctx, model).Where("id = ?", id).First(model).Error
}
func (r *TenantAwareRepository) UpdateWithTenant(ctx context.Context, model interface{}) error {
func (r *TenantAwareRepository) UpdateWithTenant(ctx context.Context, model any) error {
if err := r.ValidateTenant(ctx); err != nil {
return err
}
@@ -37,7 +37,7 @@ func (r *TenantAwareRepository) UpdateWithTenant(ctx context.Context, model inte
return r.db.WithContext(ctx).Save(model).Error
}
func (r *TenantAwareRepository) DeleteWithTenant(ctx context.Context, model interface{}, id string) error {
func (r *TenantAwareRepository) DeleteWithTenant(ctx context.Context, model any, id string) error {
if err := r.ValidateTenant(ctx); err != nil {
return err
}
@@ -45,7 +45,7 @@ func (r *TenantAwareRepository) DeleteWithTenant(ctx context.Context, model inte
return r.TenantScopedQuery(ctx, model).Where("id = ?", id).Delete(model).Error
}
func (r *TenantAwareRepository) ListWithTenant(ctx context.Context, model interface{}, results interface{}, filters map[string]interface{}) error {
func (r *TenantAwareRepository) ListWithTenant(ctx context.Context, model any, results any, filters map[string]any) error {
if err := r.ValidateTenant(ctx); err != nil {
return err
}
@@ -60,7 +60,7 @@ func (r *TenantAwareRepository) ListWithTenant(ctx context.Context, model interf
return query.Find(results).Error
}
func (r *TenantAwareRepository) CountWithTenant(ctx context.Context, model interface{}, filters map[string]interface{}) (int64, error) {
func (r *TenantAwareRepository) CountWithTenant(ctx context.Context, model any, filters map[string]any) (int64, error) {
if err := r.ValidateTenant(ctx); err != nil {
return 0, err
}
@@ -145,7 +145,7 @@ func NewTenantQueryBuilder(db *gorm.DB, tenantID string) *TenantQueryBuilder {
}
}
func (b *TenantQueryBuilder) Where(query string, args ...interface{}) *TenantQueryBuilder {
func (b *TenantQueryBuilder) Where(query string, args ...any) *TenantQueryBuilder {
b.query = b.query.Where(query, args...)
return b
}
@@ -165,11 +165,11 @@ func (b *TenantQueryBuilder) Offset(offset int) *TenantQueryBuilder {
return b
}
func (b *TenantQueryBuilder) Find(dest interface{}) error {
func (b *TenantQueryBuilder) Find(dest any) error {
return b.query.Find(dest).Error
}
func (b *TenantQueryBuilder) First(dest interface{}) error {
func (b *TenantQueryBuilder) First(dest any) error {
return b.query.First(dest).Error
}
@@ -189,4 +189,4 @@ type TenantResourceValidator struct {
func NewTenantResourceValidator(db *gorm.DB) *TenantResourceValidator {
return &TenantResourceValidator{db: db}
}
}
@@ -99,20 +99,20 @@ func (RatePlanUsage) TableName() string {
// RatePlanSubscription represents a subscription to a rate plan
type RatePlanSubscription struct {
ID string `json:"id" gorm:"primaryKey"`
ProfileID string `json:"profile_id" gorm:"index"`
RatePlanID string `json:"rate_plan_id" gorm:"index"`
Status SubscriptionStatus `json:"status" gorm:"index"`
StartedAt time.Time `json:"started_at"`
EndedAt *time.Time `json:"ended_at,omitempty"`
BillingCycle BillingCycle `json:"billing_cycle"`
NextBillingDate time.Time `json:"next_billing_date"`
AutoRenew bool `json:"auto_renew"`
CurrentCycle time.Time `json:"current_cycle"`
AppliedDiscounts []string `json:"applied_discounts,omitempty" gorm:"serializer:json"`
Metadata map[string]interface{} `json:"metadata,omitempty" gorm:"serializer:json"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ID string `json:"id" gorm:"primaryKey"`
ProfileID string `json:"profile_id" gorm:"index"`
RatePlanID string `json:"rate_plan_id" gorm:"index"`
Status SubscriptionStatus `json:"status" gorm:"index"`
StartedAt time.Time `json:"started_at"`
EndedAt *time.Time `json:"ended_at,omitempty"`
BillingCycle BillingCycle `json:"billing_cycle"`
NextBillingDate time.Time `json:"next_billing_date"`
AutoRenew bool `json:"auto_renew"`
CurrentCycle time.Time `json:"current_cycle"`
AppliedDiscounts []string `json:"applied_discounts,omitempty" gorm:"serializer:json"`
Metadata map[string]any `json:"metadata,omitempty" gorm:"serializer:json"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// TableName returns the table name for RatePlanSubscription
@@ -153,27 +153,27 @@ type SubscriptionFilter struct {
// RatePlan represents a rate plan
type RatePlan struct {
ID string `json:"id" gorm:"primaryKey"`
Name string `json:"name"`
Description string `json:"description"`
CarrierID string `json:"carrier_id" gorm:"index"`
Region string `json:"region" gorm:"index"`
PlanType PlanType `json:"plan_type"`
BasePrice float64 `json:"base_price"`
Currency string `json:"currency"`
BillingCycle BillingCycle `json:"billing_cycle"`
DataAllowance *DataAllowance `json:"data_allowance,omitempty" gorm:"serializer:json"`
VoiceAllowance *VoiceAllowance `json:"voice_allowance,omitempty" gorm:"serializer:json"`
SMSAllowance *SMSAllowance `json:"sms_allowance,omitempty" gorm:"serializer:json"`
OverageRates *OverageRates `json:"overage_rates,omitempty" gorm:"serializer:json"`
Discounts []*Discount `json:"discounts,omitempty" gorm:"serializer:json"`
ValidFrom time.Time `json:"valid_from"`
ValidTo *time.Time `json:"valid_to,omitempty"`
IsActive bool `json:"is_active"`
Status PlanStatus `json:"status"`
Metadata map[string]interface{} `json:"metadata,omitempty" gorm:"serializer:json"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ID string `json:"id" gorm:"primaryKey"`
Name string `json:"name"`
Description string `json:"description"`
CarrierID string `json:"carrier_id" gorm:"index"`
Region string `json:"region" gorm:"index"`
PlanType PlanType `json:"plan_type"`
BasePrice float64 `json:"base_price"`
Currency string `json:"currency"`
BillingCycle BillingCycle `json:"billing_cycle"`
DataAllowance *DataAllowance `json:"data_allowance,omitempty" gorm:"serializer:json"`
VoiceAllowance *VoiceAllowance `json:"voice_allowance,omitempty" gorm:"serializer:json"`
SMSAllowance *SMSAllowance `json:"sms_allowance,omitempty" gorm:"serializer:json"`
OverageRates *OverageRates `json:"overage_rates,omitempty" gorm:"serializer:json"`
Discounts []*Discount `json:"discounts,omitempty" gorm:"serializer:json"`
ValidFrom time.Time `json:"valid_from"`
ValidTo *time.Time `json:"valid_to,omitempty"`
IsActive bool `json:"is_active"`
Status PlanStatus `json:"status"`
Metadata map[string]any `json:"metadata,omitempty" gorm:"serializer:json"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// TableName returns the table name for RatePlan
@@ -323,11 +323,11 @@ type SearchCriteria struct {
// SubscribeRequest represents a request to subscribe to a rate plan
type SubscribeRequest struct {
ProfileID string `json:"profile_id"`
RatePlanID string `json:"rate_plan_id"`
AutoRenew bool `json:"auto_renew"`
AppliedDiscounts []string `json:"applied_discounts,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
ProfileID string `json:"profile_id"`
RatePlanID string `json:"rate_plan_id"`
AutoRenew bool `json:"auto_renew"`
AppliedDiscounts []string `json:"applied_discounts,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
// RecordUsageRequest represents a request to record usage
@@ -349,12 +349,12 @@ type CalculateCostRequest struct {
// RatePlanCostCalculation represents the result of a cost calculation
type RatePlanCostCalculation struct {
RatePlanID string `json:"rate_plan_id"`
BaseCost float64 `json:"base_cost"`
OverageCost float64 `json:"overage_cost"`
DiscountCost float64 `json:"discount_cost"`
TotalCost float64 `json:"total_cost"`
Currency string `json:"currency"`
Breakdown map[string]interface{} `json:"breakdown"`
CalculatedAt time.Time `json:"calculated_at"`
RatePlanID string `json:"rate_plan_id"`
BaseCost float64 `json:"base_cost"`
OverageCost float64 `json:"overage_cost"`
DiscountCost float64 `json:"discount_cost"`
TotalCost float64 `json:"total_cost"`
Currency string `json:"currency"`
Breakdown map[string]any `json:"breakdown"`
CalculatedAt time.Time `json:"calculated_at"`
}
@@ -64,7 +64,7 @@ func (rpci *RatePlanCurrencyIntegrator) SubscribeToPlanWithCurrency(ctx context.
RatePlanID: planID,
Status: rateplan.SubscriptionStatusActive,
StartedAt: time.Now(),
Metadata: map[string]interface{}{
Metadata: map[string]any{
"original_currency": plan.Currency,
"subscription_currency": targetCurrency,
"original_price": plan.BasePrice,
@@ -155,7 +155,7 @@ func (rpci *RatePlanCurrencyIntegrator) CalculatePlanCostInCurrency(ctx context.
TransactionCount: 1,
FromDate: time.Now().AddDate(0, -1, 0),
ToDate: time.Now(),
Breakdown: map[string]interface{}{
Breakdown: map[string]any{
"plan_id": planID,
"plan_name": plan.Name,
"base_cost": plan.BasePrice,
@@ -39,7 +39,7 @@ func (rpci *RatePlanCurrencyIntegrator) GetPlansInCurrency(ctx context.Context,
// Store original price and update with converted price
if plan.Metadata == nil {
plan.Metadata = make(map[string]interface{})
plan.Metadata = make(map[string]any)
}
plan.Metadata["original_price"] = plan.BasePrice
plan.Metadata["original_currency"] = plan.Currency
@@ -81,9 +81,9 @@ func (rpci *RatePlanCurrencyIntegrator) UpdatePlanCurrency(ctx context.Context,
// Store conversion information in metadata
if plan.Metadata == nil {
plan.Metadata = make(map[string]interface{})
plan.Metadata = make(map[string]any)
}
plan.Metadata["currency_conversion"] = map[string]interface{}{
plan.Metadata["currency_conversion"] = map[string]any{
"from_currency": plan.Metadata["original_currency"],
"to_currency": newCurrency,
"exchange_rate": convertedPrice.ExchangeRate,
@@ -187,7 +187,7 @@ func (s *Service) CalculateCost(ctx context.Context, req *repository.CalculateCo
DiscountCost: discountCost,
TotalCost: totalCost,
Currency: plan.Currency,
Breakdown: map[string]interface{}{
Breakdown: map[string]any{
"base_cost": baseCost,
"overage_cost": overageCost,
"discount_cost": discountCost,
@@ -101,7 +101,7 @@ func (s *Service) CancelSubscription(ctx context.Context, subscriptionID string,
subscription.UpdatedAt = now
if subscription.Metadata == nil {
subscription.Metadata = make(map[string]interface{})
subscription.Metadata = make(map[string]any)
}
subscription.Metadata["cancellation_reason"] = reason
@@ -178,7 +178,7 @@ func (s *TenantServiceImpl) ResetTenantConfig(ctx context.Context, tenantID stri
func (s *TenantServiceImpl) convertTenantConfig(tenantID string, settings *tenant.TenantSettings, plan tenant.TenantPlan) *tenant.TenantConfig {
return &tenant.TenantConfig{
TenantID: tenantID,
Config: make(map[string]interface{}),
Config: make(map[string]any),
Settings: settings,
Quotas: s.getDefaultQuotas(plan),
Features: s.getDefaultFeatures(plan),
@@ -74,7 +74,7 @@ func (s *TenantServiceImpl) CreateTenant(ctx context.Context, req *tenant.Create
// Create initial configuration
config := &tenant.TenantConfig{
TenantID: newTenant.ID,
Config: make(map[string]interface{}),
Config: make(map[string]any),
Settings: newTenant.Settings,
Quotas: s.getDefaultQuotas(req.Plan),
Features: s.getDefaultFeatures(req.Plan),
@@ -98,7 +98,7 @@ type Service interface {
// Middleware defines the interface for tenant middleware
type Middleware interface {
// Request middleware
ExtractTenantFromRequest(ctx context.Context, request interface{}) (*TenantContext, error)
ExtractTenantFromRequest(ctx context.Context, request any) (*TenantContext, error)
ValidateTenantAccess(ctx context.Context, tenantCtx *TenantContext) error
InjectTenantContext(ctx context.Context, tenantCtx *TenantContext) context.Context
@@ -140,15 +140,15 @@ type ResourceManager interface {
type ConfigManager interface {
GetConfig(ctx context.Context, tenantID string) (*TenantConfig, error)
SetConfig(ctx context.Context, tenantID string, config *TenantConfig) error
UpdateConfig(ctx context.Context, tenantID string, updates map[string]interface{}) error
GetSetting(ctx context.Context, tenantID, key string) (interface{}, error)
SetSetting(ctx context.Context, tenantID, key string, value interface{}) error
UpdateConfig(ctx context.Context, tenantID string, updates map[string]any) error
GetSetting(ctx context.Context, tenantID, key string) (any, error)
SetSetting(ctx context.Context, tenantID, key string, value any) error
DeleteSetting(ctx context.Context, tenantID, key string) error
}
// AuditLogger defines the interface for tenant audit logging
type AuditLogger interface {
LogTenantAction(ctx context.Context, tenantID, userID, action string, details map[string]interface{}) error
LogTenantAction(ctx context.Context, tenantID, userID, action string, details map[string]any) error
LogAPIAccess(ctx context.Context, tenantID, userID, apiKey, endpoint, method string) error
LogResourceAccess(ctx context.Context, tenantID, userID, resource, resourceID, action string) error
LogQuotaViolation(ctx context.Context, tenantID, resourceType string, usage, limit int) error
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"net/http"
"slices"
"strings"
"time"
@@ -65,8 +66,8 @@ func (tm *TenantMiddleware) ExtractTenantFromAPIKey(c *gin.Context) (*TenantCont
if apiKey == "" {
// Try Authorization header with Bearer token
authHeader := c.GetHeader("Authorization")
if strings.HasPrefix(authHeader, "Bearer ") {
apiKey = strings.TrimPrefix(authHeader, "Bearer ")
if after, ok := strings.CutPrefix(authHeader, "Bearer "); ok {
apiKey = after
}
}
@@ -133,13 +134,7 @@ func (tm *TenantMiddleware) RequireTenantRole(requiredRoles ...TenantRole) gin.H
}
// Check if user has required role
hasRole := false
for _, requiredRole := range requiredRoles {
if tenantCtx.UserRole == requiredRole {
hasRole = true
break
}
}
hasRole := slices.Contains(requiredRoles, tenantCtx.UserRole)
if !hasRole {
tm.logger.WithFields(logrus.Fields{
@@ -293,7 +288,7 @@ func (tm *TenantMiddleware) LogTenantActivity(activity string) gin.HandlerFunc {
TenantID: tenantCtx.TenantID,
UserID: userID,
EventType: TenantEventType(activity),
EventData: map[string]interface{}{
EventData: map[string]any{
"method": c.Request.Method,
"path": c.Request.URL.Path,
"user_agent": c.Request.UserAgent(),
@@ -6,19 +6,19 @@ import (
// Tenant represents a multi-tenant organization
type Tenant struct {
ID string `json:"id" gorm:"primaryKey;column:id"`
Name string `json:"name" gorm:"column:name;not null"`
Domain string `json:"domain" gorm:"column:domain;uniqueIndex"`
Status TenantStatus `json:"status" gorm:"column:status;not null"`
Plan TenantPlan `json:"plan" gorm:"column:plan;not null"`
MaxUsers int `json:"max_users" gorm:"column:max_users"`
MaxProfiles int `json:"max_profiles" gorm:"column:max_profiles"`
MaxCarriers int `json:"max_carriers" gorm:"column:max_carriers"`
Settings *TenantSettings `json:"settings" gorm:"column:settings;serializer:json"`
Metadata map[string]interface{} `json:"metadata" gorm:"column:metadata;serializer:json"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
DeletedAt *time.Time `json:"deleted_at,omitempty" gorm:"column:deleted_at"`
ID string `json:"id" gorm:"primaryKey;column:id"`
Name string `json:"name" gorm:"column:name;not null"`
Domain string `json:"domain" gorm:"column:domain;uniqueIndex"`
Status TenantStatus `json:"status" gorm:"column:status;not null"`
Plan TenantPlan `json:"plan" gorm:"column:plan;not null"`
MaxUsers int `json:"max_users" gorm:"column:max_users"`
MaxProfiles int `json:"max_profiles" gorm:"column:max_profiles"`
MaxCarriers int `json:"max_carriers" gorm:"column:max_carriers"`
Settings *TenantSettings `json:"settings" gorm:"column:settings;serializer:json"`
Metadata map[string]any `json:"metadata" gorm:"column:metadata;serializer:json"`
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
DeletedAt *time.Time `json:"deleted_at,omitempty" gorm:"column:deleted_at"`
}
// TableName returns the table name for Tenant
+49 -49
View File
@@ -19,26 +19,26 @@ type TenantFilter struct {
// CreateTenantRequest represents a request to create a new tenant
type CreateTenantRequest struct {
Name string `json:"name" binding:"required"`
Domain string `json:"domain" binding:"required"`
Plan TenantPlan `json:"plan" binding:"required"`
MaxUsers int `json:"max_users"`
MaxProfiles int `json:"max_profiles"`
MaxCarriers int `json:"max_carriers"`
Settings *TenantSettings `json:"settings,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
Name string `json:"name" binding:"required"`
Domain string `json:"domain" binding:"required"`
Plan TenantPlan `json:"plan" binding:"required"`
MaxUsers int `json:"max_users"`
MaxProfiles int `json:"max_profiles"`
MaxCarriers int `json:"max_carriers"`
Settings *TenantSettings `json:"settings,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
// UpdateTenantRequest represents a request to update a tenant
type UpdateTenantRequest struct {
Name *string `json:"name,omitempty"`
Status *TenantStatus `json:"status,omitempty"`
Plan *TenantPlan `json:"plan,omitempty"`
MaxUsers *int `json:"max_users,omitempty"`
MaxProfiles *int `json:"max_profiles,omitempty"`
MaxCarriers *int `json:"max_carriers,omitempty"`
Settings *TenantSettings `json:"settings,omitempty"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
Name *string `json:"name,omitempty"`
Status *TenantStatus `json:"status,omitempty"`
Plan *TenantPlan `json:"plan,omitempty"`
MaxUsers *int `json:"max_users,omitempty"`
MaxProfiles *int `json:"max_profiles,omitempty"`
MaxCarriers *int `json:"max_carriers,omitempty"`
Settings *TenantSettings `json:"settings,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
// TenantUserFilter defines filtering options for tenant user queries
@@ -87,8 +87,8 @@ type UpdateAPIKeyRequest struct {
type TenantUsageFilter struct {
TenantID string `json:"tenant_id,omitempty"`
ResourceType string `json:"resource_type,omitempty"`
PeriodStart time.Time `json:"period_start,omitempty"`
PeriodEnd time.Time `json:"period_end,omitempty"`
PeriodStart time.Time `json:"period_start"`
PeriodEnd time.Time `json:"period_end"`
Limit int `json:"limit,omitempty"`
Offset int `json:"offset,omitempty"`
}
@@ -121,13 +121,13 @@ type QuotaStatus struct {
// TenantContext represents tenant context for request processing
type TenantContext struct {
TenantID string `json:"tenant_id"`
TenantName string `json:"tenant_name"`
Plan TenantPlan `json:"plan"`
UserID string `json:"user_id"`
UserRole TenantRole `json:"user_role"`
Settings *TenantSettings `json:"settings"`
Metadata map[string]interface{} `json:"metadata"`
TenantID string `json:"tenant_id"`
TenantName string `json:"tenant_name"`
Plan TenantPlan `json:"plan"`
UserID string `json:"user_id"`
UserRole TenantRole `json:"user_role"`
Settings *TenantSettings `json:"settings"`
Metadata map[string]any `json:"metadata"`
}
// ResourceQuota represents resource quota configuration
@@ -148,23 +148,23 @@ type ResourceUsage struct {
// TenantConfig represents tenant-specific configuration
type TenantConfig struct {
TenantID string `json:"tenant_id"`
Config map[string]interface{} `json:"config"`
Settings *TenantSettings `json:"settings"`
Quotas []ResourceQuota `json:"quotas"`
Features map[string]bool `json:"features"`
TenantID string `json:"tenant_id"`
Config map[string]any `json:"config"`
Settings *TenantSettings `json:"settings"`
Quotas []ResourceQuota `json:"quotas"`
Features map[string]bool `json:"features"`
}
// TenantEvent represents events related to a tenant
type TenantEvent struct {
ID string `json:"id"`
TenantID string `json:"tenant_id"`
UserID string `json:"user_id"`
EventType TenantEventType `json:"event_type"`
EventData map[string]interface{} `json:"event_data"`
Timestamp time.Time `json:"timestamp"`
IPAddress string `json:"ip_address"`
UserAgent string `json:"user_agent"`
ID string `json:"id"`
TenantID string `json:"tenant_id"`
UserID string `json:"user_id"`
EventType TenantEventType `json:"event_type"`
EventData map[string]any `json:"event_data"`
Timestamp time.Time `json:"timestamp"`
IPAddress string `json:"ip_address"`
UserAgent string `json:"user_agent"`
}
// TenantEventType represents types of tenant events
@@ -236,9 +236,9 @@ type UsageTrend struct {
// UsagePeak represents a usage peak
type UsagePeak struct {
Timestamp time.Time `json:"timestamp"`
Usage int `json:"usage"`
Context map[string]interface{} `json:"context"`
Timestamp time.Time `json:"timestamp"`
Usage int `json:"usage"`
Context map[string]any `json:"context"`
}
// TenantPerformanceAnalytics represents performance analytics
@@ -282,16 +282,16 @@ type APIRequestEvent struct {
// ErrorEvent represents an error event
type ErrorEvent struct {
Timestamp time.Time `json:"timestamp"`
Error string `json:"error"`
Context map[string]interface{} `json:"context"`
UserID string `json:"user_id"`
Timestamp time.Time `json:"timestamp"`
Error string `json:"error"`
Context map[string]any `json:"context"`
UserID string `json:"user_id"`
}
// SlowQuery represents a slow query event
type SlowQuery struct {
Timestamp time.Time `json:"timestamp"`
Query string `json:"query"`
Duration time.Duration `json:"duration"`
Context map[string]interface{} `json:"context"`
Timestamp time.Time `json:"timestamp"`
Query string `json:"query"`
Duration time.Duration `json:"duration"`
Context map[string]any `json:"context"`
}