Files
Bookra/apps/backend/internal/billing/service_test.go
T
Tomas DvorakandDevin f2f7439050 refactor(db): replace sqlc with handwritten pgx repos
- Finish Paddle-to-Stripe billing migration; drop paddle/stripe libs
- Renumber migrations; add 00012 memberships+manage_token,
  00013 location_type_capacity
- Add tests: admin, auth, bookings customer service
- Remove graphify-out artifacts and stale env files

Authored By: TDvorak <[email protected]>

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-09-17 20:21:34 +02:00

143 lines
4.3 KiB
Go

package billing
import (
"context"
"testing"
"bookra/apps/backend/internal/config"
"bookra/apps/backend/internal/db"
"bookra/apps/backend/internal/domain"
)
func testConfig() config.Config {
return config.Config{
FrontendURL: "http://localhost:3000",
StripeAPIKey: "sk_test_123",
StripeWebhookKey: "whsec_test_123",
StripePriceMatrix: map[string]map[string]string{
"starter": {"czk": "price_starter_czk", "usd": "price_starter_usd"},
"pro": {"czk": "price_pro_czk", "usd": "price_pro_usd"},
"business": {"czk": "price_business_czk", "usd": "price_business_usd"},
},
}
}
func TestGetSubscriptionFallsBackToSnapshotAndEntitlements(t *testing.T) {
service := NewService(testConfig(), db.NewMemoryRepository())
snapshot, err := service.GetSubscription(context.Background(), domain.Principal{
Subject: "demo-owner",
Email: "[email protected]",
})
if err != nil {
t.Fatalf("get subscription: %v", err)
}
if snapshot.PlanCode != "pro" {
t.Fatalf("expected pro, got %s", snapshot.PlanCode)
}
if snapshot.Provider != "stripe" {
t.Fatalf("expected stripe provider, got %s", snapshot.Provider)
}
if snapshot.Entitlements.MaxLocations != 3 {
t.Fatalf("expected 3 locations, got %d", snapshot.Entitlements.MaxLocations)
}
}
func TestCreateCheckoutRequiresStripeConfig(t *testing.T) {
cfg := testConfig()
cfg.StripeAPIKey = ""
service := NewService(cfg, db.NewMemoryRepository())
response, err := service.CreateCheckoutSession(context.Background(), domain.Principal{
Subject: "demo-owner",
Email: "[email protected]",
}, "pro", "czk", "monthly")
if err != ErrStripeNotConfigured {
t.Fatalf("expected ErrStripeNotConfigured, got response=%v err=%v", response, err)
}
}
func TestCreateCheckoutRejectsUnconfiguredPlan(t *testing.T) {
cfg := testConfig()
cfg.StripePriceMatrix["pro"] = map[string]string{}
service := NewService(cfg, db.NewMemoryRepository())
_, err := service.CreateCheckoutSession(context.Background(), domain.Principal{
Subject: "demo-owner",
Email: "[email protected]",
}, "pro", "czk", "monthly")
if err != ErrBillingPlanUnsupported {
t.Fatalf("expected ErrBillingPlanUnsupported, got %v", err)
}
}
func TestRefreshRequiresStripeKeyWhenCustomerExists(t *testing.T) {
cfg := testConfig()
cfg.StripeAPIKey = ""
service := NewService(cfg, db.NewMemoryRepository())
snapshot, err := service.Refresh(context.Background(), domain.Principal{
Subject: "demo-owner",
Email: "[email protected]",
})
if err != ErrStripeNotConfigured {
t.Fatalf("expected ErrStripeNotConfigured, got snapshot=%v err=%v", snapshot, err)
}
}
func TestGetSubscriptionDisablesCheckoutWhenWebhookMissing(t *testing.T) {
cfg := testConfig()
cfg.StripeWebhookKey = ""
service := NewService(cfg, db.NewMemoryRepository())
snapshot, err := service.GetSubscription(context.Background(), domain.Principal{
Subject: "demo-owner",
Email: "[email protected]",
})
if err != nil {
t.Fatalf("get subscription: %v", err)
}
if snapshot.CheckoutURLAvailable {
t.Fatal("expected checkout unavailable without webhook secret")
}
}
func TestGetSubscriptionEnablesCheckoutWhenStripeConfigured(t *testing.T) {
service := NewService(testConfig(), db.NewMemoryRepository())
snapshot, err := service.GetSubscription(context.Background(), domain.Principal{
Subject: "demo-owner",
Email: "[email protected]",
})
if err != nil {
t.Fatalf("get subscription: %v", err)
}
if !snapshot.CheckoutURLAvailable {
t.Fatal("expected checkout available when stripe is configured")
}
if !snapshot.PortalAvailable {
t.Fatal("expected portal available when customer exists")
}
}
func TestCreatePortalSessionRequiresCustomer(t *testing.T) {
repo := db.NewMemoryRepository()
membership, err := repo.GetTenantMembershipBySubject(context.Background(), "demo-owner")
if err != nil {
t.Fatalf("get membership: %v", err)
}
if err := repo.UpdateTenantBillingCustomerID(context.Background(), membership.Tenant.ID, "stripe", ""); err != nil {
t.Fatalf("clear billing customer: %v", err)
}
service := NewService(testConfig(), repo)
_, err = service.CreatePortalSession(context.Background(), domain.Principal{
Subject: "demo-owner",
Email: "[email protected]",
})
if err != ErrBillingCustomerMissing {
t.Fatalf("expected ErrBillingCustomerMissing, got %v", err)
}
}