Skip to content

Commit

Permalink
Add getTrialUntil to BillingContract; Allow delete endpoints after bl…
Browse files Browse the repository at this point in the history
…ocking
  • Loading branch information
korridor committed Sep 5, 2024
1 parent f31b590 commit 76bb999
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 4 deletions.
1 change: 1 addition & 0 deletions app/Http/Middleware/HandleInertiaRequests.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public function share(Request $request): array
'billing' => $billing !== null && $currentOrganization !== null ? [
'has_subscription' => $billing->hasSubscription($currentOrganization),
'has_trial' => $billing->hasTrial($currentOrganization),
'trial_until' => $billing->getTrialUntil($currentOrganization)?->toIso8601ZuluString(),
'is_blocked' => $billing->isBlocked($currentOrganization),
] : null,
'flash' => [
Expand Down
10 changes: 10 additions & 0 deletions app/Service/BillingContract.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace App\Service;

use App\Models\Organization;
use Illuminate\Support\Carbon;

/**
* This class is a contract for the billing system
Expand Down Expand Up @@ -33,6 +34,15 @@ public function hasTrial(Organization $organization): bool
return false;

Check warning on line 34 in app/Service/BillingContract.php

View check run for this annotation

Codecov / codecov/patch

app/Service/BillingContract.php#L34

Added line #L34 was not covered by tests
}

/**
* Get the date until which the organization's trial subscription is valid
* If the organization does not have a trial subscription, this method should return null
*/
public function getTrialUntil(Organization $organization): ?Carbon

Check warning on line 41 in app/Service/BillingContract.php

View check run for this annotation

Codecov / codecov/patch

app/Service/BillingContract.php#L41

Added line #L41 was not covered by tests
{
return null;

Check warning on line 43 in app/Service/BillingContract.php

View check run for this annotation

Codecov / codecov/patch

app/Service/BillingContract.php#L43

Added line #L43 was not covered by tests
}

/**
* Check if the organization is blocked
* A blocked organization is an organization that has more than 1 non-placeholder member but no subscription/trial
Expand Down
6 changes: 3 additions & 3 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,15 @@
Route::get('/organizations/{organization}/projects/{project}', [ProjectController::class, 'show'])->name('show');
Route::post('/organizations/{organization}/projects', [ProjectController::class, 'store'])->name('store')->middleware('check-organization-blocked');
Route::put('/organizations/{organization}/projects/{project}', [ProjectController::class, 'update'])->name('update')->middleware('check-organization-blocked');
Route::delete('/organizations/{organization}/projects/{project}', [ProjectController::class, 'destroy'])->name('destroy')->middleware('check-organization-blocked');
Route::delete('/organizations/{organization}/projects/{project}', [ProjectController::class, 'destroy'])->name('destroy');
});

// Project member routes
Route::name('project-members.')->group(static function () {
Route::get('/organizations/{organization}/projects/{project}/project-members', [ProjectMemberController::class, 'index'])->name('index');
Route::post('/organizations/{organization}/projects/{project}/project-members', [ProjectMemberController::class, 'store'])->name('store')->middleware('check-organization-blocked');
Route::put('/organizations/{organization}/project-members/{projectMember}', [ProjectMemberController::class, 'update'])->name('update')->middleware('check-organization-blocked');
Route::delete('/organizations/{organization}/project-members/{projectMember}', [ProjectMemberController::class, 'destroy'])->name('destroy')->middleware('check-organization-blocked');
Route::delete('/organizations/{organization}/project-members/{projectMember}', [ProjectMemberController::class, 'destroy'])->name('destroy');
});

// Time entry routes
Expand All @@ -91,7 +91,7 @@
Route::post('/organizations/{organization}/time-entries', [TimeEntryController::class, 'store'])->name('store')->middleware('check-organization-blocked');
Route::put('/organizations/{organization}/time-entries/{timeEntry}', [TimeEntryController::class, 'update'])->name('update')->middleware('check-organization-blocked');
Route::patch('/organizations/{organization}/time-entries', [TimeEntryController::class, 'updateMultiple'])->name('update-multiple')->middleware('check-organization-blocked');
Route::delete('/organizations/{organization}/time-entries/{timeEntry}', [TimeEntryController::class, 'destroy'])->name('destroy')->middleware('check-organization-blocked');
Route::delete('/organizations/{organization}/time-entries/{timeEntry}', [TimeEntryController::class, 'destroy'])->name('destroy');
});

Route::name('users.time-entries.')->group(static function () {
Expand Down
1 change: 1 addition & 0 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ protected function setUp(): void
$this->mock(BillingContract::class, function (MockInterface $mock) {
$mock->shouldReceive('hasSubscription')->andReturn(false);
$mock->shouldReceive('hasTrial')->andReturn(false);
$mock->shouldReceive('getTrialUntil')->andReturn(null);
$mock->shouldReceive('isBlocked')->andReturn(false);
});
}
Expand Down
31 changes: 30 additions & 1 deletion tests/Unit/Middleware/HandleInertiaRequestsMiddlewareTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use App\Http\Middleware\HandleInertiaRequests;
use App\Service\BillingContract;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
use Inertia\Testing\AssertableInertia as Assert;
Expand All @@ -31,9 +32,10 @@ public function test_adds_billing_information_to_shared_data_of_inertia_requests
// Arrange
$user = $this->createUserWithPermission();
$route = $this->createTestRoute();
$this->mock(BillingContract::class, function (MockInterface $mock) {
$this->mock(BillingContract::class, function (MockInterface $mock): void {
$mock->shouldReceive('hasSubscription')->andReturn(false);
$mock->shouldReceive('hasTrial')->andReturn(false);
$mock->shouldReceive('getTrialUntil')->andReturn(null);
$mock->shouldReceive('isBlocked')->andReturn(false);
});
Passport::actingAs($user->user);
Expand All @@ -45,6 +47,33 @@ public function test_adds_billing_information_to_shared_data_of_inertia_requests
$response->assertInertia(fn (Assert $page) => $page
->where('billing.has_subscription', false)
->where('billing.has_trial', false)
->where('billing.trial_until', null)
->where('billing.is_blocked', false)
);
}

public function test_adds_billing_information_to_shared_data_of_inertia_requests_with_active_trial(): void
{
// Arrange
$user = $this->createUserWithPermission();
$route = $this->createTestRoute();
$trialUntil = Carbon::now()->addDays(10);
$this->mock(BillingContract::class, function (MockInterface $mock) use ($trialUntil): void {
$mock->shouldReceive('hasSubscription')->andReturn(false);
$mock->shouldReceive('hasTrial')->andReturn(true);
$mock->shouldReceive('getTrialUntil')->andReturn($trialUntil);
$mock->shouldReceive('isBlocked')->andReturn(false);
});
Passport::actingAs($user->user);

// Act
$response = $this->get($route);

// Assert
$response->assertInertia(fn (Assert $page) => $page
->where('billing.has_subscription', false)
->where('billing.has_trial', true)
->where('billing.trial_until', $trialUntil->toIso8601ZuluString())
->where('billing.is_blocked', false)
);
}
Expand Down

0 comments on commit 76bb999

Please sign in to comment.