@@ -13,6 +13,7 @@ import (
13
13
"github.com/gitpod-io/gitpod/common-go/log"
14
14
"github.com/stripe/stripe-go/v72"
15
15
"github.com/stripe/stripe-go/v72/customer"
16
+ "github.com/stripe/stripe-go/v72/usagerecord"
16
17
)
17
18
18
19
type stripeKeys struct {
@@ -37,19 +38,54 @@ func Authenticate(apiKeyFile string) error {
37
38
return nil
38
39
}
39
40
40
- // FindCustomersForTeamIds queries the stripe API to find all customers with a teamId in `teamIds`.
41
- func FindCustomersForTeamIds (teamIds []string ) {
41
+ // UpdateUsage updates teams' Stripe subscriptions with usage data
42
+ // `usageForTeam` is a map from team name to total workspace seconds used within a billing period.
43
+ func UpdateUsage (usageForTeam map [string ]int64 ) error {
44
+ teamIds := make ([]string , 0 , len (usageForTeam ))
45
+ for k := range usageForTeam {
46
+ teamIds = append (teamIds , k )
47
+ }
42
48
queries := queriesForCustomersWithTeamIds (teamIds )
43
49
44
50
for _ , query := range queries {
45
51
log .Infof ("about to make query %q" , query )
46
- params := & stripe.CustomerSearchParams {SearchParams : stripe.SearchParams {Query : query }}
52
+ params := & stripe.CustomerSearchParams {
53
+ SearchParams : stripe.SearchParams {
54
+ Query : query ,
55
+ Expand : []* string {stripe .String ("data.subscriptions" )},
56
+ },
57
+ }
47
58
iter := customer .Search (params )
48
59
for iter .Next () {
49
60
customer := iter .Customer ()
50
61
log .Infof ("found customer %q for teamId %q" , customer .Name , customer .Metadata ["teamId" ])
62
+ subscriptions := customer .Subscriptions .Data
63
+ if len (subscriptions ) != 1 {
64
+ log .Errorf ("customer has an unexpected number of subscriptions (expected 1, got %d)" , len (subscriptions ))
65
+ continue
66
+ }
67
+ subscription := customer .Subscriptions .Data [0 ]
68
+
69
+ log .Infof ("customer has subscription: %q" , subscription .ID )
70
+ if len (subscription .Items .Data ) != 1 {
71
+ log .Errorf ("this subscription has an unexpected number of subscriptionItems (expected 1, got %d)" , len (subscription .Items .Data ))
72
+ continue
73
+ }
74
+
75
+ creditsUsed := workspaceSecondsToCredits (usageForTeam [customer .Metadata ["teamId" ]])
76
+
77
+ subscriptionItemId := subscription .Items .Data [0 ].ID
78
+ log .Infof ("registering usage against subscriptionItem %q" , subscriptionItemId )
79
+ _ , err := usagerecord .New (& stripe.UsageRecordParams {
80
+ SubscriptionItem : stripe .String (subscriptionItemId ),
81
+ Quantity : stripe .Int64 (creditsUsed ),
82
+ })
83
+ if err != nil {
84
+ log .WithError (err ).Errorf ("failed to register usage for customer %q" , customer .Name )
85
+ }
51
86
}
52
87
}
88
+ return nil
53
89
}
54
90
55
91
// queriesForCustomersWithTeamIds constructs Stripe query strings to find the Stripe Customer for each teamId
@@ -73,3 +109,8 @@ func queriesForCustomersWithTeamIds(teamIds []string) []string {
73
109
74
110
return queries
75
111
}
112
+
113
+ // workspaceSecondsToCredits converts seconds (of workspace usage) into Stripe credits.
114
+ func workspaceSecondsToCredits (seconds int64 ) int64 {
115
+ return (seconds + 59 ) / 60
116
+ }
0 commit comments