@@ -7,7 +7,6 @@ package stripe
7
7
import (
8
8
"context"
9
9
"encoding/json"
10
- "errors"
11
10
"fmt"
12
11
"os"
13
12
"strings"
@@ -51,26 +50,14 @@ type UsageRecord struct {
51
50
Quantity int64
52
51
}
53
52
54
- type StripeInvoice struct {
53
+ type Invoice struct {
55
54
ID string
56
55
SubscriptionID string
57
56
Amount int64
58
57
Currency string
59
58
Credits int64
60
59
}
61
60
62
- type CustomerKind string
63
-
64
- const (
65
- User CustomerKind = "user"
66
- Team = "team"
67
- )
68
-
69
- var (
70
- // ErrorCustomerNotFound is returned when no stripe customer is found for a given user account
71
- ErrorCustomerNotFound = errors .New ("invalid size" )
72
- )
73
-
74
61
// UpdateUsage updates teams' Stripe subscriptions with usage data
75
62
// `usageForTeam` is a map from team name to total workspace seconds used within a billing period.
76
63
func (c * Client ) UpdateUsage (ctx context.Context , creditsPerTeam map [string ]int64 ) error {
@@ -82,16 +69,13 @@ func (c *Client) UpdateUsage(ctx context.Context, creditsPerTeam map[string]int6
82
69
83
70
for _ , query := range queries {
84
71
log .Infof ("Searching customers in Stripe with query: %q" , query )
85
- params := & stripe.CustomerSearchParams {
86
- SearchParams : stripe.SearchParams {
87
- Query : query ,
88
- Expand : []* string {stripe .String ("data.subscriptions" )},
89
- Context : ctx ,
90
- },
72
+
73
+ customers , err := c .findCustomers (ctx , query )
74
+ if err != nil {
75
+ return fmt .Errorf ("failed to udpate usage: %w" , err )
91
76
}
92
- iter := c .sc .Customers .Search (params )
93
- for iter .Next () {
94
- customer := iter .Customer ()
77
+
78
+ for _ , customer := range customers {
95
79
teamID := customer .Metadata ["teamId" ]
96
80
log .Infof ("Found customer %q for teamId %q" , customer .Name , teamID )
97
81
@@ -112,6 +96,27 @@ func (c *Client) UpdateUsage(ctx context.Context, creditsPerTeam map[string]int6
112
96
return nil
113
97
}
114
98
99
+ func (c * Client ) findCustomers (ctx context.Context , query string ) ([]* stripe.Customer , error ) {
100
+ params := & stripe.CustomerSearchParams {
101
+ SearchParams : stripe.SearchParams {
102
+ Query : query ,
103
+ Expand : []* string {stripe .String ("data.subscriptions" )},
104
+ Context : ctx ,
105
+ },
106
+ }
107
+ iter := c .sc .Customers .Search (params )
108
+ if iter .Err () != nil {
109
+ return nil , fmt .Errorf ("failed to search for customers: %w" , iter .Err ())
110
+ }
111
+
112
+ var customers []* stripe.Customer
113
+ for iter .Next () {
114
+ customers = append (customers , iter .Customer ())
115
+ }
116
+
117
+ return customers , nil
118
+ }
119
+
115
120
func (c * Client ) updateUsageForCustomer (ctx context.Context , customer * stripe.Customer , credits int64 ) (* UsageRecord , error ) {
116
121
subscriptions := customer .Subscriptions .Data
117
122
if len (subscriptions ) != 1 {
@@ -143,37 +148,55 @@ func (c *Client) updateUsageForCustomer(ctx context.Context, customer *stripe.Cu
143
148
}, nil
144
149
}
145
150
146
- // GetUpcomingInvoice fetches the upcoming invoice for the given team or user id.
147
- func (c * Client ) GetUpcomingInvoice (ctx context.Context , kind CustomerKind , id string ) (* StripeInvoice , error ) {
148
- log .Infof ("Fetching upcoming invoice of customer. (%q %q)" , kind , id )
149
- query := fmt .Sprintf ("metadata['%sId']:'%s'" , kind , id )
150
- searchParams := & stripe.CustomerSearchParams {
151
- SearchParams : stripe.SearchParams {
152
- Query : query ,
153
- Expand : []* string {stripe .String ("data.subscriptions" )},
154
- Context : ctx ,
155
- },
151
+ func (c * Client ) GetCustomerByTeamID (ctx context.Context , teamID string ) (* stripe.Customer , error ) {
152
+ customers , err := c .findCustomers (ctx , fmt .Sprintf ("metadata['teamId']:'%s'" , teamID ))
153
+ if err != nil {
154
+ return nil , fmt .Errorf ("failed to find customers: %w" , err )
156
155
}
157
- iter := c . sc . Customers . Search ( searchParams )
158
- if iter . Err () != nil || ! iter . Next () {
159
- return nil , ErrorCustomerNotFound
156
+
157
+ if len ( customers ) == 0 {
158
+ return nil , fmt . Errorf ( "no team customer found for id: %s" , teamID )
160
159
}
161
- customer := iter .Customer ()
162
- if iter .Next () {
163
- return nil , fmt .Errorf ("found more than one customer for query %s" , query )
160
+ if len (customers ) > 1 {
161
+ return nil , fmt .Errorf ("found multiple team customers for id: %s" , teamID )
162
+ }
163
+
164
+ return customers [0 ], nil
165
+ }
166
+
167
+ func (c * Client ) GetCustomerByUserID (ctx context.Context , userID string ) (* stripe.Customer , error ) {
168
+ customers , err := c .findCustomers (ctx , fmt .Sprintf ("metadata['userId']:'%s'" , userID ))
169
+ if err != nil {
170
+ return nil , fmt .Errorf ("failed to find customers: %w" , err )
164
171
}
172
+
173
+ if len (customers ) == 0 {
174
+ return nil , fmt .Errorf ("no user customer found for id: %s" , userID )
175
+ }
176
+ if len (customers ) > 1 {
177
+ return nil , fmt .Errorf ("found multiple user customers for id: %s" , userID )
178
+ }
179
+
180
+ return customers [0 ], nil
181
+ }
182
+
183
+ // GetUpcomingInvoice fetches the upcoming invoice for the given team or user id.
184
+ func (c * Client ) GetUpcomingInvoice (ctx context.Context , customerID string ) (* Invoice , error ) {
165
185
invoiceParams := & stripe.InvoiceParams {
166
- Customer : stripe .String (customer .ID ),
186
+ Params : stripe.Params {
187
+ Context : ctx ,
188
+ },
189
+ Customer : stripe .String (customerID ),
167
190
}
168
191
invoice , err := c .sc .Invoices .GetNext (invoiceParams )
169
192
if err != nil {
170
- return nil , fmt .Errorf ("failed to fetch the upcoming invoice for customer %s" , customer . ID )
193
+ return nil , fmt .Errorf ("failed to fetch the upcoming invoice for customer %s" , customerID )
171
194
}
172
195
if len (invoice .Lines .Data ) < 1 {
173
- return nil , fmt .Errorf ("no line items on invoice %s" , invoice .ID )
196
+ return nil , fmt .Errorf ("no line items on invoice %s for customer %s " , invoice .ID , customerID )
174
197
}
175
198
176
- return & StripeInvoice {
199
+ return & Invoice {
177
200
ID : invoice .ID ,
178
201
SubscriptionID : invoice .Subscription .ID ,
179
202
Amount : invoice .AmountRemaining ,
0 commit comments