SparePartInventoryControllerTest.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. <?php
  2. namespace Tests\Feature;
  3. use App\Models\Reclamation;
  4. use App\Models\Role;
  5. use App\Models\Shortage;
  6. use App\Models\SparePart;
  7. use App\Models\User;
  8. use Illuminate\Foundation\Testing\RefreshDatabase;
  9. use Tests\TestCase;
  10. class SparePartInventoryControllerTest extends TestCase
  11. {
  12. use RefreshDatabase;
  13. protected $seed = true;
  14. private User $adminUser;
  15. private User $managerUser;
  16. private User $brigadierUser;
  17. protected function setUp(): void
  18. {
  19. parent::setUp();
  20. $this->adminUser = User::factory()->create(['role' => Role::ADMIN]);
  21. $this->managerUser = User::factory()->create(['role' => Role::MANAGER]);
  22. $this->brigadierUser = User::factory()->create(['role' => Role::BRIGADIER]);
  23. }
  24. // ==================== Authentication ====================
  25. public function test_guest_cannot_access_inventory(): void
  26. {
  27. $response = $this->get(route('spare_part_inventory.index'));
  28. $response->assertRedirect(route('login'));
  29. }
  30. // ==================== Authorization ====================
  31. public function test_brigadier_cannot_access_inventory(): void
  32. {
  33. $response = $this->actingAs($this->brigadierUser)
  34. ->get(route('spare_part_inventory.index'));
  35. $response->assertStatus(403);
  36. }
  37. // ==================== Index ====================
  38. public function test_admin_can_access_inventory_index(): void
  39. {
  40. $response = $this->actingAs($this->adminUser)
  41. ->get(route('spare_part_inventory.index'));
  42. $response->assertStatus(200);
  43. $response->assertViewIs('spare_parts.index');
  44. }
  45. public function test_manager_can_access_inventory_index(): void
  46. {
  47. $response = $this->actingAs($this->managerUser)
  48. ->get(route('spare_part_inventory.index'));
  49. $response->assertStatus(200);
  50. $response->assertViewIs('spare_parts.index');
  51. }
  52. public function test_inventory_view_has_required_data(): void
  53. {
  54. $response = $this->actingAs($this->adminUser)
  55. ->get(route('spare_part_inventory.index'));
  56. $response->assertStatus(200);
  57. $response->assertViewHas('critical_shortages');
  58. $response->assertViewHas('below_min_stock');
  59. $response->assertViewHas('open_shortages');
  60. $response->assertViewHas('tab');
  61. }
  62. public function test_inventory_shows_open_shortages(): void
  63. {
  64. $sparePart = SparePart::factory()->create([
  65. 'min_stock' => 5,
  66. ]);
  67. $reclamation = Reclamation::factory()->create();
  68. $shortage = Shortage::factory()->create([
  69. 'spare_part_id' => $sparePart->id,
  70. 'reclamation_id' => $reclamation->id,
  71. 'status' => Shortage::STATUS_OPEN,
  72. 'required_qty' => 3,
  73. 'reserved_qty' => 0,
  74. 'missing_qty' => 3,
  75. ]);
  76. $response = $this->actingAs($this->adminUser)
  77. ->get(route('spare_part_inventory.index'));
  78. $response->assertStatus(200);
  79. $openShortages = $response->viewData('open_shortages');
  80. $this->assertTrue($openShortages->contains('id', $shortage->id));
  81. }
  82. public function test_inventory_does_not_show_closed_shortages(): void
  83. {
  84. $sparePart = SparePart::factory()->create();
  85. $reclamation = Reclamation::factory()->create();
  86. $closedShortage = Shortage::factory()->create([
  87. 'spare_part_id' => $sparePart->id,
  88. 'reclamation_id' => $reclamation->id,
  89. 'status' => Shortage::STATUS_CLOSED,
  90. 'required_qty' => 2,
  91. 'reserved_qty' => 2,
  92. 'missing_qty' => 0,
  93. ]);
  94. $response = $this->actingAs($this->adminUser)
  95. ->get(route('spare_part_inventory.index'));
  96. $response->assertStatus(200);
  97. $openShortages = $response->viewData('open_shortages');
  98. $this->assertFalse($openShortages->contains('id', $closedShortage->id));
  99. }
  100. public function test_inventory_shows_below_min_stock_parts(): void
  101. {
  102. // SparePart без SparePartOrders в STATUS_IN_STOCK => total_free_stock = 0
  103. // При min_stock > 0 isBelowMinStock() вернёт true
  104. $belowMinSparePart = SparePart::factory()->create([
  105. 'min_stock' => 10,
  106. ]);
  107. $response = $this->actingAs($this->adminUser)
  108. ->get(route('spare_part_inventory.index'));
  109. $response->assertStatus(200);
  110. $belowMinStock = $response->viewData('below_min_stock');
  111. $this->assertTrue($belowMinStock->contains('id', $belowMinSparePart->id));
  112. }
  113. public function test_inventory_tab_is_set_correctly(): void
  114. {
  115. $response = $this->actingAs($this->adminUser)
  116. ->get(route('spare_part_inventory.index'));
  117. $response->assertStatus(200);
  118. $response->assertViewHas('tab', 'inventory');
  119. }
  120. }