mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-07 00:37:36 +00:00
91 lines
3.3 KiB
Go
91 lines
3.3 KiB
Go
package licensing
|
|
|
|
import "strings"
|
|
|
|
func DefaultBillingState() *BillingState {
|
|
return &BillingState{
|
|
Capabilities: []string{},
|
|
Limits: map[string]int64{},
|
|
MetersEnabled: []string{},
|
|
PlanVersion: string(SubStateTrial),
|
|
SubscriptionState: SubStateTrial,
|
|
}
|
|
}
|
|
|
|
func NormalizeBillingState(state *BillingState) *BillingState {
|
|
if state == nil {
|
|
return DefaultBillingState()
|
|
}
|
|
|
|
// Start with a full struct copy so new fields are never silently dropped.
|
|
cp := *state
|
|
normalized := &cp
|
|
|
|
// Deep-clone reference types to avoid aliasing the original.
|
|
normalized.Capabilities = append([]string(nil), state.Capabilities...)
|
|
normalized.MetersEnabled = append([]string(nil), state.MetersEnabled...)
|
|
normalized.Limits = make(map[string]int64, len(state.Limits))
|
|
for key, value := range state.Limits {
|
|
normalized.Limits[key] = value
|
|
}
|
|
|
|
// Clone pointer fields so the caller can't mutate through the original.
|
|
normalized.TrialStartedAt = cloneInt64Ptr(state.TrialStartedAt)
|
|
normalized.TrialEndsAt = cloneInt64Ptr(state.TrialEndsAt)
|
|
normalized.TrialExtendedAt = cloneInt64Ptr(state.TrialExtendedAt)
|
|
normalized.OverflowGrantedAt = cloneInt64Ptr(state.OverflowGrantedAt)
|
|
normalized.QuickstartCreditsGrantedAt = cloneInt64Ptr(state.QuickstartCreditsGrantedAt)
|
|
normalized.CommercialMigration = CloneCommercialMigrationStatus(state.CommercialMigration)
|
|
|
|
// Normalize string fields.
|
|
normalized.PlanVersion = strings.TrimSpace(normalized.PlanVersion)
|
|
normalized.SubscriptionState = SubscriptionState(strings.ToLower(strings.TrimSpace(string(normalized.SubscriptionState))))
|
|
normalized.EntitlementJWT = strings.TrimSpace(normalized.EntitlementJWT)
|
|
normalized.EntitlementRefreshToken = strings.TrimSpace(normalized.EntitlementRefreshToken)
|
|
normalized.StripeCustomerID = strings.TrimSpace(normalized.StripeCustomerID)
|
|
normalized.StripeSubscriptionID = strings.TrimSpace(normalized.StripeSubscriptionID)
|
|
normalized.StripePriceID = strings.TrimSpace(normalized.StripePriceID)
|
|
normalized.CommercialMigration = NormalizeCommercialMigrationStatus(normalized.CommercialMigration)
|
|
|
|
normalized.Limits = NormalizeMonitoredSystemLimits(normalized.Limits)
|
|
|
|
// Ensure slices/maps are never nil (JSON marshals as [] / {} instead of null).
|
|
if normalized.Capabilities == nil {
|
|
normalized.Capabilities = []string{}
|
|
}
|
|
if normalized.Limits == nil {
|
|
normalized.Limits = map[string]int64{}
|
|
}
|
|
if normalized.MetersEnabled == nil {
|
|
normalized.MetersEnabled = []string{}
|
|
}
|
|
// Preserve absence when the stored hosted billing record has no plan label.
|
|
// Canonical defaults still come from DefaultBillingState()/call-site defaults.
|
|
normalized.PlanVersion = CanonicalizePlanVersion(normalized.PlanVersion)
|
|
switch normalized.SubscriptionState {
|
|
case SubStateExpired, SubStateSuspended, SubStateCanceled:
|
|
normalized.Capabilities = []string{}
|
|
normalized.Limits = map[string]int64{}
|
|
normalized.MetersEnabled = []string{}
|
|
default:
|
|
if limit, known := CloudPlanMonitoredSystemLimits[normalized.PlanVersion]; known {
|
|
normalized.Limits[MaxMonitoredSystemsLicenseGateKey] = int64(limit)
|
|
}
|
|
}
|
|
|
|
return normalized
|
|
}
|
|
|
|
func IsValidBillingSubscriptionState(state SubscriptionState) bool {
|
|
switch state {
|
|
case SubStateTrial,
|
|
SubStateActive,
|
|
SubStateGrace,
|
|
SubStateExpired,
|
|
SubStateSuspended,
|
|
SubStateCanceled:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|