@@ -50,23 +50,27 @@ func (h *Handlers) billingCheckout(w http.ResponseWriter, r *http.Request) { |
| 50 | 50 | h.d.Render.HTTPError(w, r, http.StatusNotFound, "") |
| 51 | 51 | return |
| 52 | 52 | } |
| 53 | | - state, err := orgbilling.GetOrgBillingState(r.Context(), orgbilling.Deps{Pool: h.d.Pool}, org.ID) |
| 53 | + sessionURL, err := h.startBillingCheckout(r, org) |
| 54 | 54 | if err != nil { |
| 55 | | - h.d.Logger.ErrorContext(r.Context(), "org billing: load state for checkout", "org_id", org.ID, "error", err) |
| 56 | | - h.d.Render.HTTPError(w, r, http.StatusInternalServerError, "") |
| 55 | + h.d.Logger.ErrorContext(r.Context(), "org billing: create checkout", "org_id", org.ID, "error", err) |
| 56 | + h.renderSettingsBilling(w, r, org, "Could not start checkout right now.", "") |
| 57 | 57 | return |
| 58 | 58 | } |
| 59 | + http.Redirect(w, r, sessionURL, http.StatusSeeOther) |
| 60 | +} |
| 61 | + |
| 62 | +func (h *Handlers) startBillingCheckout(r *http.Request, org orgsdb.Org) (string, error) { |
| 63 | + state, err := orgbilling.GetOrgBillingState(r.Context(), orgbilling.Deps{Pool: h.d.Pool}, org.ID) |
| 64 | + if err != nil { |
| 65 | + return "", fmt.Errorf("load billing state: %w", err) |
| 66 | + } |
| 59 | 67 | state, err = h.ensureStripeCustomer(r, org, state) |
| 60 | 68 | if err != nil { |
| 61 | | - h.d.Logger.ErrorContext(r.Context(), "org billing: ensure stripe customer", "org_id", org.ID, "error", err) |
| 62 | | - h.renderSettingsBilling(w, r, org, "Could not start checkout right now.", "") |
| 63 | | - return |
| 69 | + return "", fmt.Errorf("ensure stripe customer: %w", err) |
| 64 | 70 | } |
| 65 | 71 | seats, err := orgbilling.CountBillableOrgMembers(r.Context(), orgbilling.Deps{Pool: h.d.Pool}, org.ID) |
| 66 | 72 | if err != nil { |
| 67 | | - h.d.Logger.ErrorContext(r.Context(), "org billing: count seats", "org_id", org.ID, "error", err) |
| 68 | | - h.renderSettingsBilling(w, r, org, "Could not calculate billable seats right now.", "") |
| 69 | | - return |
| 73 | + return "", fmt.Errorf("count billable seats: %w", err) |
| 70 | 74 | } |
| 71 | 75 | session, err := h.d.Stripe.CreateCheckoutSession(r.Context(), stripebilling.CheckoutInput{ |
| 72 | 76 | OrgID: org.ID, |
@@ -77,11 +81,9 @@ func (h *Handlers) billingCheckout(w http.ResponseWriter, r *http.Request) { |
| 77 | 81 | CancelURL: h.billingReturnURL(org.Slug, h.d.StripeCancelURL, "/organizations/"+org.Slug+"/billing/cancel"), |
| 78 | 82 | }) |
| 79 | 83 | if err != nil { |
| 80 | | - h.d.Logger.ErrorContext(r.Context(), "org billing: create checkout session", "org_id", org.ID, "error", err) |
| 81 | | - h.renderSettingsBilling(w, r, org, "Could not create the Stripe checkout session.", "") |
| 82 | | - return |
| 84 | + return "", fmt.Errorf("create stripe checkout session: %w", err) |
| 83 | 85 | } |
| 84 | | - http.Redirect(w, r, session.URL, http.StatusSeeOther) |
| 86 | + return session.URL, nil |
| 85 | 87 | } |
| 86 | 88 | |
| 87 | 89 | func (h *Handlers) billingPortal(w http.ResponseWriter, r *http.Request) { |
@@ -212,6 +214,8 @@ func billingNotice(code string) string { |
| 212 | 214 | return "Organization created. Continue with Team checkout to unlock paid features." |
| 213 | 215 | case "team-created-import-started": |
| 214 | 216 | return "Organization created and GitHub import started. Continue with Team checkout to unlock paid features." |
| 217 | + case "team-checkout-failed": |
| 218 | + return "Organization created, but checkout could not be started. Try Continue with Team again." |
| 215 | 219 | default: |
| 216 | 220 | return "" |
| 217 | 221 | } |