Files
WMS/tests/Feature/Warehouse/WarehouseCrudTest.php
2026-09-21 10:14:57 +01:00

221 lines
8.2 KiB
PHP
Executable File

<?php
namespace Tests\Feature\Warehouse;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Modules\Company\Models\Company;
use Modules\Platform\app\Models\LicenseKey;
use Modules\Warehouse\app\Models\Warehouse;
use Modules\Warehouse\app\Models\WarehouseValidationRule;
use Tests\TestCase;
class WarehouseCrudTest extends TestCase
{
use RefreshDatabase;
/**
* Ensure licensed tenant users can see the warehouse dashboard for their company.
*/
public function test_licensed_user_can_view_warehouse_dashboard(): void
{
$user = User::factory()->create();
Warehouse::create(['company_id' => $user->company_id, 'code' => 'MAIN', 'name' => 'Main Warehouse']);
$this->actingAs($user)
->get(route('warehouses.index'))
->assertOk()
->assertSee('Warehouses', false)
->assertSee('Main Warehouse', false);
}
/**
* Ensure unlicensed tenants are blocked from licensed warehouse screens.
*/
public function test_unlicensed_tenant_is_blocked_from_warehouse_dashboard(): void
{
$company = Company::create(['name' => 'Unlicensed Ltd', 'slug' => 'unlicensed-ltd']);
$user = User::factory()->create(['company_id' => $company->id]);
$this->actingAs($user)
->get(route('dashboard'))
->assertStatus(402);
}
/**
* Ensure users without a company are forbidden by tenant assignment middleware.
*/
public function test_user_without_company_is_forbidden_from_warehouse_dashboard(): void
{
$user = User::factory()->create(['company_id' => null]);
$this->actingAs($user)
->get(route('dashboard'))
->assertForbidden();
}
/**
* Ensure tenant users only see their own warehouses.
*/
public function test_warehouse_index_is_tenant_isolated(): void
{
$companyA = Company::create(['name' => 'Company A', 'slug' => 'company-a']);
$companyB = Company::create(['name' => 'Company B', 'slug' => 'company-b']);
LicenseKey::issueFor($companyA, 'A licence');
$user = User::factory()->create(['company_id' => $companyA->id]);
Warehouse::create(['company_id' => $companyA->id, 'code' => 'A1', 'name' => 'A Warehouse']);
Warehouse::create(['company_id' => $companyB->id, 'code' => 'B1', 'name' => 'B Warehouse']);
$this->actingAs($user)
->get(route('warehouses.index'))
->assertOk()
->assertSee('A Warehouse', false)
->assertDontSee('B Warehouse', false);
}
/**
* Ensure warehouse creation uses the authenticated tenant company and timezone.
*/
public function test_licensed_user_can_create_warehouse_for_their_company(): void
{
$user = User::factory()->create();
$this->actingAs($user)->withSession(['_token' => 'test-token'])->post(route('warehouses.store'), $this->csrfPayload([
'code' => 'EAST',
'name' => 'East Midlands DC',
'address' => 'Main Road, Nottingham',
]))->assertRedirect();
$this->assertDatabaseHas('warehouses', [
'company_id' => $user->company_id,
'code' => 'EAST',
'name' => 'East Midlands DC',
'status' => 'active',
'timezone' => 'Europe/London',
]);
}
/**
* Ensure warehouse input validation protects required fields.
*/
public function test_create_warehouse_validates_input(): void
{
$user = User::factory()->create();
$this->actingAs($user)
->from(route('warehouses.index'))
->withSession(['_token' => 'test-token'])
->post(route('warehouses.store'), $this->csrfPayload([
'code' => '',
'name' => '',
]))
->assertRedirect(route('warehouses.index'))
->assertSessionHasErrors(['code', 'name']);
}
/**
* Ensure rules index only lists rules attached to the authenticated company.
*/
public function test_validation_rules_index_is_tenant_isolated(): void
{
$companyA = Company::create(['name' => 'Rules A', 'slug' => 'rules-a']);
$companyB = Company::create(['name' => 'Rules B', 'slug' => 'rules-b']);
LicenseKey::issueFor($companyA, 'Rules licence');
$user = User::factory()->create(['company_id' => $companyA->id]);
$warehouseA = Warehouse::create(['company_id' => $companyA->id, 'code' => 'RA', 'name' => 'Rules A Warehouse']);
$warehouseB = Warehouse::create(['company_id' => $companyB->id, 'code' => 'RB', 'name' => 'Rules B Warehouse']);
WarehouseValidationRule::create(['warehouse_id' => $warehouseA->id, 'name' => 'A Rule', 'rule_key' => 'a-rule', 'severity' => 'warning']);
WarehouseValidationRule::create(['warehouse_id' => $warehouseB->id, 'name' => 'B Rule', 'rule_key' => 'b-rule', 'severity' => 'blocker']);
$this->actingAs($user)
->get(route('warehouse-rules.index'))
->assertOk()
->assertSee('A Rule', false)
->assertDontSee('B Rule', false);
}
/**
* Ensure users can create validation rules for their own warehouses.
*/
public function test_user_can_create_validation_rule_for_own_warehouse(): void
{
$user = User::factory()->create();
$warehouse = Warehouse::create(['company_id' => $user->company_id, 'code' => 'MAIN', 'name' => 'Main Warehouse']);
$this->actingAs($user)->withSession(['_token' => 'test-token'])->post(route('warehouse-rules.store'), $this->csrfPayload([
'warehouse_id' => $warehouse->id,
'name' => 'Require batch number',
'rule_key' => 'batch-required',
'severity' => 'blocker',
'configuration' => json_encode(['field' => 'batch_no']),
]))->assertRedirect();
$this->assertDatabaseHas('warehouse_validation_rules', [
'warehouse_id' => $warehouse->id,
'name' => 'Require batch number',
'rule_key' => 'batch-required',
'severity' => 'blocker',
'is_active' => true,
]);
$this->assertSame(['field' => 'batch_no'], WarehouseValidationRule::firstOrFail()->configuration);
}
/**
* Ensure users cannot create rules against another tenant warehouse.
*/
public function test_user_cannot_create_validation_rule_for_another_company_warehouse(): void
{
$user = User::factory()->create();
$otherCompany = Company::create(['name' => 'Other Company', 'slug' => 'other-company']);
$otherWarehouse = Warehouse::create(['company_id' => $otherCompany->id, 'code' => 'OTHER', 'name' => 'Other Warehouse']);
$this->actingAs($user)->withSession(['_token' => 'test-token'])->post(route('warehouse-rules.store'), $this->csrfPayload([
'warehouse_id' => $otherWarehouse->id,
'name' => 'Invalid Rule',
'rule_key' => 'invalid-rule',
'severity' => 'error',
'configuration' => '{}',
]))->assertNotFound();
}
/**
* Ensure rule creation validates JSON and severity choices.
*/
public function test_create_validation_rule_validates_input(): void
{
$user = User::factory()->create();
$this->actingAs($user)
->from(route('warehouse-rules.index'))
->withSession(['_token' => 'test-token'])
->post(route('warehouse-rules.store'), $this->csrfPayload([
'warehouse_id' => '',
'name' => '',
'rule_key' => '',
'severity' => 'critical',
'configuration' => '{bad json',
]))
->assertRedirect(route('warehouse-rules.index'))
->assertSessionHasErrors(['warehouse_id', 'name', 'rule_key', 'severity', 'configuration']);
}
/**
* Return payload with a valid test CSRF token.
*
* @param array<string, mixed> $payload
*
* @return array<string, mixed>
*/
private function csrfPayload(array $payload = []): array
{
return ['_token' => 'test-token'] + $payload;
}
/**
* Seed the test session with the matching CSRF token.
*/
}