221 lines
8.2 KiB
PHP
Executable File
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.
|
|
*/
|
|
}
|