Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
131 lines
4.3 KiB
Go
131 lines
4.3 KiB
Go
package billing
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// IsCustomPackage reports whether a plan should get the "custom deal" feature
|
|
// treatment (all dashboard features ON by default for non-A1 deals).
|
|
//
|
|
// Product semantics (see IsPublicProductPlan + plans.is_custom):
|
|
// - Client / admin deals with is_custom=true → custom (including A1 PAYG)
|
|
// - Public Enterprise (and any row with is_custom=true) → custom
|
|
// - Exact "Legacy" plan name → never enable-all (restricted migrated matrix)
|
|
// - Free / Starter / Growth / Business with is_custom=false → not custom
|
|
//
|
|
// is_custom wins over A1* name patterns for PAYG billing / PlanProfileCustom,
|
|
// but A1* custom deals use A1PaygPlanFeatures (not literal enable-all) so
|
|
// Stores, Marketing, and Integrations stay off.
|
|
func IsCustomPackage(name string, isCustom bool) bool {
|
|
if strings.EqualFold(strings.TrimSpace(name), LegacyPlanName) {
|
|
return false
|
|
}
|
|
if isCustom {
|
|
return true
|
|
}
|
|
// Legacy-named plans without is_custom stay on the limited matrix.
|
|
if IsLegacyPlanName(name) {
|
|
return false
|
|
}
|
|
return !IsPublicProductPlan(name)
|
|
}
|
|
|
|
// A1PaygFeatureDenied reports keys that stay OFF on A1 PAYG custom deals.
|
|
// Nav: Stores → stores.*; Marketing → marketing.*; Integrations → integrations.*.
|
|
// Cutover honesty chrome (ETL gaps / reconnect / migrated checklist) stays OFF — A1 is not a
|
|
// hypercare merchant surface (see MigratedEtlGapsPanel + IsA1CohortCompany product rules).
|
|
func A1PaygFeatureDenied(key string) bool {
|
|
switch key {
|
|
case "dashboard.etl_gaps", "dashboard.store_reconnect", "dashboard.migrated_checklist":
|
|
return true
|
|
}
|
|
return strings.HasPrefix(key, "stores.") ||
|
|
strings.HasPrefix(key, "marketing.") ||
|
|
strings.HasPrefix(key, "integrations.")
|
|
}
|
|
|
|
// A1PaygPlanFeatures is the dump-faithful A1 PAYG matrix: custom enable-all
|
|
// minus Stores, Marketing, and Integrations sections.
|
|
func A1PaygPlanFeatures() map[string]bool {
|
|
out := AllRegistryFeatures(true)
|
|
for k := range out {
|
|
if A1PaygFeatureDenied(k) {
|
|
out[k] = false
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// SparseA1PaygOverrides returns explicit false overrides for A1 PAYG denied keys.
|
|
func SparseA1PaygOverrides() map[string]bool {
|
|
out := make(map[string]bool)
|
|
for _, k := range FeatureCatalogKeys {
|
|
if A1PaygFeatureDenied(k) {
|
|
out[k] = false
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// AllRegistryFeatures returns every FeatureCatalogKeys entry set to enabled.
|
|
func AllRegistryFeatures(enabled bool) map[string]bool {
|
|
out := make(map[string]bool, len(FeatureCatalogKeys))
|
|
for _, k := range FeatureCatalogKeys {
|
|
out[k] = enabled
|
|
}
|
|
return out
|
|
}
|
|
|
|
// EnableSectionForAllPlans turns a section master switch ON for every plan
|
|
// (global gate; missing rows already default ON).
|
|
func (s *Service) EnableSectionForAllPlans(ctx context.Context, section string, updatedBy *uuid.UUID) (FeatureGatesView, error) {
|
|
return s.SetSectionGate(ctx, section, true, updatedBy)
|
|
}
|
|
|
|
// DisableSectionForAllPlans turns a section master switch OFF for every plan.
|
|
func (s *Service) DisableSectionForAllPlans(ctx context.Context, section string, updatedBy *uuid.UUID) (FeatureGatesView, error) {
|
|
return s.SetSectionGate(ctx, section, false, updatedBy)
|
|
}
|
|
|
|
// prepareCustomPackageCreateFeatures applies create-time defaults for custom packages:
|
|
// when the caller omitted features, materialize enable-all overrides so admin UIs
|
|
// show an explicit all-ON matrix (resolve already treats empty+is_custom as all ON).
|
|
func prepareCustomPackageCreateFeatures(p *Plan, creating, featuresProvided bool) {
|
|
if !creating {
|
|
return
|
|
}
|
|
if IsLegacyPlan(p.Name, p.IsLegacy) && !IsCustomPackage(p.Name, p.IsCustom) {
|
|
p.IsLegacy = true
|
|
if strings.EqualFold(strings.TrimSpace(p.Name), LegacyPlanName) {
|
|
p.IsCustom = false
|
|
} else if !IsPublicProductPlan(p.Name) {
|
|
p.IsCustom = true
|
|
}
|
|
if !featuresProvided {
|
|
p.Features = SparseLegacyOverrides()
|
|
}
|
|
return
|
|
}
|
|
// Non-public ladder names are client deals — keep is_custom aligned.
|
|
if !IsPublicProductPlan(p.Name) {
|
|
p.IsCustom = true
|
|
}
|
|
// A1 PAYG / custom deals are never the restricted Legacy matrix.
|
|
if IsCustomPackage(p.Name, p.IsCustom) {
|
|
p.IsLegacy = false
|
|
}
|
|
if featuresProvided {
|
|
return
|
|
}
|
|
if IsCustomPackage(p.Name, p.IsCustom) {
|
|
if IsLegacyPlanName(p.Name) {
|
|
p.Features = A1PaygPlanFeatures()
|
|
return
|
|
}
|
|
p.Features = AllRegistryFeatures(true)
|
|
}
|
|
}
|