Parcourir la source

Add trials logic

Mauricio Araujo il y a 2 ans
Parent
commit
3be49056ec

+ 1 - 9
api/server/handlers/billing/invoices.go

@@ -1,7 +1,6 @@
 package billing
 package billing
 
 
 import (
 import (
-	"fmt"
 	"net/http"
 	"net/http"
 
 
 	"github.com/porter-dev/porter/api/server/handlers"
 	"github.com/porter-dev/porter/api/server/handlers"
@@ -54,13 +53,6 @@ func (c *ListCustomerInvoicesHandler) ServeHTTP(w http.ResponseWriter, r *http.R
 		return
 		return
 	}
 	}
 
 
-	invoices, err := c.Config().BillingManager.StripeClient.ListCustomerInvoices(ctx, proj.BillingID, req.Status)
-	if err != nil {
-		err = telemetry.Error(ctx, span, err, fmt.Sprintf("error listing invoices for customer %s", proj.BillingID))
-		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
-		return
-	}
-
 	// Write the response to the frontend
 	// Write the response to the frontend
-	c.WriteResult(w, r, invoices)
+	c.WriteResult(w, r, "invoices")
 }
 }

+ 6 - 5
api/server/shared/config/env/envconfs.go

@@ -69,11 +69,12 @@ type ServerConf struct {
 	SendgridDeleteProjectTemplateID    string `env:"SENDGRID_DELETE_PROJECT_TEMPLATE_ID"`
 	SendgridDeleteProjectTemplateID    string `env:"SENDGRID_DELETE_PROJECT_TEMPLATE_ID"`
 	SendgridSenderEmail                string `env:"SENDGRID_SENDER_EMAIL"`
 	SendgridSenderEmail                string `env:"SENDGRID_SENDER_EMAIL"`
 
 
-	StripeSecretKey      string `env:"STRIPE_SECRET_KEY"`
-	StripePublishableKey string `env:"STRIPE_PUBLISHABLE_KEY"`
-	LagoAPIKey           string `env:"LAGO_API_KEY"`
-	PorterCloudPlanID    string `env:"PORTER_CLOUD_PLAN_ID"`
-	PorterStandardPlanID string `env:"PORTER_STANDARD_PLAN_ID"`
+	StripeSecretKey        string `env:"STRIPE_SECRET_KEY"`
+	StripePublishableKey   string `env:"STRIPE_PUBLISHABLE_KEY"`
+	LagoAPIKey             string `env:"LAGO_API_KEY"`
+	PorterCloudPlanCode    string `env:"PORTER_CLOUD_PLAN_CODE"`
+	PorterStandardPlanCode string `env:"PORTER_STANDARD_PLAN_CODE"`
+	PorterTrialCode        string `env:"PORTER_TRIAL_CODE"`
 
 
 	// The URL of the webhook to verify ingesting events works
 	// The URL of the webhook to verify ingesting events works
 	IngestStatusWebhookUrl string `env:"INGEST_STATUS_WEBHOOK_URL"`
 	IngestStatusWebhookUrl string `env:"INGEST_STATUS_WEBHOOK_URL"`

+ 3 - 3
api/server/shared/config/loader/loader.go

@@ -371,15 +371,15 @@ func (e *EnvConfigLoader) LoadConfig() (res *config.Config, err error) {
 		res.Logger.Info().Msg("STRIPE_SECRET_KEY not set, all Stripe functionality will be disabled")
 		res.Logger.Info().Msg("STRIPE_SECRET_KEY not set, all Stripe functionality will be disabled")
 	}
 	}
 
 
