removed all references to credits. now credits are completely replaced by addons.
This commit is contained in:
@@ -18,13 +18,7 @@ class PublicEventErrorResponseTest extends TestCase
|
||||
'error' => ['code', 'title', 'message', 'meta'],
|
||||
]);
|
||||
|
||||
$response->assertJson([
|
||||
'error' => [
|
||||
'code' => 'invalid_token',
|
||||
'title' => 'Invalid Join Token',
|
||||
'message' => 'The provided join token is invalid.',
|
||||
],
|
||||
]);
|
||||
$response->assertJsonPath('error.code', 'invalid_token');
|
||||
|
||||
$this->assertSame('not-a-token', $response->json('error.meta.token'));
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Tests\Feature\Api;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Laravel\Sanctum\Sanctum;
|
||||
use Tests\TestCase;
|
||||
|
||||
@@ -15,8 +15,24 @@ class HelpControllerTest extends TestCase
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
Storage::fake('local');
|
||||
$this->artisan('help:sync');
|
||||
|
||||
Cache::put('help.guest.en', collect([
|
||||
[
|
||||
'slug' => 'getting-started',
|
||||
'title' => 'Getting Started',
|
||||
'summary' => 'Welcome guide',
|
||||
'body_html' => '<p>When to read this</p>',
|
||||
],
|
||||
]), now()->addMinutes(30));
|
||||
|
||||
Cache::put('help.admin.en', collect([
|
||||
[
|
||||
'slug' => 'tenant-dashboard-overview',
|
||||
'title' => 'Dashboard Overview',
|
||||
'summary' => 'Overview for admins',
|
||||
'body_html' => '<p>Admin guide</p>',
|
||||
],
|
||||
]), now()->addMinutes(30));
|
||||
}
|
||||
|
||||
public function test_guest_help_listing_is_public(): void
|
||||
|
||||
@@ -17,7 +17,6 @@ class TenantProfileApiTest extends TestCase
|
||||
$tenant = Tenant::factory()->create([
|
||||
'name' => 'Test Tenant GmbH',
|
||||
'slug' => 'test-tenant',
|
||||
'event_credits_balance' => 12,
|
||||
'features' => ['custom_branding' => true],
|
||||
]);
|
||||
|
||||
@@ -53,7 +52,6 @@ class TenantProfileApiTest extends TestCase
|
||||
$me->assertJsonFragment([
|
||||
'name' => 'Test Tenant GmbH',
|
||||
'slug' => 'test-tenant',
|
||||
'event_credits_balance' => 12,
|
||||
]);
|
||||
|
||||
$data = $me->json();
|
||||
@@ -69,7 +67,6 @@ class TenantProfileApiTest extends TestCase
|
||||
'id' => $tenant->id,
|
||||
'tenant_id' => $tenant->id,
|
||||
'name' => 'Test Tenant GmbH',
|
||||
'event_credits_balance' => 12,
|
||||
'fullName' => 'Max Mustermann',
|
||||
]);
|
||||
$legacy->assertJsonStructure([
|
||||
@@ -79,7 +76,6 @@ class TenantProfileApiTest extends TestCase
|
||||
'slug',
|
||||
'email',
|
||||
'fullName',
|
||||
'event_credits_balance',
|
||||
'active_reseller_package_id',
|
||||
'remaining_events',
|
||||
'package_expires_at',
|
||||
|
||||
@@ -5,7 +5,6 @@ namespace Tests\Feature\Console;
|
||||
use App\Console\Commands\CheckEventPackages;
|
||||
use App\Events\Packages\EventPackageGalleryExpired;
|
||||
use App\Events\Packages\EventPackageGalleryExpiring;
|
||||
use App\Events\Packages\TenantCreditsLow;
|
||||
use App\Events\Packages\TenantPackageExpired;
|
||||
use App\Events\Packages\TenantPackageExpiring;
|
||||
use App\Models\Event;
|
||||
@@ -144,73 +143,4 @@ class CheckEventPackagesCommandTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
public function test_dispatches_credit_warning_and_sets_threshold(): void
|
||||
{
|
||||
EventFacade::fake();
|
||||
|
||||
Config::set('package-limits.credit_thresholds', [5, 1]);
|
||||
|
||||
$tenant = Tenant::factory()->create([
|
||||
'event_credits_balance' => 5,
|
||||
'credit_warning_sent_at' => null,
|
||||
'credit_warning_threshold' => null,
|
||||
]);
|
||||
|
||||
Artisan::call(CheckEventPackages::class);
|
||||
|
||||
EventFacade::assertDispatched(TenantCreditsLow::class, function ($event) use ($tenant) {
|
||||
return $event->tenant->is($tenant) && $event->threshold === 5 && $event->balance === 5;
|
||||
});
|
||||
|
||||
$tenant->refresh();
|
||||
|
||||
$this->assertNotNull($tenant->credit_warning_sent_at);
|
||||
$this->assertSame(5, $tenant->credit_warning_threshold);
|
||||
}
|
||||
|
||||
public function test_resets_credit_warning_when_balance_recovers(): void
|
||||
{
|
||||
EventFacade::fake();
|
||||
|
||||
Config::set('package-limits.credit_thresholds', [5, 1]);
|
||||
|
||||
$tenant = Tenant::factory()->create([
|
||||
'event_credits_balance' => 10,
|
||||
'credit_warning_sent_at' => now()->subDay(),
|
||||
'credit_warning_threshold' => 1,
|
||||
]);
|
||||
|
||||
Artisan::call(CheckEventPackages::class);
|
||||
|
||||
EventFacade::assertNotDispatched(TenantCreditsLow::class);
|
||||
|
||||
$tenant->refresh();
|
||||
|
||||
$this->assertNull($tenant->credit_warning_sent_at);
|
||||
$this->assertNull($tenant->credit_warning_threshold);
|
||||
}
|
||||
|
||||
public function test_dispatches_lower_credit_threshold_after_higher_warning(): void
|
||||
{
|
||||
EventFacade::fake();
|
||||
|
||||
Config::set('package-limits.credit_thresholds', [5, 1]);
|
||||
|
||||
$tenant = Tenant::factory()->create([
|
||||
'event_credits_balance' => 1,
|
||||
'credit_warning_sent_at' => now()->subDay(),
|
||||
'credit_warning_threshold' => 5,
|
||||
]);
|
||||
|
||||
Artisan::call(CheckEventPackages::class);
|
||||
|
||||
EventFacade::assertDispatched(TenantCreditsLow::class, function ($event) use ($tenant) {
|
||||
return $event->tenant->is($tenant) && $event->threshold === 1;
|
||||
});
|
||||
|
||||
$tenant->refresh();
|
||||
|
||||
$this->assertSame(1, $tenant->credit_warning_threshold);
|
||||
$this->assertNotNull($tenant->credit_warning_sent_at);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,9 +20,7 @@ class DashboardPageTest extends TestCase
|
||||
|
||||
public function test_unverified_user_can_access_dashboard_with_summary_data(): void
|
||||
{
|
||||
$tenant = Tenant::factory()->create([
|
||||
'event_credits_balance' => 4,
|
||||
]);
|
||||
$tenant = Tenant::factory()->create();
|
||||
|
||||
$package = Package::factory()->reseller()->create([
|
||||
'name_translations' => [
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Packages;
|
||||
|
||||
use App\Jobs\Packages\SendTenantCreditsLowNotification;
|
||||
use App\Models\Tenant;
|
||||
use App\Notifications\Packages\TenantCreditsLowNotification;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SendTenantCreditsLowNotificationTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_logs_successful_notification(): void
|
||||
{
|
||||
Notification::fake();
|
||||
|
||||
$tenant = Tenant::factory()->create([
|
||||
'contact_email' => 'admin@example.com',
|
||||
]);
|
||||
|
||||
$job = new SendTenantCreditsLowNotification($tenant->id, balance: 5, threshold: 10);
|
||||
$job->handle();
|
||||
|
||||
Notification::assertSentOnDemand(TenantCreditsLowNotification::class, function ($notification, $channels, $notifiable) {
|
||||
return in_array('mail', $channels, true) && ($notifiable->routes['mail'] ?? null) === 'admin@example.com';
|
||||
});
|
||||
|
||||
$tenant->refresh();
|
||||
|
||||
$this->assertCount(1, $tenant->notificationLogs);
|
||||
$log = $tenant->notificationLogs()->first();
|
||||
$this->assertSame('credits_low', $log->type);
|
||||
$this->assertSame('sent', $log->status);
|
||||
$this->assertSame('admin@example.com', $log->recipient);
|
||||
$this->assertNotNull($log->sent_at);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,6 @@ class ProfilePageTest extends TestCase
|
||||
public function test_profile_page_displays_user_and_package_information(): void
|
||||
{
|
||||
$tenant = Tenant::factory()->create([
|
||||
'event_credits_balance' => 7,
|
||||
'subscription_status' => 'active',
|
||||
'subscription_expires_at' => now()->addMonths(3),
|
||||
]);
|
||||
|
||||
@@ -23,9 +23,7 @@ class DashboardSummaryTest extends TestCase
|
||||
{
|
||||
app()->setLocale('de');
|
||||
|
||||
$tenant = Tenant::factory()->create([
|
||||
'event_credits_balance' => 5,
|
||||
]);
|
||||
$tenant = Tenant::factory()->create();
|
||||
|
||||
$eventType = EventType::factory()->create();
|
||||
|
||||
@@ -106,10 +104,5 @@ class DashboardSummaryTest extends TestCase
|
||||
$activePackage->expires_at->toIso8601String(),
|
||||
Arr::get($payload, 'active_package.expires_at')
|
||||
);
|
||||
|
||||
$this->assertSame(
|
||||
$tenant->event_credits_balance,
|
||||
Arr::get($payload, 'credit_balance')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Tenant;
|
||||
|
||||
use App\Models\EventType;
|
||||
use App\Models\Package;
|
||||
use Illuminate\Support\Carbon;
|
||||
|
||||
class EventCreditsTest extends TenantTestCase
|
||||
{
|
||||
public function test_event_creation_requires_credits(): void
|
||||
{
|
||||
$this->tenant->update(['event_credits_balance' => 0]);
|
||||
$eventType = EventType::factory()->create();
|
||||
|
||||
$package = Package::factory()->create([
|
||||
'type' => 'endcustomer',
|
||||
'price' => 0,
|
||||
'gallery_days' => 30,
|
||||
]);
|
||||
|
||||
$this->tenant->tenantPackages()->create([
|
||||
'package_id' => $package->id,
|
||||
'price' => $package->price,
|
||||
'purchased_at' => now()->subDay(),
|
||||
'expires_at' => now()->addMonth(),
|
||||
'active' => true,
|
||||
]);
|
||||
|
||||
$payload = [
|
||||
'name' => 'Sample Event',
|
||||
'description' => 'Test description',
|
||||
'event_date' => Carbon::now()->addDays(3)->toDateString(),
|
||||
'event_type_id' => $eventType->id,
|
||||
];
|
||||
|
||||
$response = $this->authenticatedRequest('POST', '/api/v1/tenant/events', $payload);
|
||||
|
||||
$response->assertStatus(402)
|
||||
->assertJsonPath('error.code', 'event_credits_exhausted')
|
||||
->assertJsonPath('error.meta.balance', 0);
|
||||
|
||||
$this->tenant->update(['event_credits_balance' => 2]);
|
||||
|
||||
$createResponse = $this->authenticatedRequest('POST', '/api/v1/tenant/events', $payload);
|
||||
|
||||
$createResponse->assertStatus(201)
|
||||
->assertJsonPath('message', 'Event created successfully')
|
||||
->assertJsonPath('data.package.id', $package->id);
|
||||
|
||||
$createdEventId = $createResponse->json('data.id');
|
||||
|
||||
$this->assertNotNull($createdEventId);
|
||||
$this->assertDatabaseHas('event_packages', [
|
||||
'event_id' => $createdEventId,
|
||||
'package_id' => $package->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -58,10 +58,6 @@ class EventManagementTest extends TenantTestCase
|
||||
'active' => true,
|
||||
]);
|
||||
|
||||
$this->tenant->update([
|
||||
'event_credits_balance' => 1,
|
||||
]);
|
||||
|
||||
$payload = [
|
||||
'name' => 'Launch Event',
|
||||
'slug' => 'launch-event',
|
||||
|
||||
@@ -37,7 +37,6 @@ class NotificationPreferencesTest extends TestCase
|
||||
'defaults',
|
||||
'preferences',
|
||||
'overrides',
|
||||
'meta' => ['credit_warning_sent_at', 'credit_warning_threshold'],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Models\Tenant;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Tests\TestCase;
|
||||
|
||||
class TenantCreditsTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_tenant_can_retrieve_balance_and_purchase_credits(): void
|
||||
{
|
||||
$tenant = Tenant::factory()->create([
|
||||
'slug' => 'credits-tenant',
|
||||
'event_credits_balance' => 0,
|
||||
]);
|
||||
|
||||
$user = User::factory()->create([
|
||||
'tenant_id' => $tenant->id,
|
||||
'role' => 'tenant_admin',
|
||||
'email' => 'tenant-admin@example.com',
|
||||
'password' => Hash::make('password'),
|
||||
]);
|
||||
|
||||
$login = $this->postJson('/api/v1/tenant-auth/login', [
|
||||
'login' => $user->email,
|
||||
'password' => 'password',
|
||||
]);
|
||||
|
||||
$login->assertOk();
|
||||
|
||||
$accessToken = $login->json('token');
|
||||
|
||||
$headers = [
|
||||
'Authorization' => 'Bearer '.$accessToken,
|
||||
];
|
||||
|
||||
$balanceResponse = $this->withHeaders($headers)
|
||||
->getJson('/api/v1/tenant/credits/balance');
|
||||
|
||||
$balanceResponse->assertOk()
|
||||
->assertJsonStructure(['balance', 'free_event_granted_at']);
|
||||
|
||||
$purchaseResponse = $this->withHeaders($headers)
|
||||
->postJson('/api/v1/tenant/credits/purchase', [
|
||||
'package_id' => 'event_starter',
|
||||
'credits_added' => 5,
|
||||
'platform' => 'capacitor',
|
||||
'transaction_id' => 'txn_test_123',
|
||||
'subscription_active' => false,
|
||||
]);
|
||||
|
||||
$purchaseResponse->assertCreated()
|
||||
->assertJsonStructure(['message', 'balance', 'subscription_active']);
|
||||
|
||||
$tenant->refresh();
|
||||
$this->assertSame(5, $tenant->event_credits_balance);
|
||||
|
||||
$this->assertDatabaseHas('event_purchases', [
|
||||
'tenant_id' => $tenant->id,
|
||||
'events_purchased' => 5,
|
||||
'external_receipt_id' => 'txn_test_123',
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('event_credits_ledger', [
|
||||
'tenant_id' => $tenant->id,
|
||||
'delta' => 5,
|
||||
'reason' => 'purchase',
|
||||
]);
|
||||
|
||||
$syncResponse = $this->withHeaders($headers)
|
||||
->postJson('/api/v1/tenant/credits/sync', [
|
||||
'balance' => $tenant->event_credits_balance,
|
||||
'subscription_active' => false,
|
||||
'last_sync' => now()->toIso8601String(),
|
||||
]);
|
||||
|
||||
$syncResponse->assertOk()
|
||||
->assertJsonStructure(['balance', 'subscription_active', 'server_time']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Filament\Widgets\CreditAlertsWidget;
|
||||
use App\Filament\Widgets\RevenueTrendWidget;
|
||||
use App\Models\PurchaseHistory;
|
||||
use App\Models\Tenant;
|
||||
@@ -21,67 +20,17 @@ class AdminDashboardWidgetsTest extends TestCase
|
||||
Carbon::setTestNow();
|
||||
}
|
||||
|
||||
public function test_credit_alerts_widget_cards_reflect_metrics(): void
|
||||
{
|
||||
$lowBalanceTenant = Tenant::factory()->create([
|
||||
'event_credits_balance' => 2,
|
||||
'is_active' => true,
|
||||
'subscription_expires_at' => now()->addMonths(2),
|
||||
]);
|
||||
|
||||
Tenant::factory()->create([
|
||||
'event_credits_balance' => 20,
|
||||
'is_active' => true,
|
||||
'subscription_expires_at' => now()->addMonths(1),
|
||||
]);
|
||||
|
||||
Tenant::factory()->create([
|
||||
'event_credits_balance' => 1,
|
||||
'is_active' => false,
|
||||
'subscription_expires_at' => now()->subDay(),
|
||||
]);
|
||||
|
||||
PurchaseHistory::create([
|
||||
'id' => 'ph-1',
|
||||
'tenant_id' => $lowBalanceTenant->id,
|
||||
'package_id' => 'starter_pack',
|
||||
'credits_added' => 5,
|
||||
'price' => 149.90,
|
||||
'currency' => 'EUR',
|
||||
'platform' => 'web',
|
||||
'transaction_id' => 'txn-1',
|
||||
'purchased_at' => now()->startOfMonth()->addDay(),
|
||||
'created_at' => now(),
|
||||
]);
|
||||
|
||||
$widget = new CreditAlertsWidget();
|
||||
|
||||
$cards = $this->invokeProtectedMethod($widget, 'getCards');
|
||||
|
||||
$this->assertCount(3, $cards);
|
||||
$this->assertSame(
|
||||
__('admin.widgets.credit_alerts.low_balance_label'),
|
||||
$cards[0]->getLabel()
|
||||
);
|
||||
$this->assertSame(1, $cards[0]->getValue());
|
||||
$this->assertSame(
|
||||
2,
|
||||
$cards[2]->getValue()
|
||||
);
|
||||
$this->assertStringContainsString('149.9', (string) $cards[1]->getValue());
|
||||
}
|
||||
|
||||
public function test_revenue_trend_widget_compiles_monthly_totals(): void
|
||||
{
|
||||
Carbon::setTestNow(Carbon::create(2025, 10, 20, 12));
|
||||
|
||||
$tenant = Tenant::factory()->create();
|
||||
$packagePro = \App\Models\Package::factory()->create(['name' => 'Pro Pack']);
|
||||
$packageStarter = \App\Models\Package::factory()->create(['name' => 'Starter Pack']);
|
||||
|
||||
PurchaseHistory::create([
|
||||
'id' => 'cur-1',
|
||||
'tenant_id' => $tenant->id,
|
||||
'package_id' => 'pro_pack',
|
||||
'credits_added' => 10,
|
||||
'package_id' => $packagePro->id,
|
||||
'price' => 299.99,
|
||||
'currency' => 'EUR',
|
||||
'platform' => 'web',
|
||||
@@ -91,10 +40,8 @@ class AdminDashboardWidgetsTest extends TestCase
|
||||
]);
|
||||
|
||||
PurchaseHistory::create([
|
||||
'id' => 'prev-1',
|
||||
'tenant_id' => $tenant->id,
|
||||
'package_id' => 'starter_pack',
|
||||
'credits_added' => 5,
|
||||
'package_id' => $packageStarter->id,
|
||||
'price' => 149.90,
|
||||
'currency' => 'EUR',
|
||||
'platform' => 'web',
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Jobs\ProcessRevenueCatWebhook;
|
||||
use App\Models\Tenant;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ProcessRevenueCatWebhookTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_job_creates_purchase_and_updates_balance(): void
|
||||
{
|
||||
config()->set('services.revenuecat.product_mappings', 'pro_month:5');
|
||||
$tenant = Tenant::factory()->create([
|
||||
'event_credits_balance' => 1,
|
||||
'subscription_tier' => 'free',
|
||||
]);
|
||||
|
||||
$expiresAt = Carbon::now()->addDays(30)->setTimezone('UTC')->floorSecond();
|
||||
$payload = [
|
||||
'event' => [
|
||||
'app_user_id' => 'tenant:' . $tenant->id,
|
||||
'product_id' => 'pro_month',
|
||||
'transaction_id' => 'txn-test-1',
|
||||
'price' => 19.99,
|
||||
'currency' => 'eur',
|
||||
'expiration_at_ms' => (int) ($expiresAt->valueOf()),
|
||||
],
|
||||
];
|
||||
|
||||
$job = new ProcessRevenueCatWebhook($payload, 'evt-test-1');
|
||||
$job->handle();
|
||||
|
||||
$tenant->refresh();
|
||||
$this->assertSame(6, $tenant->event_credits_balance);
|
||||
$this->assertSame('pro', $tenant->subscription_tier);
|
||||
$this->assertNotNull($tenant->subscription_expires_at);
|
||||
$expected = $expiresAt->clone()->setTimezone(config('app.timezone'));
|
||||
$this->assertLessThanOrEqual(3600, abs($tenant->subscription_expires_at->timestamp - $expected->timestamp));
|
||||
|
||||
$this->assertDatabaseHas('event_purchases', [
|
||||
'tenant_id' => $tenant->id,
|
||||
'provider' => 'revenuecat',
|
||||
'external_receipt_id' => 'txn-test-1',
|
||||
'events_purchased' => 5,
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('event_credits_ledger', [
|
||||
'tenant_id' => $tenant->id,
|
||||
'delta' => 5,
|
||||
'reason' => 'purchase',
|
||||
]);
|
||||
|
||||
$duplicateJob = new ProcessRevenueCatWebhook($payload, 'evt-test-1');
|
||||
$duplicateJob->handle();
|
||||
|
||||
$this->assertSame(6, $tenant->fresh()->event_credits_balance);
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,13 @@ class PackageLimitEvaluatorTest extends TestCase
|
||||
|
||||
public function test_assess_event_creation_returns_null_when_allowance_available(): void
|
||||
{
|
||||
$tenant = Tenant::factory()->create(['event_credits_balance' => 2]);
|
||||
$tenant = Tenant::factory()->create();
|
||||
$package = Package::factory()->reseller()->create(['max_events_per_year' => 5]);
|
||||
TenantPackage::factory()->for($tenant)->for($package)->create([
|
||||
'used_events' => 1,
|
||||
'expires_at' => now()->addMonth(),
|
||||
'active' => true,
|
||||
]);
|
||||
|
||||
$violation = $this->evaluator->assessEventCreation($tenant);
|
||||
|
||||
@@ -39,7 +45,7 @@ class PackageLimitEvaluatorTest extends TestCase
|
||||
'max_events_per_year' => 1,
|
||||
]);
|
||||
|
||||
$tenant = Tenant::factory()->create(['event_credits_balance' => 0]);
|
||||
$tenant = Tenant::factory()->create();
|
||||
|
||||
TenantPackage::factory()->create([
|
||||
'tenant_id' => $tenant->id,
|
||||
@@ -59,17 +65,6 @@ class PackageLimitEvaluatorTest extends TestCase
|
||||
$this->assertSame(0, $violation['meta']['remaining']);
|
||||
}
|
||||
|
||||
public function test_assess_event_creation_returns_credit_violation_when_no_credits(): void
|
||||
{
|
||||
$tenant = Tenant::factory()->create(['event_credits_balance' => 0]);
|
||||
|
||||
$violation = $this->evaluator->assessEventCreation($tenant);
|
||||
|
||||
$this->assertNotNull($violation);
|
||||
$this->assertSame('event_credits_exhausted', $violation['code']);
|
||||
$this->assertSame('credits', $violation['meta']['scope']);
|
||||
}
|
||||
|
||||
public function test_assess_photo_upload_returns_violation_when_photo_limit_reached(): void
|
||||
{
|
||||
$package = Package::factory()->endcustomer()->create([
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Tests\Unit\Services;
|
||||
|
||||
use App\Events\Packages\TenantCreditsLow;
|
||||
use App\Events\Packages\TenantPackageEventLimitReached;
|
||||
use App\Events\Packages\TenantPackageEventThresholdReached;
|
||||
use App\Models\Package;
|
||||
@@ -85,31 +84,4 @@ class TenantUsageTrackerTest extends TestCase
|
||||
|
||||
$this->assertNotNull($tenantPackage->event_limit_notified_at);
|
||||
}
|
||||
|
||||
public function test_record_credit_balance_dispatches_event_and_updates_tenant(): void
|
||||
{
|
||||
EventFacade::fake([TenantCreditsLow::class]);
|
||||
|
||||
Config::set('package-limits.credit_thresholds', [5, 1]);
|
||||
|
||||
$tenant = Tenant::factory()->create([
|
||||
'event_credits_balance' => 5,
|
||||
'credit_warning_sent_at' => null,
|
||||
'credit_warning_threshold' => null,
|
||||
]);
|
||||
|
||||
/** @var TenantUsageTracker $tracker */
|
||||
$tracker = app(TenantUsageTracker::class);
|
||||
|
||||
$tracker->recordCreditBalance($tenant, 6, 5);
|
||||
|
||||
EventFacade::assertDispatched(TenantCreditsLow::class, function ($event) use ($tenant) {
|
||||
return $event->tenant->is($tenant) && $event->threshold === 5;
|
||||
});
|
||||
|
||||
$tenant->refresh();
|
||||
|
||||
$this->assertNotNull($tenant->credit_warning_sent_at);
|
||||
$this->assertSame(5, $tenant->credit_warning_threshold);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\Package;
|
||||
use App\Models\Tenant;
|
||||
use App\Models\TenantPackage;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class TenantCreditTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_consume_event_allowance_uses_reseller_package(): void
|
||||
{
|
||||
$package = Package::factory()
|
||||
->reseller()
|
||||
->create([
|
||||
'max_events_per_year' => 5,
|
||||
]);
|
||||
|
||||
$tenant = Tenant::factory()->create([
|
||||
'event_credits_balance' => 0,
|
||||
]);
|
||||
|
||||
TenantPackage::factory()->for($tenant)->for($package)->create([
|
||||
'used_events' => 1,
|
||||
'active' => true,
|
||||
]);
|
||||
|
||||
$this->assertTrue($tenant->consumeEventAllowance());
|
||||
|
||||
$updatedPackage = $tenant->getActiveResellerPackage();
|
||||
$this->assertNotNull($updatedPackage);
|
||||
$this->assertSame(2, $updatedPackage->used_events);
|
||||
}
|
||||
|
||||
public function test_consume_event_allowance_decrements_credits_when_no_package(): void
|
||||
{
|
||||
$tenant = Tenant::factory()->create([
|
||||
'event_credits_balance' => 2,
|
||||
]);
|
||||
|
||||
$this->assertTrue($tenant->consumeEventAllowance(1, 'event.create', 'Event #1 created'));
|
||||
|
||||
$tenant->refresh();
|
||||
$this->assertSame(1, $tenant->event_credits_balance);
|
||||
|
||||
$this->assertDatabaseHas('event_credits_ledger', [
|
||||
'tenant_id' => $tenant->id,
|
||||
'delta' => -1,
|
||||
'reason' => 'event.create',
|
||||
'note' => 'Event #1 created',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_consume_event_allowance_returns_false_without_package_or_credits(): void
|
||||
{
|
||||
$tenant = Tenant::factory()->create([
|
||||
'event_credits_balance' => 0,
|
||||
]);
|
||||
|
||||
$this->assertFalse($tenant->consumeEventAllowance());
|
||||
|
||||
$this->assertDatabaseCount('event_credits_ledger', 0);
|
||||
}
|
||||
}
|
||||
@@ -146,22 +146,4 @@ class TenantModelTest extends TestCase
|
||||
$this->assertFalse($tenant->features['analytics']);
|
||||
}
|
||||
|
||||
public function test_increment_credits_clears_warning_when_balance_above_threshold(): void
|
||||
{
|
||||
Config::set('package-limits.credit_thresholds', [5, 1]);
|
||||
|
||||
$tenant = Tenant::factory()->create([
|
||||
'event_credits_balance' => 1,
|
||||
'credit_warning_sent_at' => now()->subDay(),
|
||||
'credit_warning_threshold' => 1,
|
||||
]);
|
||||
|
||||
$tenant->incrementCredits(10);
|
||||
|
||||
$tenant->refresh();
|
||||
|
||||
$this->assertNull($tenant->credit_warning_sent_at);
|
||||
$this->assertNull($tenant->credit_warning_threshold);
|
||||
$this->assertSame(11, (int) $tenant->event_credits_balance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\Tenant;
|
||||
use App\Models\User;
|
||||
use App\Policies\TenantPolicy;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class TenantPolicyTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected TenantPolicy $policy;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->policy = new TenantPolicy();
|
||||
}
|
||||
|
||||
public function test_super_admin_can_adjust_credits(): void
|
||||
{
|
||||
$tenant = Tenant::factory()->create();
|
||||
$user = User::factory()->create([
|
||||
'role' => 'super_admin',
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->policy->adjustCredits($user, $tenant));
|
||||
}
|
||||
|
||||
public function test_tenant_admin_cannot_adjust_credits(): void
|
||||
{
|
||||
$tenant = Tenant::factory()->create();
|
||||
$user = User::factory()->create([
|
||||
'role' => 'tenant_admin',
|
||||
]);
|
||||
|
||||
$user->forceFill(['tenant_id' => $tenant->id])->save();
|
||||
|
||||
$this->assertFalse($this->policy->adjustCredits($user, $tenant));
|
||||
}
|
||||
|
||||
public function test_tenant_admin_can_view_own_tenant(): void
|
||||
{
|
||||
$tenant = Tenant::factory()->create();
|
||||
$user = User::factory()->create([
|
||||
'role' => 'tenant_admin',
|
||||
]);
|
||||
|
||||
$user->forceFill(['tenant_id' => $tenant->id])->save();
|
||||
|
||||
$this->assertTrue($this->policy->view($user, $tenant));
|
||||
}
|
||||
|
||||
public function test_tenant_admin_cannot_view_other_tenant(): void
|
||||
{
|
||||
$tenant = Tenant::factory()->create();
|
||||
$otherTenant = Tenant::factory()->create();
|
||||
|
||||
$user = User::factory()->create([
|
||||
'role' => 'tenant_admin',
|
||||
]);
|
||||
|
||||
$user->forceFill(['tenant_id' => $tenant->id])->save();
|
||||
|
||||
$this->assertFalse($this->policy->view($user, $otherTenant));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user