package billing import ( "strings" ) // A1LegacyCompanyID is the MySQL company_id for A1 Slovenija (migrated dump name kept in PG). // Cohort remains legacy even if an older local rename used "Local Demo Co". const A1LegacyCompanyID = "97e1a309-3d23-4aa2-b518-8e8d7afdfec7" // LegacyPlanName is the seeded package name for migrated / limited-nav tenants. const LegacyPlanName = "Legacy" // PlanProfile is the packaging bucket used for default feature matrices. type PlanProfile string const ( PlanProfileFree PlanProfile = "free" PlanProfileStarter PlanProfile = "starter" PlanProfileGrowth PlanProfile = "growth" PlanProfileBusiness PlanProfile = "business" PlanProfileEnterprise PlanProfile = "enterprise" PlanProfileLegacy PlanProfile = "legacy" PlanProfileCustom PlanProfile = "custom" ) // legacyFeatureAllowlist is the ON set for the legacy (A1) matrix. // Source: docs/admin-roles-support/03-roles-matrix.md / .json (legacy_user). var legacyFeatureAllowlist = map[string]struct{}{ "shell.navigation": {}, "shell.command_palette": {}, "shell.company_switcher": {}, "shell.tutorial": {}, "shell.account_menu": {}, "shell.billing_recovery_banner": {}, "dashboard.overview": {}, "dashboard.stats": {}, "dashboard.quick_links": {}, "dashboard.recent_jobs": {}, "dashboard.news_feed": {}, "dashboard.activation_checklist": {}, "dashboard.migrated_checklist": {}, "dashboard.etl_gaps": {}, "dashboard.upgrade_banners": {}, "catalog.products": {}, "catalog.products.tab_processed": {}, "catalog.products.tab_needs_review": {}, "catalog.products.tab_error": {}, "catalog.products.tab_processing": {}, "catalog.products.tab_unprocessed": {}, "catalog.products.process_categories": {}, "catalog.products.process_attributes": {}, "catalog.products.process_ai_titles": {}, "catalog.products.process_ai_descriptions": {}, "catalog.products.enrichment_review": {}, "catalog.products.export_selection": {}, "catalog.products.upgrade_prompt": {}, "catalog.categories": {}, "catalog.categories.title_formula": {}, "catalog.categories.description_formula": {}, "catalog.attributes": {}, "catalog.attributes.bulk_import": {}, "catalog.standard_fields": {}, "catalog.standard_fields.groups": {}, "feeds.list": {}, "feeds.add_url": {}, "feeds.add_csv": {}, "feeds.sync": {}, "feeds.mapping": {}, "feeds.mapping.select_item": {}, "feeds.mapping.map_fields": {}, "feeds.export_feeds": {}, "feeds.export_feeds.create": {}, "feeds.export_feeds.generate": {}, "feeds.uploads": {}, "billing.overview": {}, "billing.customer_portal": {}, "billing.quick_upgrade": {}, "billing.plans_compare": {}, "billing.checkout": {}, "settings.profile": {}, "settings.company": {}, "settings.alerts": {}, "settings.api_keys": {}, "settings.team": {}, "settings.team_invite": {}, "capability.sku_cap": {}, "capability.ai_credits": {}, "capability.ai_processing": {}, "capability.eprel": {}, "capability.normalize_specs_fill": {}, "capability.feed_source_limit": {}, "capability.export_feed_limit": {}, "capability.storage_limit": {}, "capability.api_access": {}, } // IsLegacyPlanName reports whether a plan name matches the legacy cohort patterns // (exact "legacy", A1*, or "a1 slovenija"). See docs/admin-roles-support/03-roles-matrix.md. func IsLegacyPlanName(planName string) bool { n := strings.ToLower(strings.TrimSpace(planName)) if n == "" { return false } if n == "legacy" { return true } if strings.Contains(n, "a1 slovenija") { return true } if n == "a1" || strings.HasPrefix(n, "a1 ") || strings.HasPrefix(n, "a1-") || strings.HasPrefix(n, "a1_") { return true } return false } // IsLegacyPlan reports legacy packaging from an explicit flag and/or name patterns. func IsLegacyPlan(planName string, isLegacyFlag bool) bool { return isLegacyFlag || IsLegacyPlanName(planName) } // IsLegacyCompanyID reports whether a remapped legacy MySQL company id is the A1 cohort. func IsLegacyCompanyID(legacyCompanyID string) bool { return strings.EqualFold(strings.TrimSpace(legacyCompanyID), A1LegacyCompanyID) } // IsA1CohortCompany reports whether a company is the migrated A1 tenant. // Match only immutable legacy_company_id — never mutable display names // (register/rename to "A1" must not grant Legacy plan privileges). // companyName is retained for call-site compatibility; it is ignored. func IsA1CohortCompany(legacyCompanyID, companyName string) bool { _ = companyName return IsLegacyCompanyID(legacyCompanyID) } // LegacyFeatureAllowed reports whether key is ON in the legacy matrix. func LegacyFeatureAllowed(key string) bool { _, ok := legacyFeatureAllowlist[key] return ok } // ResolvePlanProfile maps name + flags to the default matrix bucket. func ResolvePlanProfile(planName string, isCustom, isLegacyFlag bool) PlanProfile { if IsCustomPackage(planName, isCustom) { norm := strings.ToLower(strings.TrimSpace(planName)) if norm == "enterprise" { return PlanProfileEnterprise } return PlanProfileCustom } if IsLegacyPlan(planName, isLegacyFlag) { return PlanProfileLegacy } norm := strings.ToLower(strings.TrimSpace(planName)) switch norm { case "", "free": return PlanProfileFree case "starter", "plus": return PlanProfileStarter case "growth": return PlanProfileGrowth case "business", "scale": return PlanProfileBusiness case "enterprise": return PlanProfileEnterprise } return PlanProfileFree }