-	if sc.LagoAPIKey != "" && sc.PorterCloudPlanID != "" && sc.PorterStandardPlanID != "" {
-		lagoClient, err = billing.NewLagoClient(InstanceEnvConf.ServerConf.LagoAPIKey, InstanceEnvConf.ServerConf.PorterCloudPlanID, InstanceEnvConf.ServerConf.PorterStandardPlanID)
+	if sc.LagoAPIKey != "" && sc.PorterCloudPlanCode != "" && sc.PorterStandardPlanCode != "" && sc.PorterTrialCode != "" {
+		lagoClient, err = billing.NewLagoClient(InstanceEnvConf.ServerConf.LagoAPIKey, InstanceEnvConf.ServerConf.PorterCloudPlanCode, InstanceEnvConf.ServerConf.PorterStandardPlanCode, InstanceEnvConf.ServerConf.PorterTrialCode)
 		if err != nil {
 		if err != nil {
 			return nil, fmt.Errorf("unable to create Lago client: %w", err)
 			return nil, fmt.Errorf("unable to create Lago client: %w", err)
 		}
 		}
 		metronomeEnabled = true
 		metronomeEnabled = true
 		res.Logger.Info().Msg("Lago configuration loaded")
 		res.Logger.Info().Msg("Lago configuration loaded")
 	} else {
 	} else {
-		res.Logger.Info().Msg("LAGO_API_KEY, PORTER_CLOUD_PLAN_ID, or PORTER_STANDARD_PLAN_ID not set, all Metronome functionality will be disabled")
+		res.Logger.Info().Msg("LAGO_API_KEY, PORTER_CLOUD_PLAN_CODE, PORTER_STANDARD_PLAN_CODE and PORTER_TRIAL_CODE must be set, all Lago functionality will be disabled")
 	}
 	}
 
 
 	res.Logger.Info().Msg("Creating billing manager")
 	res.Logger.Info().Msg("Creating billing manager")

+ 0 - 39
internal/billing/stripe.go

@@ -4,13 +4,11 @@ import (
 	"context"
 	"context"
 	"fmt"
 	"fmt"
 	"strconv"
 	"strconv"
-	"time"
 
 
 	"github.com/porter-dev/porter/api/types"
 	"github.com/porter-dev/porter/api/types"
 	"github.com/porter-dev/porter/internal/telemetry"
 	"github.com/porter-dev/porter/internal/telemetry"
 	"github.com/stripe/stripe-go/v76"
 	"github.com/stripe/stripe-go/v76"
 	"github.com/stripe/stripe-go/v76/customer"
 	"github.com/stripe/stripe-go/v76/customer"
-	"github.com/stripe/stripe-go/v76/invoice"
 	"github.com/stripe/stripe-go/v76/paymentmethod"
 	"github.com/stripe/stripe-go/v76/paymentmethod"
 	"github.com/stripe/stripe-go/v76/setupintent"
 	"github.com/stripe/stripe-go/v76/setupintent"
 )
 )
@@ -245,43 +243,6 @@ func (s StripeClient) GetPublishableKey(ctx context.Context) (key string) {
 	return s.PublishableKey
 	return s.PublishableKey
 }
 }
 
 
