Deploy Ladill Meet / deploy (push) Successful in 46s
Meetings and webinars now share GHS 0.30 per peak participant, with usage UI and plan quotas updated to match. Co-authored-by: Cursor <cursoragent@cursor.com>
166 lines
5.2 KiB
PHP
166 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\Organization;
|
|
use App\Models\Room;
|
|
use App\Models\Session;
|
|
use App\Services\Meet\MeetBillingService;
|
|
use App\Services\Meet\UsageMeteringService;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Tests\TestCase;
|
|
|
|
class MeetBillingTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected function fakeAffordableBilling(): void
|
|
{
|
|
$base = rtrim((string) config('billing.api_url'), '/');
|
|
|
|
Http::fake([
|
|
$base.'/can-afford*' => Http::response(['affordable' => true]),
|
|
$base.'/debit' => Http::response(['ok' => true]),
|
|
]);
|
|
}
|
|
|
|
public function test_session_end_charges_per_participant(): void
|
|
{
|
|
$this->fakeAffordableBilling();
|
|
|
|
$organization = Organization::create([
|
|
'owner_ref' => 'owner-001',
|
|
'name' => 'Billing Org',
|
|
'slug' => 'billing-org',
|
|
'timezone' => 'UTC',
|
|
]);
|
|
|
|
$room = Room::create([
|
|
'owner_ref' => 'owner-001',
|
|
'organization_id' => $organization->id,
|
|
'host_user_ref' => 'owner-001',
|
|
'title' => 'Billing Room',
|
|
'type' => 'instant',
|
|
'status' => 'live',
|
|
'settings' => config('meet.default_settings'),
|
|
]);
|
|
|
|
$session = Session::create([
|
|
'owner_ref' => 'owner-001',
|
|
'room_id' => $room->id,
|
|
'media_room_name' => 'room-test',
|
|
'status' => 'ended',
|
|
'started_at' => now()->subHour(),
|
|
'ended_at' => now(),
|
|
'peak_participants' => 4,
|
|
]);
|
|
|
|
app(UsageMeteringService::class)->recordSessionUsage($session);
|
|
|
|
$this->assertDatabaseHas('meet_usage_records', [
|
|
'organization_id' => $organization->id,
|
|
'metric' => 'participant_count',
|
|
'quantity' => 4,
|
|
]);
|
|
|
|
Http::assertSent(fn ($request) => str_contains($request->url(), '/debit')
|
|
&& ($request->data()['source'] ?? '') === 'meet_participants');
|
|
}
|
|
|
|
public function test_webinar_session_end_charges_per_participant(): void
|
|
{
|
|
$this->fakeAffordableBilling();
|
|
|
|
$organization = Organization::create([
|
|
'owner_ref' => 'owner-webinar',
|
|
'name' => 'Webinar Org',
|
|
'slug' => 'webinar-org',
|
|
'timezone' => 'UTC',
|
|
]);
|
|
|
|
$room = Room::create([
|
|
'owner_ref' => 'owner-webinar',
|
|
'organization_id' => $organization->id,
|
|
'host_user_ref' => 'owner-webinar',
|
|
'title' => 'Webinar Room',
|
|
'type' => 'webinar',
|
|
'status' => 'ended',
|
|
'settings' => config('meet.default_settings'),
|
|
]);
|
|
|
|
$session = Session::create([
|
|
'owner_ref' => 'owner-webinar',
|
|
'room_id' => $room->id,
|
|
'media_room_name' => 'webinar-test',
|
|
'status' => 'ended',
|
|
'started_at' => now()->subHour(),
|
|
'ended_at' => now(),
|
|
'peak_participants' => 5,
|
|
]);
|
|
|
|
app(UsageMeteringService::class)->recordSessionUsage($session);
|
|
|
|
$this->assertDatabaseHas('meet_usage_records', [
|
|
'organization_id' => $organization->id,
|
|
'metric' => 'participant_count',
|
|
'quantity' => 5,
|
|
]);
|
|
|
|
Http::assertSent(fn ($request) => str_contains($request->url(), '/debit')
|
|
&& ($request->data()['source'] ?? '') === 'meet_participants');
|
|
}
|
|
|
|
public function test_storage_renewal_enters_grace_when_wallet_is_empty(): void
|
|
{
|
|
$base = rtrim((string) config('billing.api_url'), '/');
|
|
Http::fake([
|
|
$base.'/can-afford*' => Http::response(['affordable' => false]),
|
|
]);
|
|
|
|
$organization = Organization::create([
|
|
'owner_ref' => 'owner-002',
|
|
'name' => 'Grace Org',
|
|
'slug' => 'grace-org',
|
|
'timezone' => 'UTC',
|
|
]);
|
|
|
|
$room = Room::create([
|
|
'owner_ref' => 'owner-002',
|
|
'organization_id' => $organization->id,
|
|
'host_user_ref' => 'owner-002',
|
|
'title' => 'Grace Room',
|
|
'type' => 'instant',
|
|
'status' => 'ended',
|
|
'settings' => config('meet.default_settings'),
|
|
]);
|
|
|
|
$session = Session::create([
|
|
'owner_ref' => 'owner-002',
|
|
'room_id' => $room->id,
|
|
'media_room_name' => 'room-grace',
|
|
'status' => 'ended',
|
|
'started_at' => now()->subDay(),
|
|
'ended_at' => now()->subDay(),
|
|
]);
|
|
|
|
$file = \App\Models\SessionFile::create([
|
|
'owner_ref' => 'owner-002',
|
|
'room_id' => $room->id,
|
|
'session_id' => $session->id,
|
|
'uploaded_by_ref' => 'owner-002',
|
|
'uploaded_by_name' => 'Host',
|
|
'original_name' => 'notes.pdf',
|
|
'storage_path' => 'meet-files/test/notes.pdf',
|
|
'file_size' => 1073741824,
|
|
'storage_paid_until' => now()->subMinute(),
|
|
]);
|
|
|
|
$result = app(MeetBillingService::class)->processDueStorageRenewals();
|
|
|
|
$file->refresh();
|
|
$this->assertSame(1, $result['graced']);
|
|
$this->assertNotNull($file->storage_grace_ends_at);
|
|
}
|
|
}
|