152 lines
5.4 KiB
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);
|
|
}
|
|
}
|