-// ListCustomerInvoices will return all invoices for the customer with the given status
-func (s StripeClient) ListCustomerInvoices(ctx context.Context, customerID string, status string) (invoiceList []types.Invoice, err error) {
-	ctx, span := telemetry.NewSpan(ctx, "populate-invoice-urls")
-	defer span.End()
-
-	if customerID == "" {
-		return invoiceList, telemetry.Error(ctx, span, err, "customer id cannot be empty")
-	}
-
-	stripe.Key = s.SecretKey
-
-	params := &stripe.InvoiceListParams{
-		Customer: stripe.String(customerID),
-		Status:   stripe.String(status),
-	}
-
-	result := invoice.List(params)
-
-	for result.Next() {
-		invoice := result.Current().(*stripe.Invoice)
-
-		if invoice == nil {
-			continue
-		}
-
-		createdTimestamp := time.Unix(invoice.Created, 0)
-
-		invoiceList = append(invoiceList, types.Invoice{
-			HostedInvoiceURL: invoice.HostedInvoiceURL,
-			Status:           string(invoice.Status),
-			Created:          createdTimestamp.Format(time.RFC3339),
-		})
-	}
-
-	return invoiceList, nil
-}
-
 func (s StripeClient) checkDefaultPaymentMethod(customerID string) (defaultPaymentExists bool, defaultPaymentID string, err error) {
 func (s StripeClient) checkDefaultPaymentMethod(customerID string) (defaultPaymentExists bool, defaultPaymentID string, err error) {
 	// Get customer to check default payment method
 	// Get customer to check default payment method
 	customer, err := customer.Get(customerID, nil)
 	customer, err := customer.Get(customerID, nil)

+ 66 - 32
internal/billing/usage.go

@@ -17,10 +17,15 @@ const (
 	defaultMaxRetries        = 10
 	defaultMaxRetries        = 10
 	maxIngestEventLimit      = 100
 	maxIngestEventLimit      = 100
 
 
+	// porterStandardTrialDays is the number of days for the trial
+	porterStandardTrialDays = 15
+
 	// These prefixes are used to build the customer and subscription IDs
 	// These prefixes are used to build the customer and subscription IDs
 	// in Lago. This way we can reuse the project IDs instead of storing
 	// in Lago. This way we can reuse the project IDs instead of storing
 	// the Lago IDs in the database.
 	// the Lago IDs in the database.
 
 
+	// TrialIDPrefix is the prefix for the trial ID
+	TrialIDPrefix = "trial"
 	// SubscriptionIDPrefix is the prefix for the subscription ID
 	// SubscriptionIDPrefix is the prefix for the subscription ID
 	SubscriptionIDPrefix = "sub"
 	SubscriptionIDPrefix = "sub"
 	// CustomerIDPrefix is the prefix for the customer ID
 	// CustomerIDPrefix is the prefix for the customer ID
@@ -29,9 +34,10 @@ const (
 
 
 // LagoClient is the client used to call the Lago API
 // LagoClient is the client used to call the Lago API
 type LagoClient struct {
 type LagoClient struct {
-	client               lago.Client
-	PorterCloudPlanID    string
-	PorterStandardPlanID string
+	client                 lago.Client
+	PorterCloudPlanCode    string
+	PorterStandardPlanCode string
+	PorterTrialCode        string
 
 
 	// DefaultRewardAmountCents is the default amount in USD cents rewarded to users
 	// DefaultRewardAmountCents is the default amount in USD cents rewarded to users
 	// who successfully refer a new user
 	// who successfully refer a new user
@@ -40,48 +46,65 @@ type LagoClient struct {
 	MaxReferralRewards int64
 	MaxReferralRewards int64
 }
 }
 
 
-// NewLagoClient returns a new Metronome client
-func NewLagoClient(lagoApiKey string, porterCloudPlanID string, porterStandardPlanID string) (client LagoClient, err error) {
+// NewLagoClient returns a new Lago client
+func NewLagoClient(lagoApiKey string, porterCloudPlanCode string, porterStandardPlanCode string, porterTrialCode string) (client LagoClient, err error) {
 	lagoClient := lago.New().
 	lagoClient := lago.New().
 		SetApiKey("__YOU_API_KEY__")
 		SetApiKey("__YOU_API_KEY__")
 
 
 	return LagoClient{
 	return LagoClient{
 		client:                   *lagoClient,
 		client:                   *lagoClient,
-		PorterCloudPlanID:        porterCloudPlanID,
-		PorterStandardPlanID:     porterStandardPlanID,
+		PorterCloudPlanCode:      porterCloudPlanCode,
+		PorterStandardPlanCode:   porterStandardPlanCode,
+		PorterTrialCode:          porterTrialCode,
 		DefaultRewardAmountCents: defaultRewardAmountCents,
 		DefaultRewardAmountCents: defaultRewardAmountCents,
 		MaxReferralRewards:       maxReferralRewards,
 		MaxReferralRewards:       maxReferralRewards,
 	}, nil
 	}, nil
 }
 }
 
 
-// CreateCustomerWithPlan will create the customer in Metronome and immediately add it to the plan
+// CreateCustomerWithPlan will create the customer in Lago and immediately add it to the plan
 func (m LagoClient) CreateCustomerWithPlan(ctx context.Context, userEmail string, projectName string, projectID uint, billingID string, sandboxEnabled bool) (err error) {
 func (m LagoClient) CreateCustomerWithPlan(ctx context.Context, userEmail string, projectName string, projectID uint, billingID string, sandboxEnabled bool) (err error) {
-	ctx, span := telemetry.NewSpan(ctx, "add-metronome-customer-plan")
+	ctx, span := telemetry.NewSpan(ctx, "add-lago-customer-plan")
 	defer span.End()
 	defer span.End()
 
 
-	planID := m.PorterStandardPlanID
+	customerID, err := m.createCustomer(ctx, userEmail, projectName, projectID, billingID, sandboxEnabled)
+	if err != nil {
+		return telemetry.Error(ctx, span, err, "error while creating customer")
+	}
+
+	trialID := m.generateLagoID(TrialIDPrefix, projectID, sandboxEnabled)
+	subscriptionID := m.generateLagoID(SubscriptionIDPrefix, projectID, sandboxEnabled)
+	now := time.Now()
+	trialEndTime := now.Add(time.Hour * 24 * porterStandardTrialDays)
+
 	if sandboxEnabled {
 	if sandboxEnabled {
-		planID = m.PorterCloudPlanID
+		err = m.addCustomerPlan(ctx, customerID, m.PorterCloudPlanCode, subscriptionID, &now, nil)
+		if err != nil {
+			return telemetry.Error(ctx, span, err, fmt.Sprintf("error while adding customer to plan %s", m.PorterCloudPlanCode))
+		}
+		return nil
 	}
 	}
 
 
-	customerID, err := m.createCustomer(ctx, userEmail, projectName, projectID, billingID, sandboxEnabled)
+	// First, start the new customer on the trial
+	err = m.addCustomerPlan(ctx, customerID, m.PorterTrialCode, trialID, &now, &trialEndTime)
 	if err != nil {
 	if err != nil {
-		return telemetry.Error(ctx, span, err, fmt.Sprintf("error while creating customer with plan %s", planID))
+		return telemetry.Error(ctx, span, err, fmt.Sprintf("error while starting customer trial %s", m.PorterTrialCode))
 	}
 	}
 
 
-	subscriptionID := m.GenerateLagoID(SubscriptionIDPrefix, projectID, sandboxEnabled)
-
-	err = m.addCustomerPlan(ctx, customerID, planID, subscriptionID)
+	// Then, add the customer to the actual plan. The date of the subscription will be the end of the trial
+	err = m.addCustomerPlan(ctx, customerID, m.PorterStandardPlanCode, subscriptionID, &trialEndTime, nil)
+	if err != nil {
+		return telemetry.Error(ctx, span, err, fmt.Sprintf("error while adding customer to plan %s", m.PorterStandardPlanCode))
+	}
 
 
 	return err
 	return err
 }
 }
 
 
-// createCustomer will create the customer in Metronome
+// createCustomer will create the customer in Lago
 func (m LagoClient) createCustomer(ctx context.Context, userEmail string, projectName string, projectID uint, billingID string, sandboxEnabled bool) (customerID string, err error) {
 func (m LagoClient) createCustomer(ctx context.Context, userEmail string, projectName string, projectID uint, billingID string, sandboxEnabled bool) (customerID string, err error) {
-	ctx, span := telemetry.NewSpan(ctx, "create-metronome-customer")
+	ctx, span := telemetry.NewSpan(ctx, "create-lago-customer")
 	defer span.End()
 	defer span.End()
 
 
-	customerID = m.GenerateLagoID(CustomerIDPrefix, projectID, sandboxEnabled)
+	customerID = m.generateLagoID(CustomerIDPrefix, projectID, sandboxEnabled)
 
 
 	customerInput := &lago.CustomerInput{
 	customerInput := &lago.CustomerInput{
 		ExternalID: customerID,
 		ExternalID: customerID,
@@ -101,20 +124,20 @@ func (m LagoClient) createCustomer(ctx context.Context, userEmail string, projec
 }
 }
 
 
 // addCustomerPlan will create a plan subscription for the customer
 // addCustomerPlan will create a plan subscription for the customer
-func (m LagoClient) addCustomerPlan(ctx context.Context, projectID string, planID string, subscriptionID string) (err error) {
-	ctx, span := telemetry.NewSpan(ctx, "add-metronome-customer-plan")
+func (m LagoClient) addCustomerPlan(ctx context.Context, projectID string, planID string, subscriptionID string, startingAt *time.Time, endingAt *time.Time) (err error) {
+	ctx, span := telemetry.NewSpan(ctx, "add-lago-customer-plan")
 	defer span.End()
 	defer span.End()
 
 
 	if projectID == "" || planID == "" {
 	if projectID == "" || planID == "" {
 		return telemetry.Error(ctx, span, err, "project and plan id are required")
 		return telemetry.Error(ctx, span, err, "project and plan id are required")
 	}
 	}
 
 
-	now := time.Now()
 	subscriptionInput := &lago.SubscriptionInput{
 	subscriptionInput := &lago.SubscriptionInput{
 		ExternalCustomerID: projectID,
 		ExternalCustomerID: projectID,
 		ExternalID:         subscriptionID,
 		ExternalID:         subscriptionID,
 		PlanCode:           planID,
 		PlanCode:           planID,
-		SubscriptionAt:     &now,
+		SubscriptionAt:     startingAt,
+		EndingAt:           endingAt,
 		BillingTime:        lago.Calendar,
 		BillingTime:        lago.Calendar,
 	}
 	}
 
 
@@ -135,7 +158,7 @@ func (m LagoClient) ListCustomerPlan(ctx context.Context, projectID uint, sandbo
 		return plan, telemetry.Error(ctx, span, err, "project id empty")
 		return plan, telemetry.Error(ctx, span, err, "project id empty")
 	}
 	}
 
 
-	subscriptionID := m.GenerateLagoID(SubscriptionIDPrefix, projectID, sandboxEnabled)
+	subscriptionID := m.generateLagoID(SubscriptionIDPrefix, projectID, sandboxEnabled)
 	subscription, lagoErr := m.client.Subscription().Get(ctx, subscriptionID)
 	subscription, lagoErr := m.client.Subscription().Get(ctx, subscriptionID)
 	if err != nil {
 	if err != nil {
 		return plan, telemetry.Error(ctx, span, lagoErr.Err, "failed to create subscription")
 		return plan, telemetry.Error(ctx, span, lagoErr.Err, "failed to create subscription")
@@ -150,14 +173,14 @@ func (m LagoClient) ListCustomerPlan(ctx context.Context, projectID uint, sandbo
 
 
 // EndCustomerPlan will immediately end the plan for the given customer
 // EndCustomerPlan will immediately end the plan for the given customer
 func (m LagoClient) EndCustomerPlan(ctx context.Context, projectID uint) (err error) {
 func (m LagoClient) EndCustomerPlan(ctx context.Context, projectID uint) (err error) {
-	ctx, span := telemetry.NewSpan(ctx, "end-metronome-customer-plan")
+	ctx, span := telemetry.NewSpan(ctx, "end-lago-customer-plan")
 	defer span.End()
 	defer span.End()
 
 
 	if projectID == 0 {
 	if projectID == 0 {
 		return telemetry.Error(ctx, span, err, "subscription id empty")
 		return telemetry.Error(ctx, span, err, "subscription id empty")
 	}
 	}
 
 
-	subscriptionID := m.GenerateLagoID(SubscriptionIDPrefix, projectID, false)
+	subscriptionID := m.generateLagoID(SubscriptionIDPrefix, projectID, false)
 	subscriptionTerminateInput := lago.SubscriptionTerminateInput{
 	subscriptionTerminateInput := lago.SubscriptionTerminateInput{
 		ExternalID: subscriptionID,
 		ExternalID: subscriptionID,
 	}
 	}
@@ -206,7 +229,7 @@ func (m LagoClient) CreateCreditsGrant(ctx context.Context, projectID uint, name
 		return telemetry.Error(ctx, span, err, "project id empty")
 		return telemetry.Error(ctx, span, err, "project id empty")
 	}
 	}
 
 
-	customerID := m.GenerateLagoID(CustomerIDPrefix, projectID, sandboxEnabled)
+	customerID := m.generateLagoID(CustomerIDPrefix, projectID, sandboxEnabled)
 	expiresAtTime, err := time.Parse(time.RFC3339, expiresAt)
 	expiresAtTime, err := time.Parse(time.RFC3339, expiresAt)
 	if err != nil {
 	if err != nil {
 		return telemetry.Error(ctx, span, err, "failed to parse credit expiration timestamp")
 		return telemetry.Error(ctx, span, err, "failed to parse credit expiration timestamp")
@@ -238,12 +261,12 @@ func (m LagoClient) ListCustomerUsage(ctx context.Context, projectID uint, curre
 		return usage, telemetry.Error(ctx, span, err, "project id empty")
 		return usage, telemetry.Error(ctx, span, err, "project id empty")
 	}
 	}
 
 
-	subscriptionID := m.GenerateLagoID(SubscriptionIDPrefix, projectID, sandboxEnabled)
+	subscriptionID := m.generateLagoID(SubscriptionIDPrefix, projectID, sandboxEnabled)
 	customerUsageInput := &lago.CustomerUsageInput{
 	customerUsageInput := &lago.CustomerUsageInput{
 		ExternalSubscriptionID: subscriptionID,
 		ExternalSubscriptionID: subscriptionID,
 	}
 	}
 
 
-	customerID := m.GenerateLagoID(CustomerIDPrefix, projectID, sandboxEnabled)
+	customerID := m.generateLagoID(CustomerIDPrefix, projectID, sandboxEnabled)
 	_, lagoErr := m.client.Customer().CurrentUsage(ctx, customerID, customerUsageInput)
 	_, lagoErr := m.client.Customer().CurrentUsage(ctx, customerID, customerUsageInput)
 	if lagoErr.Err != nil {
 	if lagoErr.Err != nil {
 		return usage, telemetry.Error(ctx, span, lagoErr.Err, "failed to get customer usage")
 		return usage, telemetry.Error(ctx, span, lagoErr.Err, "failed to get customer usage")
@@ -252,7 +275,7 @@ func (m LagoClient) ListCustomerUsage(ctx context.Context, projectID uint, curre
 	return usage, nil
 	return usage, nil
 }
 }
 
 
-// IngestEvents sends a list of billing events to Metronome's ingest endpoint
+// IngestEvents sends a list of billing events to Lago's ingest endpoint
 func (m LagoClient) IngestEvents(ctx context.Context, events []types.BillingEvent, enableSandbox bool) (err error) {
 func (m LagoClient) IngestEvents(ctx context.Context, events []types.BillingEvent, enableSandbox bool) (err error) {
 	ctx, span := telemetry.NewSpan(ctx, "ingets-billing-events")
 	ctx, span := telemetry.NewSpan(ctx, "ingets-billing-events")
 	defer span.End()
 	defer span.End()
@@ -275,7 +298,7 @@ func (m LagoClient) IngestEvents(ctx context.Context, events []types.BillingEven
 			if err != nil {
 			if err != nil {
 				return telemetry.Error(ctx, span, err, "failed to parse customer ID")
 				return telemetry.Error(ctx, span, err, "failed to parse customer ID")
 			}
 			}
-			externalSubscriptionID := m.GenerateLagoID(SubscriptionIDPrefix, uint(customerID), enableSandbox)
+			externalSubscriptionID := m.generateLagoID(SubscriptionIDPrefix, uint(customerID), enableSandbox)
 
 
 			event := lago.EventInput{
 			event := lago.EventInput{
 				TransactionID:          batch[i].TransactionID,
 				TransactionID:          batch[i].TransactionID,
@@ -302,7 +325,18 @@ func (m LagoClient) IngestEvents(ctx context.Context, events []types.BillingEven
 	return nil
 	return nil
 }
 }
 
 
-func (m LagoClient) GenerateLagoID(prefix string, projectID uint, sandboxEnabled bool) string {
+// ListCustomerInvoices will return all invoices for the customer with the given status
+func (s StripeClient) ListCustomerInvoices(ctx context.Context, projectID uint) (invoiceList []types.Invoice, err error) {
+	ctx, span := telemetry.NewSpan(ctx, "populate-invoice-urls")
+	defer span.End()
+
+	if projectID == 0 {
+		return invoiceList, telemetry.Error(ctx, span, err, "project id cannot be empty")
+	}
+	return invoiceList, nil
+}
+
+func (m LagoClient) generateLagoID(prefix string, projectID uint, sandboxEnabled bool) string {
 	if sandboxEnabled {
 	if sandboxEnabled {
 		return fmt.Sprintf("cloud_%s_%d", prefix, projectID)
 		return fmt.Sprintf("cloud_%s_%d", prefix, projectID)
 	}
 	}

+ 1 - 5
internal/models/project.go

@@ -146,8 +146,7 @@ type Project struct {
 	Roles []Role `json:"roles"`
 	Roles []Role `json:"roles"`
 
 
 	// BillingID corresponds to the id generated by the billing provider
 	// BillingID corresponds to the id generated by the billing provider
-	BillingID      string
-	BillingEnabled bool
+	BillingID string
 
 
 	// linked repos
 	// linked repos
 	GitRepos []GitRepo `json:"git_repos,omitempty"`
 	GitRepos []GitRepo `json:"git_repos,omitempty"`
@@ -243,8 +242,6 @@ func (p *Project) GetFeatureFlag(flagName FeatureFlagLabel, launchDarklyClient *
 			return p.AzureEnabled
 			return p.AzureEnabled
 		case "capi_provisioner_enabled":
 		case "capi_provisioner_enabled":
 			return p.CapiProvisionerEnabled
 			return p.CapiProvisionerEnabled
-		case "billing_enabled":
-			return p.BillingEnabled
 		case "db_enabled":
 		case "db_enabled":
 			return false
 			return false
 		case "enable_reprovision":
 		case "enable_reprovision":
@@ -357,7 +354,6 @@ func (p *Project) ToProjectListType() *types.ProjectList {
 		// note: all of these fields should be considered deprecated
 		// note: all of these fields should be considered deprecated
 		// in an api response
 		// in an api response
 		Roles:                  roles,
 		Roles:                  roles,
-		BillingEnabled:         p.BillingEnabled,
 		PreviewEnvsEnabled:     p.PreviewEnvsEnabled,
 		PreviewEnvsEnabled:     p.PreviewEnvsEnabled,
 		RDSDatabasesEnabled:    p.RDSDatabasesEnabled,
 		RDSDatabasesEnabled:    p.RDSDatabasesEnabled,
 		ManagedInfraEnabled:    p.ManagedInfraEnabled,
 		ManagedInfraEnabled:    p.ManagedInfraEnabled,

+ 9 - 6
zarf/helm/.serverenv

@@ -73,14 +73,17 @@ STRIPE_SECRET_KEY=
 # STRIPE_PUBLISHABLE_KEY is used in the frontend to create Stripe Web Elements
 # STRIPE_PUBLISHABLE_KEY is used in the frontend to create Stripe Web Elements
 STRIPE_PUBLISHABLE_KEY=
 STRIPE_PUBLISHABLE_KEY=
 
 
-# METRONOME_API_KEY is used to create customers in Metronome. If empty all functionality will be disabled.
-METRONOME_API_KEY=
+# LAGO_API_KEY is used to create customers in Lago. If empty all functionality will be disabled.
+LAGO_API_KEY=
 
 
-# PORTER_CLOUD_PLAN_ID is the id of the starter plan in Metronome. Only used if METRONOME_API_KEY is set
-PORTER_CLOUD_PLAN_ID=
+# PORTER_CLOUD_PLAN_ID is the id of the starter plan in Lago. Only used if LAGO_API_KEY is set
+PORTER_CLOUD_PLAN_CODE=
 
 
-# PORTER_STANDARD_PLAN_ID is the id of the standard plan in Metronome. Only used if METRONOME_API_KEY is set
-PORTER_STANDARD_PLAN_ID=
+# PORTER_STANDARD_PLAN_CODE is the id of the standard plan in Lago. Only used if LAGO_API_KEY is set
+PORTER_STANDARD_PLAN_CODE=
+
+# PORTER_TRIAL_CODE is the id of the trial plan in Lago. Only used if LAGO_API_KEY is set
+PORTER_TRIAL_CODE=
 
 
 # UPSTASH_ENABLED is used to enable the Upstash integration
 # UPSTASH_ENABLED is used to enable the Upstash integration
 UPSTASH_ENABLED=false
 UPSTASH_ENABLED=false