mirror of
https://github.com/solidtime-io/solidtime.git
synced 2026-08-18 05:02:14 +01:00
Add getTrialUntil to BillingContract; Allow delete endpoints after blocking
This commit is contained in:
committed by
Constantin Graf
parent
83301d03ca
commit
01dd13b947
@@ -51,6 +51,7 @@ class HandleInertiaRequests extends Middleware
|
|||||||
'billing' => $billing !== null && $currentOrganization !== null ? [
|
'billing' => $billing !== null && $currentOrganization !== null ? [
|
||||||
'has_subscription' => $billing->hasSubscription($currentOrganization),
|
'has_subscription' => $billing->hasSubscription($currentOrganization),
|
||||||
'has_trial' => $billing->hasTrial($currentOrganization),
|
'has_trial' => $billing->hasTrial($currentOrganization),
|
||||||
|
'trial_until' => $billing->getTrialUntil($currentOrganization)?->toIso8601ZuluString(),
|
||||||
'is_blocked' => $billing->isBlocked($currentOrganization),
|
'is_blocked' => $billing->isBlocked($currentOrganization),
|
||||||
] : null,
|
] : null,
|
||||||
'flash' => [
|
'flash' => [
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ declare(strict_types=1);
|
|||||||
namespace App\Service;
|
namespace App\Service;
|
||||||
|
|
||||||
use App\Models\Organization;
|
use App\Models\Organization;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is a contract for the billing system
|
* This class is a contract for the billing system
|
||||||
@@ -33,6 +34,15 @@ class BillingContract
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the organization is blocked
|
* Check if the organization is blocked
|
||||||
* A blocked organization is an organization that has more than 1 non-placeholder member but no subscription/trial
|
* A blocked organization is an organization that has more than 1 non-placeholder member but no subscription/trial
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ Route::middleware([
|
|||||||
Route::get('/organizations/{organization}/projects/{project}', [ProjectController::class, 'show'])->name('show');
|
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::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::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
|
// Project member routes
|
||||||
@@ -81,7 +81,7 @@ Route::middleware([
|
|||||||
Route::get('/organizations/{organization}/projects/{project}/project-members', [ProjectMemberController::class, 'index'])->name('index');
|
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::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::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
|
// Time entry routes
|
||||||
@@ -91,7 +91,7 @@ Route::middleware([
|
|||||||
Route::post('/organizations/{organization}/time-entries', [TimeEntryController::class, 'store'])->name('store')->middleware('check-organization-blocked');
|
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::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::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 () {
|
Route::name('users.time-entries.')->group(static function () {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ abstract class TestCase extends BaseTestCase
|
|||||||
$this->mock(BillingContract::class, function (MockInterface $mock) {
|
$this->mock(BillingContract::class, function (MockInterface $mock) {
|
||||||
$mock->shouldReceive('hasSubscription')->andReturn(false);
|
$mock->shouldReceive('hasSubscription')->andReturn(false);
|
||||||
$mock->shouldReceive('hasTrial')->andReturn(false);
|
$mock->shouldReceive('hasTrial')->andReturn(false);
|
||||||
|
$mock->shouldReceive('getTrialUntil')->andReturn(null);
|
||||||
$mock->shouldReceive('isBlocked')->andReturn(false);
|
$mock->shouldReceive('isBlocked')->andReturn(false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ namespace Tests\Unit\Middleware;
|
|||||||
use App\Http\Middleware\HandleInertiaRequests;
|
use App\Http\Middleware\HandleInertiaRequests;
|
||||||
use App\Service\BillingContract;
|
use App\Service\BillingContract;
|
||||||
use Illuminate\Session\Middleware\StartSession;
|
use Illuminate\Session\Middleware\StartSession;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use Inertia\Inertia;
|
use Inertia\Inertia;
|
||||||
use Inertia\Testing\AssertableInertia as Assert;
|
use Inertia\Testing\AssertableInertia as Assert;
|
||||||
@@ -31,9 +32,10 @@ class HandleInertiaRequestsMiddlewareTest extends MiddlewareTestAbstract
|
|||||||
// Arrange
|
// Arrange
|
||||||
$user = $this->createUserWithPermission();
|
$user = $this->createUserWithPermission();
|
||||||
$route = $this->createTestRoute();
|
$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('hasSubscription')->andReturn(false);
|
||||||
$mock->shouldReceive('hasTrial')->andReturn(false);
|
$mock->shouldReceive('hasTrial')->andReturn(false);
|
||||||
|
$mock->shouldReceive('getTrialUntil')->andReturn(null);
|
||||||
$mock->shouldReceive('isBlocked')->andReturn(false);
|
$mock->shouldReceive('isBlocked')->andReturn(false);
|
||||||
});
|
});
|
||||||
Passport::actingAs($user->user);
|
Passport::actingAs($user->user);
|
||||||
@@ -45,6 +47,33 @@ class HandleInertiaRequestsMiddlewareTest extends MiddlewareTestAbstract
|
|||||||
$response->assertInertia(fn (Assert $page) => $page
|
$response->assertInertia(fn (Assert $page) => $page
|
||||||
->where('billing.has_subscription', false)
|
->where('billing.has_subscription', false)
|
||||||
->where('billing.has_trial', 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)
|
->where('billing.is_blocked', false)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user