Skip to content

Commit 2eead4a

Browse files
svenefftingeroboquat
authored andcommitted
[usage] handle reset usage for chargebee
chargebee subscriptions that are cancelled get a dedicatd cost center
1 parent bafbaab commit 2eead4a

File tree

8 files changed

+156
-74
lines changed

8 files changed

+156
-74
lines changed

components/gitpod-db/go/cost_center.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ var CostCenterNotFound = errors.New("CostCenter not found")
2222
type BillingStrategy string
2323

2424
const (
25-
CostCenter_Stripe BillingStrategy = "stripe"
26-
CostCenter_Other BillingStrategy = "other"
25+
CostCenter_Stripe BillingStrategy = "stripe"
26+
CostCenter_Other BillingStrategy = "other"
27+
CostCenter_ChargebeeCancelled BillingStrategy = "chargebee-cancelled"
2728
)
2829

2930
type CostCenter struct {
@@ -103,7 +104,7 @@ func (c *CostCenterManager) GetOrCreateCostCenter(ctx context.Context, attributi
103104
// we want to reset it immediately.
104105
// This can happen in the following scenario:
105106
// * User accesses gitpod just after their CostCenter expired, but just before our periodic CostCenter reset kicks in.
106-
if result.BillingStrategy == CostCenter_Other && result.IsExpired() {
107+
if result.BillingStrategy != CostCenter_Stripe && result.IsExpired() {
107108
cc, err := c.ResetUsage(ctx, result.ID)
108109
if err != nil {
109110
logger.WithError(err).Error("Failed to reset expired usage.")
@@ -237,7 +238,7 @@ func (c *CostCenterManager) newInvoiceUsageRecord(ctx context.Context, attributi
237238
}, nil
238239
}
239240

240-
func (c *CostCenterManager) ListLatestCostCentersWithBillingTimeBefore(ctx context.Context, strategy BillingStrategy, billingTimeBefore time.Time) ([]CostCenter, error) {
241+
func (c *CostCenterManager) ListManagedCostCentersWithBillingTimeBefore(ctx context.Context, billingTimeBefore time.Time) ([]CostCenter, error) {
241242
db := c.conn.WithContext(ctx)
242243

243244
var results []CostCenter
@@ -250,7 +251,7 @@ func (c *CostCenterManager) ListLatestCostCentersWithBillingTimeBefore(ctx conte
250251
tx := db.Table(fmt.Sprintf("%s as cc", (&CostCenter{}).TableName())).
251252
// Join on our set of latest CostCenter records
252253
Joins("INNER JOIN (?) AS expiredCC on cc.id = expiredCC.id AND cc.creationTime = expiredCC.creationTime", subquery).
253-
Where("cc.billingStrategy = ?", strategy).
254+
Where("cc.billingStrategy != ?", CostCenter_Stripe). // Stripe is managed externally
254255
Where("nextBillingTime != ?", "").
255256
Where("nextBillingTime < ?", TimeToISO8601(billingTimeBefore)).
256257
FindInBatches(&batch, 1000, func(tx *gorm.DB, iteration int) error {
@@ -273,7 +274,7 @@ func (c *CostCenterManager) ResetUsage(ctx context.Context, id AttributionID) (C
273274
return cc, err
274275
}
275276
logger = logger.WithField("cost_center", cc)
276-
if cc.BillingStrategy != CostCenter_Other {
277+
if cc.BillingStrategy == CostCenter_Stripe {
277278
return CostCenter{}, fmt.Errorf("cannot reset usage for Billing Strategy %s for Cost Center ID: %s", cc.BillingStrategy, cc.ID)
278279
}
279280
if !cc.IsExpired() {
@@ -290,11 +291,19 @@ func (c *CostCenterManager) ResetUsage(ctx context.Context, id AttributionID) (C
290291
nextBillingTime = cc.NextBillingTime.Time().AddDate(0, 1, 0)
291292
}
292293

294+
futureSpendingLimit := cc.SpendingLimit
295+
futurebillingStrategy := cc.BillingStrategy
296+
// chargebee cancellations will be switched to free plan (strategy: other)
297+
if cc.BillingStrategy == CostCenter_ChargebeeCancelled {
298+
futureSpendingLimit = c.cfg.ForTeams
299+
futurebillingStrategy = CostCenter_Other
300+
}
301+
293302
// All fields on the new cost center remain the same, except for BillingCycleStart, NextBillingTime, and CreationTime
294303
newCostCenter := CostCenter{
295304
ID: cc.ID,
296-
SpendingLimit: cc.SpendingLimit,
297-
BillingStrategy: cc.BillingStrategy,
305+
SpendingLimit: futureSpendingLimit,
306+
BillingStrategy: futurebillingStrategy,
298307
BillingCycleStart: NewVarCharTime(billingCycleStart),
299308
NextBillingTime: NewVarCharTime(nextBillingTime),
300309
CreationTime: NewVarCharTime(now),

components/gitpod-db/go/cost_center_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ func TestCostCenter_ListLatestCostCentersWithBillingTimeBefore(t *testing.T) {
321321

322322
ts := time.Date(2022, 10, 10, 10, 10, 10, 10, time.UTC)
323323

324-
retrieved, err := mnr.ListLatestCostCentersWithBillingTimeBefore(context.Background(), db.CostCenter_Other, ts.Add(7*24*time.Hour))
324+
retrieved, err := mnr.ListManagedCostCentersWithBillingTimeBefore(context.Background(), ts.Add(7*24*time.Hour))
325325
require.NoError(t, err)
326326
require.Len(t, retrieved, 0)
327327
})
@@ -356,7 +356,7 @@ func TestCostCenter_ListLatestCostCentersWithBillingTimeBefore(t *testing.T) {
356356

357357
dbtest.CreateCostCenters(t, conn, costCenters...)
358358

359-
retrieved, err := mnr.ListLatestCostCentersWithBillingTimeBefore(context.Background(), db.CostCenter_Other, secondCreation.Add(7*24*time.Hour))
359+
retrieved, err := mnr.ListManagedCostCentersWithBillingTimeBefore(context.Background(), secondCreation.Add(7*24*time.Hour))
360360
require.NoError(t, err)
361361
require.Len(t, retrieved, 1)
362362

@@ -392,7 +392,7 @@ func TestCostCenter_ListLatestCostCentersWithBillingTimeBefore(t *testing.T) {
392392

393393
dbtest.CreateCostCenters(t, conn, costCenters...)
394394

395-
retrieved, err := mnr.ListLatestCostCentersWithBillingTimeBefore(context.Background(), db.CostCenter_Other, secondCreation.Add(7*24*time.Hour))
395+
retrieved, err := mnr.ListManagedCostCentersWithBillingTimeBefore(context.Background(), secondCreation.Add(7*24*time.Hour))
396396
require.NoError(t, err)
397397
require.Len(t, retrieved, 0)
398398
})

components/gitpod-protocol/src/usage.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,5 +81,6 @@ export interface CostCenterJSON {
8181
export enum CostCenter_BillingStrategy {
8282
BILLING_STRATEGY_STRIPE = "BILLING_STRATEGY_STRIPE",
8383
BILLING_STRATEGY_OTHER = "BILLING_STRATEGY_OTHER",
84+
BILLING_STRATEGY_CHARGEBEE_CANCELLATION = "BILLING_STRATEGY_CHARGEBEE_CANCELLATION",
8485
UNRECOGNIZED = "UNRECOGNIZED",
8586
}

components/usage-api/go/v1/usage.pb.go

Lines changed: 67 additions & 61 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)