fixes
This commit is contained in:
@@ -18,6 +18,7 @@ func ClientError(err error) (msg string, ok bool) {
|
||||
errors.Is(err, ErrPlanNotFound),
|
||||
errors.Is(err, ErrAmountRequired),
|
||||
errors.Is(err, ErrStripeNotConfigured),
|
||||
errors.Is(err, ErrStripeSelfServeUnavailable),
|
||||
errors.Is(err, ErrStripePlanUnsupported),
|
||||
errors.Is(err, ErrStripePriceMissing),
|
||||
errors.Is(err, ErrStripeNoCustomer),
|
||||
|
||||
@@ -99,12 +99,32 @@ func (s *StripeService) cfg(ctx context.Context) StripeConfig {
|
||||
}
|
||||
|
||||
var (
|
||||
ErrStripeNotConfigured = errors.New("stripe not configured")
|
||||
ErrStripePlanUnsupported = errors.New("plan is not available for self-serve checkout")
|
||||
ErrStripePriceMissing = errors.New("stripe price id not configured for plan/term")
|
||||
ErrStripeBadSignature = errors.New("invalid stripe signature")
|
||||
ErrStripeNotConfigured = errors.New("stripe not configured")
|
||||
ErrStripeSelfServeUnavailable = errors.New("self-serve checkout is unavailable until Stripe is configured")
|
||||
ErrStripePlanUnsupported = errors.New("plan is not available for self-serve checkout")
|
||||
ErrStripePriceMissing = errors.New("stripe price id not configured for plan/term")
|
||||
ErrStripeBadSignature = errors.New("invalid stripe signature")
|
||||
)
|
||||
|
||||
// EnsureSelfServeCheckout allows live Stripe for any caller, and mock checkout
|
||||
// only for platform admins (so new tenant users cannot buy while STRIPE_MOCK is on).
|
||||
func (s *StripeService) EnsureSelfServeCheckout(ctx context.Context, platformAdmin bool) error {
|
||||
_, cfg, err := s.bindCfg(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !cfg.MockMode() {
|
||||
return nil
|
||||
}
|
||||
if cfg.AllowMockPurchase() && platformAdmin {
|
||||
return nil
|
||||
}
|
||||
if cfg.AllowMockPurchase() {
|
||||
return ErrStripeSelfServeUnavailable
|
||||
}
|
||||
return ErrStripeNotConfigured
|
||||
}
|
||||
|
||||
// CheckoutRequest is the body for POST /api/billing/checkout.
|
||||
// Set Pack for a one-time AI credit top-up, or Plan (+ Term) for a subscription.
|
||||
type CheckoutRequest struct {
|
||||
|
||||
@@ -93,6 +93,24 @@ func TestStripeConfigMockMode(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureSelfServeCheckout(t *testing.T) {
|
||||
live := &StripeService{Cfg: StripeConfig{SecretKey: "sk_test_x"}}
|
||||
if err := live.EnsureSelfServeCheckout(context.TODO(), false); err != nil {
|
||||
t.Fatalf("live stripe should allow any admin: %v", err)
|
||||
}
|
||||
mock := &StripeService{Cfg: StripeConfig{ForceMock: true}}
|
||||
if err := mock.EnsureSelfServeCheckout(context.TODO(), true); err != nil {
|
||||
t.Fatalf("mock + platform admin should allow: %v", err)
|
||||
}
|
||||
if err := mock.EnsureSelfServeCheckout(context.TODO(), false); !errors.Is(err, ErrStripeSelfServeUnavailable) {
|
||||
t.Fatalf("mock + non-platform admin: want ErrStripeSelfServeUnavailable, got %v", err)
|
||||
}
|
||||
empty := &StripeService{Cfg: StripeConfig{}}
|
||||
if err := empty.EnsureSelfServeCheckout(context.TODO(), true); !errors.Is(err, ErrStripeNotConfigured) {
|
||||
t.Fatalf("empty secret: want ErrStripeNotConfigured, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateCheckoutSessionFailsClosedWithoutSecret(t *testing.T) {
|
||||
s := &StripeService{Cfg: StripeConfig{WebOrigin: "http://localhost:5174"}}
|
||||
_, err := s.CreateCheckoutSession(context.TODO(), uuid.Nil, "a@b.c", "Acme", CheckoutRequest{Plan: "starter", Term: "monthly"})
|
||||
|
||||
Reference in New Issue
Block a user