diff --git a/components/server/ee/src/workspace/gitpod-server-impl.ts b/components/server/ee/src/workspace/gitpod-server-impl.ts index e269b79e9a4c9e..29dec851aea7a8 100644 --- a/components/server/ee/src/workspace/gitpod-server-impl.ts +++ b/components/server/ee/src/workspace/gitpod-server-impl.ts @@ -119,6 +119,7 @@ import { UsageServiceDefinition } from "@gitpod/usage-api/lib/usage/v1/usage.pb" import { BillingServiceClient, BillingServiceDefinition } from "@gitpod/usage-api/lib/usage/v1/billing.pb"; import { IncrementalPrebuildsService } from "../prebuilds/incremental-prebuilds-service"; import { ConfigProvider } from "../../../src/workspace/config-provider"; +import { getExperimentsClientForBackend } from "@gitpod/gitpod-protocol/lib/experiments/configcat-server"; @injectable() export class GitpodServerEEImpl extends GitpodServerImpl { @@ -2177,6 +2178,7 @@ export class GitpodServerEEImpl extends GitpodServerImpl { const user = this.checkAndBlockUser("subscribeToStripe"); + let team: Team | undefined; try { if (attrId.kind === "team") { const team = await this.guardTeamOperation(attrId.teamId, "update"); @@ -2189,6 +2191,19 @@ export class GitpodServerEEImpl extends GitpodServerImpl { throw new Error(`No Stripe customer profile for '${attributionId}'`); } + const createStripeSubscriptionOnUsage = await getExperimentsClientForBackend().getValueAsync( + "createStripeSubscriptionOnUsage", + false, + { + user: user, + teamId: team ? team.id : undefined, + }, + ); + + if (createStripeSubscriptionOnUsage) { + await this.billingService.createStripeSubscription({ attributionId, setupIntentId, usageLimit }); + } + await this.stripeService.setDefaultPaymentMethodForCustomer(customerId, setupIntentId); await this.stripeService.createSubscriptionForCustomer(customerId, attributionId); diff --git a/components/usage-api/go/v1/billing.pb.go b/components/usage-api/go/v1/billing.pb.go index c7ea8665b6ceee..bec9127aaae8d4 100644 --- a/components/usage-api/go/v1/billing.pb.go +++ b/components/usage-api/go/v1/billing.pb.go @@ -578,8 +578,9 @@ type CreateStripeSubscriptionRequest struct { unknownFields protoimpl.UnknownFields AttributionId string `protobuf:"bytes,1,opt,name=attribution_id,json=attributionId,proto3" json:"attribution_id,omitempty"` - SetupIntentId string `protobuf:"bytes,2,opt,name=setup_intent_id,json=setupIntentId,proto3" json:"setup_intent_id,omitempty"` - UsageLimit int64 `protobuf:"varint,3,opt,name=usage_limit,json=usageLimit,proto3" json:"usage_limit,omitempty"` + CustomerId string `protobuf:"bytes,2,opt,name=customer_id,json=customerId,proto3" json:"customer_id,omitempty"` + SetupIntentId string `protobuf:"bytes,3,opt,name=setup_intent_id,json=setupIntentId,proto3" json:"setup_intent_id,omitempty"` + UsageLimit int64 `protobuf:"varint,4,opt,name=usage_limit,json=usageLimit,proto3" json:"usage_limit,omitempty"` } func (x *CreateStripeSubscriptionRequest) Reset() { @@ -621,6 +622,13 @@ func (x *CreateStripeSubscriptionRequest) GetAttributionId() string { return "" } +func (x *CreateStripeSubscriptionRequest) GetCustomerId() string { + if x != nil { + return x.CustomerId + } + return "" +} + func (x *CreateStripeSubscriptionRequest) GetSetupIntentId() string { if x != nil { return x.SetupIntentId @@ -883,84 +891,86 @@ var file_usage_v1_billing_proto_rawDesc = []byte{ 0x12, 0x34, 0x0a, 0x08, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x52, 0x08, 0x63, 0x75, - 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x22, 0x91, 0x01, 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x22, 0xb2, 0x01, 0x0a, 0x1f, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x65, 0x74, 0x75, 0x70, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x6e, - 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x74, 0x75, - 0x70, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x73, 0x61, - 0x67, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, - 0x75, 0x73, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x64, 0x0a, 0x20, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, - 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x22, 0x24, 0x0a, 0x12, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x5d, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x53, 0x74, 0x72, + 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x73, 0x65, 0x74, 0x75, 0x70, 0x5f, 0x69, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x65, 0x74, + 0x75, 0x70, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x75, 0x73, + 0x61, 0x67, 0x65, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x0a, 0x75, 0x73, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x22, 0x64, 0x0a, 0x20, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x40, 0x0a, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x24, 0x0a, 0x12, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x5d, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x53, 0x74, + 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x16, + 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x48, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, - 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, - 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x16, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x48, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x53, 0x74, 0x72, 0x69, - 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x32, - 0xd7, 0x05, 0x0a, 0x0e, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x12, 0x5e, 0x0a, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x49, - 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x76, 0x6f, - 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x75, 0x73, - 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, - 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x58, 0x0a, 0x0f, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x49, 0x6e, - 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x20, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, - 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x61, 0x0a, 0x12, - 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x23, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x5e, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x43, 0x75, 0x73, 0x74, - 0x6f, 0x6d, 0x65, 0x72, 0x12, 0x22, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x47, 0x65, 0x74, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x43, 0x75, 0x73, - 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x67, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x43, - 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x12, 0x25, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x43, - 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, - 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x73, 0x0a, 0x18, 0x43, 0x72, 0x65, 0x61, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, + 0x32, 0xd7, 0x05, 0x0a, 0x0e, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x5e, 0x0a, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, + 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x12, 0x22, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x49, 0x6e, 0x76, + 0x6f, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x75, + 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, + 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x12, 0x58, 0x0a, 0x0f, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x49, + 0x6e, 0x76, 0x6f, 0x69, 0x63, 0x65, 0x12, 0x20, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x49, 0x6e, 0x76, 0x6f, 0x69, 0x63, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x69, 0x6e, 0x61, 0x6c, 0x69, 0x7a, 0x65, 0x49, 0x6e, 0x76, 0x6f, + 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x61, 0x0a, + 0x12, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x24, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x5e, 0x0a, 0x11, 0x47, 0x65, 0x74, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x43, 0x75, 0x73, + 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x12, 0x22, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, + 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x75, 0x73, 0x61, 0x67, + 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x43, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, + 0x12, 0x67, 0x0a, 0x14, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, + 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x12, 0x25, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, + 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x26, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x65, 0x72, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x73, 0x0a, 0x18, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x2a, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x6a, + 0x0a, 0x15, 0x47, 0x65, 0x74, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2a, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, - 0x65, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x6a, 0x0a, - 0x15, 0x47, 0x65, 0x74, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x26, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, - 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, 0x72, - 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2d, 0x69, - 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2f, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2d, 0x61, - 0x70, 0x69, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x27, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x74, + 0x72, 0x69, 0x70, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2d, + 0x69, 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2f, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2d, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/components/usage-api/typescript/src/usage/v1/billing.pb.ts b/components/usage-api/typescript/src/usage/v1/billing.pb.ts index e9e100e91cf34b..9d3a19b30f2fe1 100644 --- a/components/usage-api/typescript/src/usage/v1/billing.pb.ts +++ b/components/usage-api/typescript/src/usage/v1/billing.pb.ts @@ -59,6 +59,7 @@ export interface CreateStripeCustomerResponse { export interface CreateStripeSubscriptionRequest { attributionId: string; + customerId: string; setupIntentId: string; usageLimit: number; } @@ -623,7 +624,7 @@ export const CreateStripeCustomerResponse = { }; function createBaseCreateStripeSubscriptionRequest(): CreateStripeSubscriptionRequest { - return { attributionId: "", setupIntentId: "", usageLimit: 0 }; + return { attributionId: "", customerId: "", setupIntentId: "", usageLimit: 0 }; } export const CreateStripeSubscriptionRequest = { @@ -631,11 +632,14 @@ export const CreateStripeSubscriptionRequest = { if (message.attributionId !== "") { writer.uint32(10).string(message.attributionId); } + if (message.customerId !== "") { + writer.uint32(18).string(message.customerId); + } if (message.setupIntentId !== "") { - writer.uint32(18).string(message.setupIntentId); + writer.uint32(26).string(message.setupIntentId); } if (message.usageLimit !== 0) { - writer.uint32(24).int64(message.usageLimit); + writer.uint32(32).int64(message.usageLimit); } return writer; }, @@ -651,9 +655,12 @@ export const CreateStripeSubscriptionRequest = { message.attributionId = reader.string(); break; case 2: - message.setupIntentId = reader.string(); + message.customerId = reader.string(); break; case 3: + message.setupIntentId = reader.string(); + break; + case 4: message.usageLimit = longToNumber(reader.int64() as Long); break; default: @@ -667,6 +674,7 @@ export const CreateStripeSubscriptionRequest = { fromJSON(object: any): CreateStripeSubscriptionRequest { return { attributionId: isSet(object.attributionId) ? String(object.attributionId) : "", + customerId: isSet(object.customerId) ? String(object.customerId) : "", setupIntentId: isSet(object.setupIntentId) ? String(object.setupIntentId) : "", usageLimit: isSet(object.usageLimit) ? Number(object.usageLimit) : 0, }; @@ -675,6 +683,7 @@ export const CreateStripeSubscriptionRequest = { toJSON(message: CreateStripeSubscriptionRequest): unknown { const obj: any = {}; message.attributionId !== undefined && (obj.attributionId = message.attributionId); + message.customerId !== undefined && (obj.customerId = message.customerId); message.setupIntentId !== undefined && (obj.setupIntentId = message.setupIntentId); message.usageLimit !== undefined && (obj.usageLimit = Math.round(message.usageLimit)); return obj; @@ -683,6 +692,7 @@ export const CreateStripeSubscriptionRequest = { fromPartial(object: DeepPartial): CreateStripeSubscriptionRequest { const message = createBaseCreateStripeSubscriptionRequest(); message.attributionId = object.attributionId ?? ""; + message.customerId = object.customerId ?? ""; message.setupIntentId = object.setupIntentId ?? ""; message.usageLimit = object.usageLimit ?? 0; return message; diff --git a/components/usage-api/usage/v1/billing.proto b/components/usage-api/usage/v1/billing.proto index b0b7013974cdb0..1bc6afdde06a99 100644 --- a/components/usage-api/usage/v1/billing.proto +++ b/components/usage-api/usage/v1/billing.proto @@ -78,8 +78,9 @@ message CreateStripeCustomerResponse { message CreateStripeSubscriptionRequest { string attribution_id = 1; - string setup_intent_id = 2; - int64 usage_limit = 3; + string customer_id = 2; + string setup_intent_id = 3; + int64 usage_limit = 4; } message CreateStripeSubscriptionResponse { diff --git a/components/usage/pkg/apiv1/billing.go b/components/usage/pkg/apiv1/billing.go index 60ecab788bc38a..e15cb75bb3c0d2 100644 --- a/components/usage/pkg/apiv1/billing.go +++ b/components/usage/pkg/apiv1/billing.go @@ -23,11 +23,12 @@ import ( "gorm.io/gorm" ) -func NewBillingService(stripeClient *stripe.Client, conn *gorm.DB, ccManager *db.CostCenterManager) *BillingService { +func NewBillingService(stripeClient *stripe.Client, conn *gorm.DB, ccManager *db.CostCenterManager, stripePrices stripe.StripePrices) *BillingService { return &BillingService{ stripeClient: stripeClient, conn: conn, ccManager: ccManager, + stripePrices: stripePrices, } } @@ -35,6 +36,7 @@ type BillingService struct { conn *gorm.DB stripeClient *stripe.Client ccManager *db.CostCenterManager + stripePrices stripe.StripePrices v1.UnimplementedBillingServiceServer } @@ -165,6 +167,88 @@ func (s *BillingService) CreateStripeCustomer(ctx context.Context, req *v1.Creat }, nil } +func (s *BillingService) CreateStripeSubscription(ctx context.Context, req *v1.CreateStripeSubscriptionRequest) (*v1.CreateStripeSubscriptionResponse, error) { + attributionID, err := db.ParseAttributionID(req.GetAttributionId()) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "Invalid attribution ID %s", attributionID) + } + + customer, err := s.GetStripeCustomer(ctx, &v1.GetStripeCustomerRequest{ + Identifier: &v1.GetStripeCustomerRequest_AttributionId{ + AttributionId: string(attributionID), + }, + }) + if err != nil { + return nil, err + } + + _, err = s.stripeClient.SetDefaultPaymentForCustomer(ctx, customer.Customer.Id, req.SetupIntentId) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "Failed to set default payment for customer ID %s", customer.Customer.Id) + } + + stripeCustomer, err := s.stripeClient.GetCustomer(ctx, customer.Customer.Id) + if err != nil { + return nil, err + } + + priceID, err := getPriceIdentifier(attributionID, stripeCustomer, s) + if err != nil { + return nil, err + } + + var isAutomaticTaxSupported bool + if stripeCustomer.Tax != nil { + isAutomaticTaxSupported = stripeCustomer.Tax.AutomaticTax == "supported" + } + if !isAutomaticTaxSupported { + log.Warnf("Automatic Stripe tax is not supported for customer %s", stripeCustomer.ID) + } + + subscription, err := s.stripeClient.CreateSubscription(ctx, stripeCustomer.ID, priceID, isAutomaticTaxSupported) + if err != nil { + return nil, status.Errorf(codes.Internal, "Failed to create subscription with customer ID %s", customer.Customer.Id) + } + + return &v1.CreateStripeSubscriptionResponse{ + Subscription: &v1.StripeSubscription{ + Id: subscription.ID, + }, + }, nil +} + +func getPriceIdentifier(attributionID db.AttributionID, stripeCustomer *stripe_api.Customer, s *BillingService) (string, error) { + preferredCurrency := stripeCustomer.Metadata["preferredCurrency"] + if stripeCustomer.Metadata["preferredCurrency"] == "" { + log. + WithField("stripe_customer_id", stripeCustomer.ID). + Warn("No preferred currency set. Defaulting to USD") + } + + entity, _ := attributionID.Values() + + switch entity { + case db.AttributionEntity_User: + switch preferredCurrency { + case "EUR": + return s.stripePrices.IndividualUsagePriceIDs.EUR, nil + default: + return s.stripePrices.IndividualUsagePriceIDs.USD, nil + } + + case db.AttributionEntity_Team: + switch preferredCurrency { + case "EUR": + return s.stripePrices.TeamUsagePriceIDs.EUR, nil + default: + return s.stripePrices.TeamUsagePriceIDs.USD, nil + } + + default: + return "", status.Errorf(codes.InvalidArgument, "Invalid currency %s for customer ID %s", stripeCustomer.Metadata["preferredCurrency"], stripeCustomer.ID) + } +} + func (s *BillingService) ReconcileInvoices(ctx context.Context, in *v1.ReconcileInvoicesRequest) (*v1.ReconcileInvoicesResponse, error) { balances, err := db.ListBalance(ctx, s.conn) if err != nil { diff --git a/components/usage/pkg/server/server.go b/components/usage/pkg/server/server.go index c391d045cf5147..7966d1570bbe4b 100644 --- a/components/usage/pkg/server/server.go +++ b/components/usage/pkg/server/server.go @@ -44,17 +44,7 @@ type Config struct { DefaultSpendingLimit db.DefaultSpendingLimit `json:"defaultSpendingLimit"` // StripePrices configure which Stripe Price IDs should be used - StripePrices StripePrices `json:"stripePrices"` -} - -type PriceConfig struct { - EUR string `json:"eur"` - USD string `json:"usd"` -} - -type StripePrices struct { - IndividualUsagePriceIDs PriceConfig `json:"individualUsagePriceIds"` - TeamUsagePriceIDs PriceConfig `json:"teamUsagePriceIds"` + StripePrices stripe.StripePrices `json:"stripePrices"` } func Start(cfg Config, version string) error { @@ -188,7 +178,7 @@ func registerGRPCServices(srv *baseserver.Server, conn *gorm.DB, stripeClient *s if stripeClient == nil { v1.RegisterBillingServiceServer(srv.GRPC(), &apiv1.BillingServiceNoop{}) } else { - v1.RegisterBillingServiceServer(srv.GRPC(), apiv1.NewBillingService(stripeClient, conn, ccManager)) + v1.RegisterBillingServiceServer(srv.GRPC(), apiv1.NewBillingService(stripeClient, conn, ccManager, cfg.StripePrices)) } return nil } diff --git a/components/usage/pkg/stripe/stripe.go b/components/usage/pkg/stripe/stripe.go index c5574e57fef89a..c6894a1fe62da0 100644 --- a/components/usage/pkg/stripe/stripe.go +++ b/components/usage/pkg/stripe/stripe.go @@ -37,6 +37,16 @@ type ClientConfig struct { SecretKey string `json:"secretKey"` } +type PriceConfig struct { + EUR string `json:"eur"` + USD string `json:"usd"` +} + +type StripePrices struct { + IndividualUsagePriceIDs PriceConfig `json:"individualUsagePriceIds"` + TeamUsagePriceIDs PriceConfig `json:"teamUsagePriceIds"` +} + func ReadConfigFromFile(path string) (ClientConfig, error) { bytes, err := os.ReadFile(path) if err != nil { @@ -320,6 +330,82 @@ func (c *Client) GetSubscriptionWithCustomer(ctx context.Context, subscriptionID return subscription, nil } +func (c *Client) CreateSubscription(ctx context.Context, customerID string, priceID string, isAutomaticTaxSupported bool) (*stripe.Subscription, error) { + if customerID == "" { + return nil, fmt.Errorf("no customerID specified") + } + if priceID == "" { + return nil, fmt.Errorf("no priceID specified") + } + + startOfNextMonth := getStartOfNextMonth(time.Now()) + + params := &stripe.SubscriptionParams{ + Customer: stripe.String(customerID), + Items: []*stripe.SubscriptionItemsParams{ + { + Price: stripe.String(priceID), + }, + }, + AutomaticTax: &stripe.SubscriptionAutomaticTaxParams{ + Enabled: stripe.Bool(isAutomaticTaxSupported), + }, + BillingCycleAnchor: stripe.Int64(startOfNextMonth.Unix()), + } + + subscription, err := c.sc.Subscriptions.New(params) + if err != nil { + return nil, fmt.Errorf("failed to get subscription with customer ID %s", customerID) + } + + return subscription, err +} + +func getStartOfNextMonth(t time.Time) time.Time { + currentYear, currentMonth, _ := t.Date() + + firstOfMonth := time.Date(currentYear, currentMonth, 1, 0, 0, 0, 0, time.UTC) + startOfNextMonth := firstOfMonth.AddDate(0, 1, 0) + + return startOfNextMonth +} + +func (c *Client) SetDefaultPaymentForCustomer(ctx context.Context, customerID string, setupIntentId string) (*stripe.Customer, error) { + if customerID == "" { + return nil, fmt.Errorf("no customerID specified") + } + + if setupIntentId == "" { + return nil, fmt.Errorf("no setupIntentID specified") + } + + setupIntent, err := c.sc.SetupIntents.Get(setupIntentId, &stripe.SetupIntentParams{ + Params: stripe.Params{ + Context: ctx, + }, + }) + if err != nil { + return nil, fmt.Errorf("Failed to retrieve setup intent with id %s", setupIntentId) + } + + paymentMethod, err := c.sc.PaymentMethods.Attach(setupIntent.PaymentMethod.ID, &stripe.PaymentMethodAttachParams{Customer: &customerID}) + if err != nil { + return nil, fmt.Errorf("Failed to attach payment method to setup intent ID %s", setupIntentId) + } + + customer, _ := c.sc.Customers.Update(customerID, &stripe.CustomerParams{ + InvoiceSettings: &stripe.CustomerInvoiceSettingsParams{ + DefaultPaymentMethod: stripe.String(paymentMethod.ID)}, + Address: &stripe.AddressParams{ + Line1: stripe.String(paymentMethod.BillingDetails.Address.Line1), + Country: stripe.String(paymentMethod.BillingDetails.Address.Country)}}) + if err != nil { + return nil, fmt.Errorf("Failed to update customer with id %s", customerID) + } + + return customer, nil +} + func GetAttributionID(ctx context.Context, customer *stripe.Customer) (db.AttributionID, error) { if customer == nil { log.Error("No customer information available for invoice.") diff --git a/components/usage/pkg/stripe/stripe_test.go b/components/usage/pkg/stripe/stripe_test.go index 4f68059d94313c..8a4f3cc6a6d1b9 100644 --- a/components/usage/pkg/stripe/stripe_test.go +++ b/components/usage/pkg/stripe/stripe_test.go @@ -6,8 +6,10 @@ package stripe import ( "fmt" - "github.com/gitpod-io/gitpod/usage/pkg/db" "testing" + "time" + + "github.com/gitpod-io/gitpod/usage/pkg/db" "github.com/stretchr/testify/require" ) @@ -89,3 +91,9 @@ func TestCustomerQueriesForTeamIds_MultipleQueries(t *testing.T) { }) } } + +func TestStartOfNextMonth(t *testing.T) { + ts := time.Date(2022, 10, 1, 0, 0, 0, 0, time.UTC) + + require.Equal(t, time.Date(2022, 11, 1, 0, 0, 0, 0, time.UTC), getStartOfNextMonth(ts)) +} diff --git a/install/installer/pkg/components/usage/configmap.go b/install/installer/pkg/components/usage/configmap.go index 1da4d79d1fbdcb..c80e03ca386c28 100644 --- a/install/installer/pkg/components/usage/configmap.go +++ b/install/installer/pkg/components/usage/configmap.go @@ -10,6 +10,7 @@ import ( "github.com/gitpod-io/gitpod/common-go/baseserver" "github.com/gitpod-io/gitpod/usage/pkg/db" "github.com/gitpod-io/gitpod/usage/pkg/server" + "github.com/gitpod-io/gitpod/usage/pkg/stripe" "github.com/gitpod-io/gitpod/installer/pkg/common" "github.com/gitpod-io/gitpod/installer/pkg/config/v1/experimental" @@ -39,12 +40,12 @@ func configmap(ctx *common.RenderContext) ([]runtime.Object, error) { expWebAppConfig := getExperimentalWebAppConfig(ctx) if expWebAppConfig != nil && expWebAppConfig.Stripe != nil { - cfg.StripePrices = server.StripePrices{ - IndividualUsagePriceIDs: server.PriceConfig{ + cfg.StripePrices = stripe.StripePrices{ + IndividualUsagePriceIDs: stripe.PriceConfig{ EUR: expWebAppConfig.Stripe.IndividualUsagePriceIDs.EUR, USD: expWebAppConfig.Stripe.IndividualUsagePriceIDs.USD, }, - TeamUsagePriceIDs: server.PriceConfig{ + TeamUsagePriceIDs: stripe.PriceConfig{ EUR: expWebAppConfig.Stripe.TeamUsagePriceIDs.EUR, USD: expWebAppConfig.Stripe.TeamUsagePriceIDs.USD, },