Files
GSB-Construction/Modules/MaterialLogistics/tests/Feature/MaterialRequisitionApprovalFlowTest.php

152 lines
5.4 KiB
PHP

<?php
namespace Modules\MaterialLogistics\Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Modules\ApprovalWorkflow\Models\ApprovalChain;
use Modules\MasterData\Models\Material;
use Modules\MaterialLogistics\Models\MaterialRequisition;
use Modules\MaterialLogistics\Models\MaterialRequisitionItem;
use Modules\ProjectManagement\Models\Project;
use Spatie\Permission\Models\Role;
use Tests\TestCase;
class MaterialRequisitionApprovalFlowTest extends TestCase
{
use RefreshDatabase;
private User $admin;
private Project $project;
private Material $material;
protected function setUp(): void
{
parent::setUp();
Role::firstOrCreate(['name' => 'Super Admin', 'guard_name' => 'web']);
Role::firstOrCreate(['name' => 'admin', 'guard_name' => 'web']);
Role::firstOrCreate(['name' => 'Project Manager', 'guard_name' => 'web']);
$this->admin = User::factory()->create(['user_type' => 'admin', 'status' => 'active']);
$this->admin->assignRole('Super Admin');
$this->project = Project::factory()->create(['status' => 'in_progress']);
$this->material = Material::factory()->create(['unit_cost' => 500.00]);
}
public function test_admin_can_approve_material_requisition_via_modal_action(): void
{
$requisition = MaterialRequisition::create([
'project_id' => $this->project->id,
'document_number' => 'MR-2026-0001',
'requisition_type' => 'project',
'status' => 'draft',
'requested_by' => $this->admin->id,
]);
MaterialRequisitionItem::create([
'material_requisition_id' => $requisition->id,
'material_id' => $this->material->id,
'quantity' => 10,
'unit_cost' => 500.00,
]);
// 1. Submit for approval
$this->actingAs($this->admin)->patch(route('requisitions.submit', $requisition->ulid));
$requisition->refresh();
$this->assertEquals('submitted', $requisition->status);
$chain = ApprovalChain::where('approvable_type', MaterialRequisition::class)
->where('approvable_id', $requisition->id)
->firstOrFail();
// 2. Approve via modal
$response = $this->actingAs($this->admin)->patch(route('approvals.approve', $chain->ulid), [
'notes' => 'Approved for immediate purchasing',
]);
$response->assertSessionHas('success');
$requisition->refresh();
$this->assertEquals('approved', $requisition->status);
$this->assertEquals($this->admin->id, $requisition->approved_by);
$this->assertNotNull($requisition->approved_at);
}
public function test_admin_can_reject_material_requisition_via_modal_action(): void
{
$requisition = MaterialRequisition::create([
'project_id' => $this->project->id,
'document_number' => 'MR-2026-0002',
'requisition_type' => 'project',
'status' => 'draft',
'requested_by' => $this->admin->id,
]);
MaterialRequisitionItem::create([
'material_requisition_id' => $requisition->id,
'material_id' => $this->material->id,
'quantity' => 5,
'unit_cost' => 500.00,
]);
// 1. Submit for approval
$this->actingAs($this->admin)->patch(route('requisitions.submit', $requisition->ulid));
$requisition->refresh();
$chain = ApprovalChain::where('approvable_type', MaterialRequisition::class)
->where('approvable_id', $requisition->id)
->firstOrFail();
// 2. Reject via modal
$response = $this->actingAs($this->admin)->patch(route('approvals.reject', $chain->ulid), [
'notes' => 'Rejected due to budget constraints',
]);
$response->assertSessionHas('success');
$requisition->refresh();
$this->assertEquals('rejected', $requisition->status);
}
public function test_admin_can_approve_material_requisition_via_direct_fallback_route(): void
{
$requisition = MaterialRequisition::create([
'project_id' => $this->project->id,
'document_number' => 'MR-2026-0003',
'requisition_type' => 'project',
'status' => 'submitted',
'requested_by' => $this->admin->id,
]);
$response = $this->actingAs($this->admin)->patch(route('requisitions.approve', $requisition->ulid), [
'notes' => 'Direct approval without chain',
]);
$response->assertSessionHas('success');
$requisition->refresh();
$this->assertEquals('approved', $requisition->status);
$this->assertEquals($this->admin->id, $requisition->approved_by);
}
public function test_admin_can_reject_material_requisition_via_direct_fallback_route(): void
{
$requisition = MaterialRequisition::create([
'project_id' => $this->project->id,
'document_number' => 'MR-2026-0004',
'requisition_type' => 'project',
'status' => 'submitted',
'requested_by' => $this->admin->id,
]);
$response = $this->actingAs($this->admin)->patch(route('requisitions.reject', $requisition->ulid), [
'notes' => 'Direct rejection reason note',
]);
$response->assertSessionHas('success');
$requisition->refresh();
$this->assertEquals('rejected', $requisition->status);
}
}