mirror of
https://github.com/Dvorinka/Bookra.git
synced 2026-06-03 20:13:00 +00:00
feat(sms): implement SMS messaging and metered billing
Implement a complete SMS messaging system including: - Integration with SMS Manager.cz API for sending messages. - Metered billing via Stripe using monthly aggregate invoice items. - Backend services for managing SMS settings, usage logging, and monthly reporting. - Database migrations for tenant settings, usage logs, and monthly reports. - Frontend dashboard components for SMS configuration, usage tracking, and history. - Support for customer phone numbers in the booking flow. Includes new migrations, backend services, and frontend UI components.
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
package sms
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"bookra/apps/backend/internal/config"
|
||||
"bookra/apps/backend/internal/db"
|
||||
"bookra/apps/backend/internal/domain"
|
||||
)
|
||||
|
||||
func TestSMSServiceEnabled(t *testing.T) {
|
||||
cfg := config.Config{SMSManagerAPIKey: "test-key"}
|
||||
svc := NewService(cfg, db.NewMemoryRepository())
|
||||
if !svc.Enabled() {
|
||||
t.Fatal("expected SMS service to be enabled")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSMSServiceDisabledWithoutKey(t *testing.T) {
|
||||
cfg := config.Config{}
|
||||
svc := NewService(cfg, db.NewMemoryRepository())
|
||||
if svc.Enabled() {
|
||||
t.Fatal("expected SMS service to be disabled")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetSettingsForNewTenant(t *testing.T) {
|
||||
cfg := config.Config{SMSManagerAPIKey: "test-key"}
|
||||
repo := db.NewMemoryRepository()
|
||||
svc := NewService(cfg, repo)
|
||||
|
||||
ctx := context.Background()
|
||||
// Use the default tenant ID from memory repository
|
||||
settings, err := svc.GetSettings(ctx, "5d6b3551-0a3e-4b86-bdf0-e9df20a47148")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if settings.Enabled {
|
||||
t.Fatal("expected SMS to be disabled by default")
|
||||
}
|
||||
if !settings.Available {
|
||||
t.Fatal("expected SMS to be available when configured")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateSettingsRequiresProOrBusiness(t *testing.T) {
|
||||
cfg := config.Config{SMSManagerAPIKey: "test-key"}
|
||||
repo := db.NewMemoryRepository()
|
||||
svc := NewService(cfg, repo)
|
||||
|
||||
ctx := context.Background()
|
||||
// Memory repo tenant is "pro" by default. Change to starter by modifying tenant.
|
||||
_, err := svc.UpdateSettings(ctx, "5d6b3551-0a3e-4b86-bdf0-e9df20a47148", domain.UpdateSMSSettingsRequest{Enabled: true})
|
||||
// The memory repo tenant is "pro", so this should succeed
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error for pro tenant: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendMessageRequiresEnabledSMS(t *testing.T) {
|
||||
cfg := config.Config{SMSManagerAPIKey: "test-key"}
|
||||
repo := db.NewMemoryRepository()
|
||||
svc := NewService(cfg, repo)
|
||||
|
||||
ctx := context.Background()
|
||||
_, err := svc.SendMessage(ctx, "5d6b3551-0a3e-4b86-bdf0-e9df20a47148", domain.SendSMSRequest{To: "+420777123456", Body: "Hello"})
|
||||
if err != ErrSMSNotEnabled {
|
||||
t.Fatalf("expected ErrSMSNotEnabled, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizePhone(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{"+420 777 123 456", "420777123456"},
|
||||
{"420777123456", "420777123456"},
|
||||
{"777123456", "420777123456"},
|
||||
{" 777-123-456 ", "420777123456"},
|
||||
{"+49 151 12345678", "4915112345678"},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
result := normalizePhone(tc.input)
|
||||
if result != tc.expected {
|
||||
t.Errorf("normalizePhone(%q) = %q, want %q", tc.input, result, tc.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user