Merge pull request #19167 from grokability/fmcs-scope-check-updates-for-multiple-companies
FMCS/Console: Fixed #19166 scope check updates for multiple companies, adds floater
This commit is contained in:
@@ -63,7 +63,7 @@ class CheckoutAccessoryTest extends TestCase
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_checkout_to_user_succeeds_when_accessory_has_no_company_with_fmcs_enabled()
|
||||
public function test_checkout_to_user_is_blocked_when_accessory_has_no_company_with_fmcs_enabled_without_floater()
|
||||
{
|
||||
$accessory = Accessory::factory()->create(['qty' => 5, 'company_id' => null]);
|
||||
[$companyA] = Company::factory()->count(1)->create();
|
||||
@@ -71,6 +71,33 @@ class CheckoutAccessoryTest extends TestCase
|
||||
$user->companies()->sync([$companyA->id]);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
$this->settings->disableFloaterMode();
|
||||
|
||||
$actor = User::factory()->superuser()->create();
|
||||
|
||||
$this->actingAs($actor)
|
||||
->post(route('accessories.checkout.store', $accessory), [
|
||||
'checkout_to_type' => 'user',
|
||||
'assigned_user' => $user->id,
|
||||
'checkout_qty' => 1,
|
||||
'redirect_option' => 'index',
|
||||
])
|
||||
->assertRedirect();
|
||||
|
||||
$this->assertDatabaseMissing('accessories_checkout', [
|
||||
'accessory_id' => $accessory->id,
|
||||
'assigned_to' => $user->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_checkout_to_user_succeeds_when_accessory_has_no_company_with_floater_enabled()
|
||||
{
|
||||
$accessory = Accessory::factory()->create(['qty' => 5, 'company_id' => null]);
|
||||
[$companyA] = Company::factory()->count(1)->create();
|
||||
$user = User::factory()->for($companyA)->create();
|
||||
$user->companies()->sync([$companyA->id]);
|
||||
|
||||
$this->settings->enableFloaterMode();
|
||||
|
||||
$actor = User::factory()->superuser()->create();
|
||||
|
||||
@@ -114,13 +141,63 @@ class CheckoutAccessoryTest extends TestCase
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_checkout_to_null_company_user_blocked_in_strict_mode()
|
||||
{
|
||||
[$companyA] = Company::factory()->count(1)->create();
|
||||
$accessory = Accessory::factory()->for($companyA)->create(['qty' => 5]);
|
||||
$nullCompanyUser = User::factory()->create(['company_id' => null]);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$actor = User::factory()->superuser()->create();
|
||||
|
||||
$this->actingAs($actor)
|
||||
->post(route('accessories.checkout.store', $accessory), [
|
||||
'checkout_to_type' => 'user',
|
||||
'assigned_user' => $nullCompanyUser->id,
|
||||
'checkout_qty' => 1,
|
||||
'redirect_option' => 'index',
|
||||
])
|
||||
->assertRedirect();
|
||||
|
||||
$this->assertDatabaseMissing('accessories_checkout', [
|
||||
'accessory_id' => $accessory->id,
|
||||
'assigned_to' => $nullCompanyUser->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_checkout_to_null_company_user_succeeds_in_floater_mode()
|
||||
{
|
||||
[$companyA] = Company::factory()->count(1)->create();
|
||||
$accessory = Accessory::factory()->for($companyA)->create(['qty' => 5]);
|
||||
$nullCompanyUser = User::factory()->create(['company_id' => null]);
|
||||
|
||||
$this->settings->enableFloaterMode();
|
||||
|
||||
$actor = User::factory()->superuser()->create();
|
||||
|
||||
$this->actingAs($actor)
|
||||
->post(route('accessories.checkout.store', $accessory), [
|
||||
'checkout_to_type' => 'user',
|
||||
'assigned_user' => $nullCompanyUser->id,
|
||||
'checkout_qty' => 1,
|
||||
'redirect_option' => 'index',
|
||||
])
|
||||
->assertRedirect();
|
||||
|
||||
$this->assertDatabaseHas('accessories_checkout', [
|
||||
'accessory_id' => $accessory->id,
|
||||
'assigned_to' => $nullCompanyUser->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_checkout_to_location_does_not_throw_when_fmcs_enabled()
|
||||
{
|
||||
[$companyA] = Company::factory()->count(1)->create();
|
||||
$accessory = Accessory::factory()->for($companyA)->create(['qty' => 5]);
|
||||
$location = Location::factory()->create();
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
$this->settings->enableFloaterMode();
|
||||
|
||||
$actor = User::factory()->superuser()->create();
|
||||
|
||||
|
||||
@@ -335,8 +335,8 @@ class AssetCheckoutTest extends TestCase
|
||||
|
||||
public function test_asset_can_be_checked_out_to_user_with_no_company_when_fmcs_enabled()
|
||||
{
|
||||
// Users with no company associations should not be blocked — they're unrestricted.
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
// In floater mode, users with no company associations can receive items from any company.
|
||||
$this->settings->enableFloaterMode();
|
||||
|
||||
$company = Company::factory()->create();
|
||||
// Actor is in the same company as the asset.
|
||||
@@ -408,4 +408,46 @@ class AssetCheckoutTest extends TestCase
|
||||
|
||||
$this->assertTrue((bool) $asset->fresh()->requestable);
|
||||
}
|
||||
|
||||
public function test_null_company_asset_cannot_be_checked_out_to_companied_user_when_fmcs_enabled_without_floater()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
$this->settings->disableFloaterMode();
|
||||
|
||||
$company = Company::factory()->create();
|
||||
$actor = User::factory()->superuser()->create();
|
||||
$nullCompanyAsset = Asset::factory()->create(['company_id' => null]);
|
||||
$companiedUser = User::factory()->for($company)->create();
|
||||
|
||||
$this->actingAsForApi($actor)
|
||||
->postJson(route('api.asset.checkout', $nullCompanyAsset), [
|
||||
'checkout_to_type' => 'user',
|
||||
'assigned_user' => $companiedUser->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('error')
|
||||
->assertMessagesAre(trans('general.error_user_company'));
|
||||
|
||||
$this->assertNull($nullCompanyAsset->fresh()->assigned_to);
|
||||
}
|
||||
|
||||
public function test_null_company_asset_can_be_checked_out_to_companied_user_when_floater_enabled()
|
||||
{
|
||||
$this->settings->enableFloaterMode();
|
||||
|
||||
$company = Company::factory()->create();
|
||||
$actor = User::factory()->superuser()->create();
|
||||
$nullCompanyAsset = Asset::factory()->create(['company_id' => null]);
|
||||
$companiedUser = User::factory()->for($company)->create();
|
||||
|
||||
$this->actingAsForApi($actor)
|
||||
->postJson(route('api.asset.checkout', $nullCompanyAsset), [
|
||||
'checkout_to_type' => 'user',
|
||||
'assigned_user' => $companiedUser->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success');
|
||||
|
||||
$this->assertEquals($companiedUser->id, $nullCompanyAsset->fresh()->assigned_to);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Console;
|
||||
|
||||
use App\Helpers\Helper;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Company;
|
||||
use App\Models\Location;
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
class TestLocationsFmcsTest extends TestCase
|
||||
{
|
||||
private function mismatchedIds(array $mismatched): array
|
||||
{
|
||||
return array_column($mismatched, 1); // column 1 is the item ID
|
||||
}
|
||||
|
||||
private function assetAt(Location $location, array $attrs = []): Asset
|
||||
{
|
||||
// Pin both location_id and rtd_location_id to prevent AssetFactory from
|
||||
// generating a random rtd_location with no company that would cause false mismatches.
|
||||
return Asset::factory()->create(array_merge([
|
||||
'location_id' => $location->id,
|
||||
'rtd_location_id' => $location->id,
|
||||
], $attrs));
|
||||
}
|
||||
|
||||
public function test_item_at_location_with_same_company_is_not_flagged()
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$location = Location::factory()->for($company)->create();
|
||||
$asset = $this->assetAt($location, ['company_id' => $company->id]);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$result = Helper::test_locations_fmcs(true);
|
||||
|
||||
$this->assertNotContains($asset->id, $this->mismatchedIds($result));
|
||||
}
|
||||
|
||||
public function test_item_at_location_with_different_company_is_flagged()
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
$location = Location::factory()->for($companyA)->create();
|
||||
$asset = $this->assetAt($location, ['company_id' => $companyB->id]);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$result = Helper::test_locations_fmcs(true);
|
||||
|
||||
$this->assertContains($asset->id, $this->mismatchedIds($result));
|
||||
}
|
||||
|
||||
public function test_null_company_item_at_company_location_is_flagged_in_strict_mode()
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$location = Location::factory()->for($company)->create();
|
||||
$asset = $this->assetAt($location, ['company_id' => null]);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$result = Helper::test_locations_fmcs(true);
|
||||
|
||||
$this->assertContains($asset->id, $this->mismatchedIds($result));
|
||||
}
|
||||
|
||||
public function test_null_company_item_at_company_location_is_not_flagged_in_floater_mode()
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$location = Location::factory()->for($company)->create();
|
||||
$asset = $this->assetAt($location, ['company_id' => null]);
|
||||
|
||||
$this->settings->enableFloaterMode();
|
||||
|
||||
$result = Helper::test_locations_fmcs(true);
|
||||
|
||||
$this->assertNotContains($asset->id, $this->mismatchedIds($result));
|
||||
}
|
||||
|
||||
public function test_company_item_at_null_company_location_is_flagged_in_strict_mode()
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$location = Location::factory()->create(['company_id' => null]);
|
||||
$asset = $this->assetAt($location, ['company_id' => $company->id]);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$result = Helper::test_locations_fmcs(true);
|
||||
|
||||
$this->assertContains($asset->id, $this->mismatchedIds($result));
|
||||
}
|
||||
|
||||
public function test_company_item_at_null_company_location_is_not_flagged_in_floater_mode()
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$location = Location::factory()->create(['company_id' => null]);
|
||||
$asset = $this->assetAt($location, ['company_id' => $company->id]);
|
||||
|
||||
$this->settings->enableFloaterMode();
|
||||
|
||||
$result = Helper::test_locations_fmcs(true);
|
||||
|
||||
$this->assertNotContains($asset->id, $this->mismatchedIds($result));
|
||||
}
|
||||
|
||||
public function test_null_company_item_at_null_company_location_is_never_flagged()
|
||||
{
|
||||
$location = Location::factory()->create(['company_id' => null]);
|
||||
$asset = $this->assetAt($location, ['company_id' => null]);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$result = Helper::test_locations_fmcs(true);
|
||||
|
||||
$this->assertNotContains($asset->id, $this->mismatchedIds($result));
|
||||
}
|
||||
|
||||
public function test_user_at_location_with_matching_company_is_not_flagged()
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$location = Location::factory()->for($company)->create();
|
||||
$user = User::factory()->create(['location_id' => $location->id]);
|
||||
$user->companies()->sync([$company->id]);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$result = Helper::test_locations_fmcs(true);
|
||||
|
||||
$this->assertNotContains($user->id, $this->mismatchedIds($result));
|
||||
}
|
||||
|
||||
public function test_user_at_location_with_different_company_is_flagged()
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
$location = Location::factory()->for($companyA)->create();
|
||||
$user = User::factory()->create(['location_id' => $location->id]);
|
||||
$user->companies()->sync([$companyB->id]);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$result = Helper::test_locations_fmcs(true);
|
||||
|
||||
$this->assertContains($user->id, $this->mismatchedIds($result));
|
||||
}
|
||||
|
||||
public function test_null_company_user_at_company_location_is_flagged_in_strict_mode()
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$location = Location::factory()->for($company)->create();
|
||||
$user = User::factory()->create(['company_id' => null, 'location_id' => $location->id]);
|
||||
$user->companies()->sync([]);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$result = Helper::test_locations_fmcs(true);
|
||||
|
||||
$this->assertContains($user->id, $this->mismatchedIds($result));
|
||||
}
|
||||
|
||||
public function test_null_company_user_at_company_location_is_not_flagged_in_floater_mode()
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$location = Location::factory()->for($company)->create();
|
||||
$user = User::factory()->create(['company_id' => null, 'location_id' => $location->id]);
|
||||
$user->companies()->sync([]);
|
||||
|
||||
$this->settings->enableFloaterMode();
|
||||
|
||||
$result = Helper::test_locations_fmcs(true);
|
||||
|
||||
$this->assertNotContains($user->id, $this->mismatchedIds($result));
|
||||
}
|
||||
|
||||
public function test_location_id_option_scopes_check_to_single_location()
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
$locationA = Location::factory()->for($companyA)->create();
|
||||
$locationB = Location::factory()->for($companyB)->create();
|
||||
$assetA = $this->assetAt($locationA, ['company_id' => $companyB->id]); // mismatch at A
|
||||
$assetB = $this->assetAt($locationB, ['company_id' => $companyA->id]); // mismatch at B
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$result = Helper::test_locations_fmcs(true, $locationA->id);
|
||||
|
||||
$this->assertContains($assetA->id, $this->mismatchedIds($result));
|
||||
$this->assertNotContains($assetB->id, $this->mismatchedIds($result));
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace Tests\Feature\Importing\Api;
|
||||
|
||||
use App\Models\Actionlog as ActionLog;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Company;
|
||||
use App\Models\CustomField;
|
||||
use App\Models\Import;
|
||||
use App\Models\User;
|
||||
@@ -641,4 +642,88 @@ class ImportAssetsTest extends ImportDataTestCase implements TestsPermissionsReq
|
||||
|
||||
$this->assertNotEquals($encryptedMacAddress, $macAddress);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function import_asset_checkout_is_blocked_when_fmcs_companies_differ(): void
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
$user = User::factory()->for($companyB)->create();
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$importFileBuilder = ImportFileBuilder::new([
|
||||
'companyName' => $companyA->name,
|
||||
'assigneeUsername' => $user->username,
|
||||
]);
|
||||
|
||||
$import = Import::factory()->asset()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create());
|
||||
$this->importFileResponse(['import' => $import->id])->assertOk();
|
||||
|
||||
$newAsset = Asset::where('serial', $importFileBuilder->firstRow()['serialNumber'])->sole();
|
||||
$this->assertNull($newAsset->assigned_to, 'Asset should not be checked out when item and user companies differ under FMCS');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function import_asset_checkout_is_allowed_when_fmcs_companies_match(): void
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$user = User::factory()->for($company)->create();
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$importFileBuilder = ImportFileBuilder::new([
|
||||
'companyName' => $company->name,
|
||||
'assigneeUsername' => $user->username,
|
||||
]);
|
||||
|
||||
$import = Import::factory()->asset()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create());
|
||||
$this->importFileResponse(['import' => $import->id])->assertOk();
|
||||
|
||||
$newAsset = Asset::where('serial', $importFileBuilder->firstRow()['serialNumber'])->sole();
|
||||
$this->assertEquals($user->id, $newAsset->assigned_to, 'Asset should be checked out when companies match under FMCS');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function import_asset_checkout_is_blocked_when_floater_disabled_and_user_has_no_company(): void
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$user = User::factory()->create(['company_id' => null]);
|
||||
$this->settings->enableMultipleFullCompanySupport()->disableFloaterMode();
|
||||
|
||||
$importFileBuilder = ImportFileBuilder::new([
|
||||
'companyName' => $company->name,
|
||||
'assigneeUsername' => $user->username,
|
||||
]);
|
||||
|
||||
$import = Import::factory()->asset()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create());
|
||||
$this->importFileResponse(['import' => $import->id])->assertOk();
|
||||
|
||||
$newAsset = Asset::where('serial', $importFileBuilder->firstRow()['serialNumber'])->sole();
|
||||
$this->assertNull($newAsset->assigned_to, 'Asset should not be checked out to a no-company user when floater mode is off');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function import_asset_checkout_is_allowed_when_floater_enabled_and_user_has_no_company(): void
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$user = User::factory()->create(['company_id' => null]);
|
||||
$this->settings->enableFloaterMode();
|
||||
|
||||
$importFileBuilder = ImportFileBuilder::new([
|
||||
'companyName' => $company->name,
|
||||
'assigneeUsername' => $user->username,
|
||||
]);
|
||||
|
||||
$import = Import::factory()->asset()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create());
|
||||
$this->importFileResponse(['import' => $import->id])->assertOk();
|
||||
|
||||
$newAsset = Asset::where('serial', $importFileBuilder->firstRow()['serialNumber'])->sole();
|
||||
$this->assertEquals($user->id, $newAsset->assigned_to, 'Asset should be checked out to a no-company user when floater mode is on');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
namespace Tests\Feature\Importing\Api;
|
||||
|
||||
use App\Models\Actionlog as ActionLog;
|
||||
use App\Models\Asset;
|
||||
use App\Models\Company;
|
||||
use App\Models\Component;
|
||||
use App\Models\Import;
|
||||
use App\Models\User;
|
||||
@@ -348,4 +350,88 @@ class ImportComponentsTest extends ImportDataTestCase implements TestsPermission
|
||||
$this->assertNull($newComponent->image);
|
||||
$this->assertNull($newComponent->notes);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function import_component_checkout_to_asset_is_blocked_when_fmcs_companies_differ(): void
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
$asset = Asset::factory()->for($companyB)->create();
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$importFileBuilder = ImportFileBuilder::new([
|
||||
'companyName' => $companyA->name,
|
||||
'assetTag' => $asset->asset_tag,
|
||||
]);
|
||||
|
||||
$import = Import::factory()->component()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create());
|
||||
$this->importFileResponse(['import' => $import->id])->assertOk();
|
||||
|
||||
$newComponent = Component::where('serial', $importFileBuilder->firstRow()['serialNumber'])->sole();
|
||||
$this->assertEquals(0, $newComponent->assets()->count(), 'Component should not be checked out when item and asset companies differ under FMCS');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function import_component_checkout_to_asset_is_allowed_when_fmcs_companies_match(): void
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$asset = Asset::factory()->for($company)->create();
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$importFileBuilder = ImportFileBuilder::new([
|
||||
'companyName' => $company->name,
|
||||
'assetTag' => $asset->asset_tag,
|
||||
]);
|
||||
|
||||
$import = Import::factory()->component()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create());
|
||||
$this->importFileResponse(['import' => $import->id])->assertOk();
|
||||
|
||||
$newComponent = Component::where('serial', $importFileBuilder->firstRow()['serialNumber'])->sole();
|
||||
$this->assertEquals(1, $newComponent->assets()->count(), 'Component should be checked out when companies match under FMCS');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function import_component_checkout_to_asset_is_blocked_when_floater_disabled_and_asset_has_no_company(): void
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$asset = Asset::factory()->create(['company_id' => null]);
|
||||
$this->settings->enableMultipleFullCompanySupport()->disableFloaterMode();
|
||||
|
||||
$importFileBuilder = ImportFileBuilder::new([
|
||||
'companyName' => $company->name,
|
||||
'assetTag' => $asset->asset_tag,
|
||||
]);
|
||||
|
||||
$import = Import::factory()->component()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create());
|
||||
$this->importFileResponse(['import' => $import->id])->assertOk();
|
||||
|
||||
$newComponent = Component::where('serial', $importFileBuilder->firstRow()['serialNumber'])->sole();
|
||||
$this->assertEquals(0, $newComponent->assets()->count(), 'Component should not be checked out to a no-company asset when floater mode is off');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function import_component_checkout_to_asset_is_allowed_when_floater_enabled_and_asset_has_no_company(): void
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$asset = Asset::factory()->create(['company_id' => null]);
|
||||
$this->settings->enableFloaterMode();
|
||||
|
||||
$importFileBuilder = ImportFileBuilder::new([
|
||||
'companyName' => $company->name,
|
||||
'assetTag' => $asset->asset_tag,
|
||||
]);
|
||||
|
||||
$import = Import::factory()->component()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create());
|
||||
$this->importFileResponse(['import' => $import->id])->assertOk();
|
||||
|
||||
$newComponent = Component::where('serial', $importFileBuilder->firstRow()['serialNumber'])->sole();
|
||||
$this->assertEquals(1, $newComponent->assets()->count(), 'Component should be checked out to a no-company asset when floater mode is on');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
namespace Tests\Feature\Importing\Api;
|
||||
|
||||
use App\Models\Actionlog as ActivityLog;
|
||||
use App\Models\Company;
|
||||
use App\Models\Import;
|
||||
use App\Models\License;
|
||||
use App\Models\LicenseSeat;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use Illuminate\Support\Str;
|
||||
@@ -399,4 +401,96 @@ class ImportLicenseTest extends ImportDataTestCase implements TestsPermissionsRe
|
||||
$this->assertNull($newLicense->deprecate);
|
||||
$this->assertNull($newLicense->min_amt);
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function import_license_checkout_is_blocked_when_fmcs_companies_differ(): void
|
||||
{
|
||||
[$companyA, $companyB] = Company::factory()->count(2)->create();
|
||||
$user = User::factory()->for($companyB)->create();
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$importFileBuilder = ImportFileBuilder::new([
|
||||
'companyName' => $companyA->name,
|
||||
'checkoutUsername' => $user->username,
|
||||
'seats' => 5,
|
||||
]);
|
||||
|
||||
$import = Import::factory()->license()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create());
|
||||
$this->importFileResponse(['import' => $import->id])->assertOk();
|
||||
|
||||
$license = License::where('serial', $importFileBuilder->firstRow()['serialNumber'])->sole();
|
||||
$checkedOutSeat = LicenseSeat::where('license_id', $license->id)->whereNotNull('assigned_to')->first();
|
||||
$this->assertNull($checkedOutSeat, 'License seat should not be checked out when item and user companies differ under FMCS');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function import_license_checkout_is_allowed_when_fmcs_companies_match(): void
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$user = User::factory()->for($company)->create();
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$importFileBuilder = ImportFileBuilder::new([
|
||||
'companyName' => $company->name,
|
||||
'checkoutUsername' => $user->username,
|
||||
'seats' => 5,
|
||||
]);
|
||||
|
||||
$import = Import::factory()->license()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create());
|
||||
$this->importFileResponse(['import' => $import->id])->assertOk();
|
||||
|
||||
$license = License::where('serial', $importFileBuilder->firstRow()['serialNumber'])->sole();
|
||||
$checkedOutSeat = LicenseSeat::where('license_id', $license->id)->where('assigned_to', $user->id)->first();
|
||||
$this->assertNotNull($checkedOutSeat, 'License seat should be checked out when companies match under FMCS');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function import_license_checkout_is_blocked_when_floater_disabled_and_user_has_no_company(): void
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$user = User::factory()->create(['company_id' => null]);
|
||||
$this->settings->enableMultipleFullCompanySupport()->disableFloaterMode();
|
||||
|
||||
$importFileBuilder = ImportFileBuilder::new([
|
||||
'companyName' => $company->name,
|
||||
'checkoutUsername' => $user->username,
|
||||
'seats' => 5,
|
||||
]);
|
||||
|
||||
$import = Import::factory()->license()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create());
|
||||
$this->importFileResponse(['import' => $import->id])->assertOk();
|
||||
|
||||
$license = License::where('serial', $importFileBuilder->firstRow()['serialNumber'])->sole();
|
||||
$checkedOutSeat = LicenseSeat::where('license_id', $license->id)->whereNotNull('assigned_to')->first();
|
||||
$this->assertNull($checkedOutSeat, 'License seat should not be checked out to a no-company user when floater mode is off');
|
||||
}
|
||||
|
||||
#[Test]
|
||||
public function import_license_checkout_is_allowed_when_floater_enabled_and_user_has_no_company(): void
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$user = User::factory()->create(['company_id' => null]);
|
||||
$this->settings->enableFloaterMode();
|
||||
|
||||
$importFileBuilder = ImportFileBuilder::new([
|
||||
'companyName' => $company->name,
|
||||
'checkoutUsername' => $user->username,
|
||||
'seats' => 5,
|
||||
]);
|
||||
|
||||
$import = Import::factory()->license()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create());
|
||||
$this->importFileResponse(['import' => $import->id])->assertOk();
|
||||
|
||||
$license = License::where('serial', $importFileBuilder->firstRow()['serialNumber'])->sole();
|
||||
$checkedOutSeat = LicenseSeat::where('license_id', $license->id)->where('assigned_to', $user->id)->first();
|
||||
$this->assertNotNull($checkedOutSeat, 'License seat should be checked out to a no-company user when floater mode is on');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Locations\Api;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\Location;
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Verifies that a location cannot be given a parent that belongs to a different
|
||||
* company when FMCS is enabled, and that the check is bypassed when FMCS is off.
|
||||
*
|
||||
* The API update case also covers the scenario where only parent_id changes
|
||||
* (company_id not included in the request), to ensure the check runs regardless.
|
||||
*/
|
||||
class LocationParentCompanyTest extends TestCase
|
||||
{
|
||||
// -----------------------------------------------------------------------
|
||||
// store (create)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
public function test_cannot_create_location_with_cross_company_parent_when_fmcs_enabled()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$acme = Company::factory()->create(['name' => 'Acme']);
|
||||
$globex = Company::factory()->create(['name' => 'Globex']);
|
||||
|
||||
$parentLocation = Location::factory()->create(['company_id' => $acme->id]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.locations.store'), [
|
||||
'name' => 'Location B',
|
||||
'company_id' => $globex->id,
|
||||
'parent_id' => $parentLocation->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('error');
|
||||
|
||||
$this->assertFalse(Location::where('name', 'Location B')->exists());
|
||||
}
|
||||
|
||||
public function test_can_create_location_with_same_company_parent_when_fmcs_enabled()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$acme = Company::factory()->create(['name' => 'Acme']);
|
||||
|
||||
$parentLocation = Location::factory()->create(['company_id' => $acme->id]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.locations.store'), [
|
||||
'name' => 'Location B',
|
||||
'company_id' => $acme->id,
|
||||
'parent_id' => $parentLocation->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success');
|
||||
|
||||
$this->assertTrue(Location::where('name', 'Location B')->exists());
|
||||
}
|
||||
|
||||
public function test_can_create_location_with_cross_company_parent_when_fmcs_disabled()
|
||||
{
|
||||
$this->settings->disableMultipleFullCompanySupport();
|
||||
|
||||
$acme = Company::factory()->create(['name' => 'Acme']);
|
||||
$globex = Company::factory()->create(['name' => 'Globex']);
|
||||
|
||||
$parentLocation = Location::factory()->create(['company_id' => $acme->id]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->postJson(route('api.locations.store'), [
|
||||
'name' => 'Location B',
|
||||
'company_id' => $globex->id,
|
||||
'parent_id' => $parentLocation->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success');
|
||||
|
||||
$this->assertTrue(Location::where('name', 'Location B')->exists());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// update
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
public function test_cannot_update_location_to_cross_company_parent_when_fmcs_enabled()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$acme = Company::factory()->create(['name' => 'Acme']);
|
||||
$globex = Company::factory()->create(['name' => 'Globex']);
|
||||
|
||||
$parentLocation = Location::factory()->create(['company_id' => $acme->id]);
|
||||
$location = Location::factory()->create(['name' => 'Location B', 'company_id' => $globex->id]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->patchJson(route('api.locations.update', $location), [
|
||||
'name' => 'Location B',
|
||||
'company_id' => $globex->id,
|
||||
'parent_id' => $parentLocation->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('error');
|
||||
|
||||
$this->assertNull($location->fresh()->parent_id);
|
||||
}
|
||||
|
||||
public function test_cannot_update_location_parent_id_only_to_cross_company_parent_when_fmcs_enabled()
|
||||
{
|
||||
// Ensures the check fires even when company_id is not included in the request.
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$acme = Company::factory()->create(['name' => 'Acme']);
|
||||
$globex = Company::factory()->create(['name' => 'Globex']);
|
||||
|
||||
$parentLocation = Location::factory()->create(['company_id' => $acme->id]);
|
||||
$location = Location::factory()->create(['name' => 'Location B', 'company_id' => $globex->id]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->patchJson(route('api.locations.update', $location), [
|
||||
'parent_id' => $parentLocation->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('error');
|
||||
|
||||
$this->assertNull($location->fresh()->parent_id);
|
||||
}
|
||||
|
||||
public function test_can_update_location_to_same_company_parent_when_fmcs_enabled()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$acme = Company::factory()->create(['name' => 'Acme']);
|
||||
|
||||
$parentLocation = Location::factory()->create(['company_id' => $acme->id]);
|
||||
$location = Location::factory()->create(['name' => 'Location B', 'company_id' => $acme->id]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->patchJson(route('api.locations.update', $location), [
|
||||
'name' => 'Location B',
|
||||
'company_id' => $acme->id,
|
||||
'parent_id' => $parentLocation->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success');
|
||||
|
||||
$this->assertEquals($parentLocation->id, $location->fresh()->parent_id);
|
||||
}
|
||||
|
||||
public function test_can_update_location_to_cross_company_parent_when_fmcs_disabled()
|
||||
{
|
||||
$this->settings->disableMultipleFullCompanySupport();
|
||||
|
||||
$acme = Company::factory()->create(['name' => 'Acme']);
|
||||
$globex = Company::factory()->create(['name' => 'Globex']);
|
||||
|
||||
$parentLocation = Location::factory()->create(['company_id' => $acme->id]);
|
||||
$location = Location::factory()->create(['name' => 'Location B', 'company_id' => $globex->id]);
|
||||
|
||||
$this->actingAsForApi(User::factory()->superuser()->create())
|
||||
->patchJson(route('api.locations.update', $location), [
|
||||
'name' => 'Location B',
|
||||
'company_id' => $globex->id,
|
||||
'parent_id' => $parentLocation->id,
|
||||
])
|
||||
->assertOk()
|
||||
->assertStatusMessageIs('success');
|
||||
|
||||
$this->assertEquals($parentLocation->id, $location->fresh()->parent_id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Locations\Ui;
|
||||
|
||||
use App\Models\Company;
|
||||
use App\Models\Location;
|
||||
use App\Models\User;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Verifies that a location cannot be given a parent that belongs to a different
|
||||
* company when FMCS is enabled, and that the check is bypassed when FMCS is off.
|
||||
*/
|
||||
class LocationParentCompanyTest extends TestCase
|
||||
{
|
||||
// -----------------------------------------------------------------------
|
||||
// store (create)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
public function test_cannot_create_location_with_cross_company_parent_when_fmcs_enabled()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$acme = Company::factory()->create(['name' => 'Acme']);
|
||||
$globex = Company::factory()->create(['name' => 'Globex']);
|
||||
|
||||
$parentLocation = Location::factory()->create(['company_id' => $acme->id]);
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->from(route('locations.create'))
|
||||
->post(route('locations.store'), [
|
||||
'name' => 'Location B',
|
||||
'company_id' => $globex->id,
|
||||
'parent_id' => $parentLocation->id,
|
||||
])
|
||||
->assertRedirect(route('locations.create'))
|
||||
->assertSessionHas('error');
|
||||
|
||||
$this->assertFalse(Location::where('name', 'Location B')->exists());
|
||||
}
|
||||
|
||||
public function test_can_create_location_with_same_company_parent_when_fmcs_enabled()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$acme = Company::factory()->create(['name' => 'Acme']);
|
||||
|
||||
$parentLocation = Location::factory()->create(['company_id' => $acme->id]);
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('locations.store'), [
|
||||
'name' => 'Location B',
|
||||
'company_id' => $acme->id,
|
||||
'parent_id' => $parentLocation->id,
|
||||
])
|
||||
->assertRedirect(route('locations.index'))
|
||||
->assertSessionHasNoErrors();
|
||||
|
||||
$this->assertTrue(Location::where('name', 'Location B')->exists());
|
||||
}
|
||||
|
||||
public function test_can_create_location_with_cross_company_parent_when_fmcs_disabled()
|
||||
{
|
||||
$this->settings->disableMultipleFullCompanySupport();
|
||||
|
||||
$acme = Company::factory()->create(['name' => 'Acme']);
|
||||
$globex = Company::factory()->create(['name' => 'Globex']);
|
||||
|
||||
$parentLocation = Location::factory()->create(['company_id' => $acme->id]);
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->post(route('locations.store'), [
|
||||
'name' => 'Location B',
|
||||
'company_id' => $globex->id,
|
||||
'parent_id' => $parentLocation->id,
|
||||
])
|
||||
->assertRedirect(route('locations.index'))
|
||||
->assertSessionHasNoErrors();
|
||||
|
||||
$this->assertTrue(Location::where('name', 'Location B')->exists());
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// update (edit)
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
public function test_cannot_update_location_to_cross_company_parent_when_fmcs_enabled()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$acme = Company::factory()->create(['name' => 'Acme']);
|
||||
$globex = Company::factory()->create(['name' => 'Globex']);
|
||||
|
||||
$parentLocation = Location::factory()->create(['company_id' => $acme->id]);
|
||||
$location = Location::factory()->create(['name' => 'Location B', 'company_id' => $globex->id]);
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->from(route('locations.edit', $location))
|
||||
->put(route('locations.update', $location), [
|
||||
'name' => 'Location B',
|
||||
'company_id' => $globex->id,
|
||||
'parent_id' => $parentLocation->id,
|
||||
])
|
||||
->assertRedirect(route('locations.edit', $location))
|
||||
->assertSessionHas('error');
|
||||
|
||||
$this->assertNull($location->fresh()->parent_id);
|
||||
}
|
||||
|
||||
public function test_can_update_location_to_same_company_parent_when_fmcs_enabled()
|
||||
{
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$acme = Company::factory()->create(['name' => 'Acme']);
|
||||
|
||||
$parentLocation = Location::factory()->create(['company_id' => $acme->id]);
|
||||
$location = Location::factory()->create(['name' => 'Location B', 'company_id' => $acme->id]);
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->put(route('locations.update', $location), [
|
||||
'name' => 'Location B',
|
||||
'company_id' => $acme->id,
|
||||
'parent_id' => $parentLocation->id,
|
||||
])
|
||||
->assertRedirect(route('locations.index'))
|
||||
->assertSessionHasNoErrors();
|
||||
|
||||
$this->assertEquals($parentLocation->id, $location->fresh()->parent_id);
|
||||
}
|
||||
|
||||
public function test_can_update_location_to_cross_company_parent_when_fmcs_disabled()
|
||||
{
|
||||
$this->settings->disableMultipleFullCompanySupport();
|
||||
|
||||
$acme = Company::factory()->create(['name' => 'Acme']);
|
||||
$globex = Company::factory()->create(['name' => 'Globex']);
|
||||
|
||||
$parentLocation = Location::factory()->create(['company_id' => $acme->id]);
|
||||
$location = Location::factory()->create(['name' => 'Location B', 'company_id' => $globex->id]);
|
||||
|
||||
$this->actingAs(User::factory()->superuser()->create())
|
||||
->put(route('locations.update', $location), [
|
||||
'name' => 'Location B',
|
||||
'company_id' => $globex->id,
|
||||
'parent_id' => $parentLocation->id,
|
||||
])
|
||||
->assertRedirect(route('locations.index'))
|
||||
->assertSessionHasNoErrors();
|
||||
|
||||
$this->assertEquals($parentLocation->id, $location->fresh()->parent_id);
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ class ComponentsImportFileBuilder extends FileBuilder
|
||||
protected function getDictionary(): array
|
||||
{
|
||||
return [
|
||||
'assetTag' => 'Asset Tag',
|
||||
'category' => 'Category',
|
||||
'companyName' => 'Company',
|
||||
'itemName' => 'item Name',
|
||||
@@ -51,6 +52,7 @@ class ComponentsImportFileBuilder extends FileBuilder
|
||||
$faker = fake();
|
||||
|
||||
return [
|
||||
'assetTag' => '',
|
||||
'category' => Str::random(),
|
||||
'companyName' => Str::random()." {$faker->companySuffix}",
|
||||
'itemName' => Str::random(),
|
||||
|
||||
@@ -39,6 +39,9 @@ class LicensesImportFileBuilder extends FileBuilder
|
||||
{
|
||||
return [
|
||||
'category' => 'Category',
|
||||
'checkoutEmail' => 'Email',
|
||||
'checkoutFullName' => 'Full Name',
|
||||
'checkoutUsername' => 'Username',
|
||||
'companyName' => 'Company',
|
||||
'expirationDate' => 'expiration date',
|
||||
'isMaintained' => 'maintained',
|
||||
@@ -66,6 +69,9 @@ class LicensesImportFileBuilder extends FileBuilder
|
||||
|
||||
return [
|
||||
'category' => Str::random(),
|
||||
'checkoutEmail' => '',
|
||||
'checkoutFullName' => '',
|
||||
'checkoutUsername' => '',
|
||||
'companyName' => Str::random()." {$faker->companySuffix}",
|
||||
'expirationDate' => $faker->date,
|
||||
'isMaintained' => $faker->randomElement(['TRUE', 'FALSE']),
|
||||
|
||||
@@ -102,6 +102,19 @@ class Settings
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function enableFloaterMode(): Settings
|
||||
{
|
||||
return $this->update([
|
||||
'full_multiple_companies_support' => 1,
|
||||
'null_company_is_floater' => 1,
|
||||
]);
|
||||
}
|
||||
|
||||
public function disableFloaterMode(): Settings
|
||||
{
|
||||
return $this->update(['null_company_is_floater' => 0]);
|
||||
}
|
||||
|
||||
public function enableSlackWebhook(): Settings
|
||||
{
|
||||
return $this->update([
|
||||
|
||||
@@ -149,6 +149,66 @@ class CompanyScopingTest extends TestCase
|
||||
$this->assertCanSee($licenseSeatB);
|
||||
}
|
||||
|
||||
#[DataProvider('models')]
|
||||
public function test_company_user_cannot_see_null_company_items_in_strict_mode($model)
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$nullCompanyItem = $model::factory()->create(['company_id' => null]);
|
||||
$companyItem = $model::factory()->for($company)->create();
|
||||
$companyUser = $company->users()->save(User::factory()->make());
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAs($companyUser);
|
||||
$this->assertCannotSee($nullCompanyItem);
|
||||
$this->assertCanSee($companyItem);
|
||||
}
|
||||
|
||||
#[DataProvider('models')]
|
||||
public function test_company_user_can_see_null_company_items_in_floater_mode($model)
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$nullCompanyItem = $model::factory()->create(['company_id' => null]);
|
||||
$companyItem = $model::factory()->for($company)->create();
|
||||
$companyUser = $company->users()->save(User::factory()->make());
|
||||
|
||||
$this->settings->enableFloaterMode();
|
||||
|
||||
$this->actingAs($companyUser);
|
||||
$this->assertCanSee($nullCompanyItem);
|
||||
$this->assertCanSee($companyItem);
|
||||
}
|
||||
|
||||
#[DataProvider('models')]
|
||||
public function test_null_company_user_cannot_see_company_items_in_strict_mode($model)
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$nullCompanyItem = $model::factory()->create(['company_id' => null]);
|
||||
$companyItem = $model::factory()->for($company)->create();
|
||||
$nullCompanyUser = User::factory()->create(['company_id' => null]);
|
||||
|
||||
$this->settings->enableMultipleFullCompanySupport();
|
||||
|
||||
$this->actingAs($nullCompanyUser);
|
||||
$this->assertCanSee($nullCompanyItem);
|
||||
$this->assertCannotSee($companyItem);
|
||||
}
|
||||
|
||||
#[DataProvider('models')]
|
||||
public function test_null_company_user_can_see_all_items_in_floater_mode($model)
|
||||
{
|
||||
$company = Company::factory()->create();
|
||||
$nullCompanyItem = $model::factory()->create(['company_id' => null]);
|
||||
$companyItem = $model::factory()->for($company)->create();
|
||||
$nullCompanyUser = User::factory()->create(['company_id' => null]);
|
||||
|
||||
$this->settings->enableFloaterMode();
|
||||
|
||||
$this->actingAs($nullCompanyUser);
|
||||
$this->assertCanSee($nullCompanyItem);
|
||||
$this->assertCanSee($companyItem);
|
||||
}
|
||||
|
||||
private function assertCanSee(Model $model)
|
||||
{
|
||||
$this->assertTrue(
|
||||
|
||||
Reference in New Issue
Block a user