adminUser = User::factory()->create(['role' => Role::ADMIN]); $this->managerUser = User::factory()->create(['role' => Role::MANAGER]); } // ==================== Authentication ==================== public function test_guest_cannot_access_spare_part_orders_index(): void { $response = $this->get(route('spare_part_orders.index')); $response->assertRedirect(route('login')); } public function test_guest_cannot_access_spare_part_order_create(): void { $response = $this->get(route('spare_part_orders.create')); $response->assertRedirect(route('login')); } public function test_guest_cannot_store_spare_part_order(): void { $response = $this->post(route('spare_part_orders.store'), []); $response->assertRedirect(route('login')); } // ==================== Index ==================== public function test_admin_can_access_spare_part_orders_index(): void { $response = $this->actingAs($this->adminUser) ->get(route('spare_part_orders.index')); $response->assertStatus(200); $response->assertViewIs('spare_parts.index'); } public function test_manager_can_access_spare_part_orders_index(): void { $response = $this->actingAs($this->managerUser) ->get(route('spare_part_orders.index')); $response->assertStatus(200); $response->assertViewIs('spare_parts.index'); } // ==================== Show ==================== public function test_admin_can_view_spare_part_order(): void { $sparePartOrder = SparePartOrder::factory()->create(); $response = $this->actingAs($this->adminUser) ->get(route('spare_part_orders.show', $sparePartOrder)); $response->assertStatus(200); $response->assertViewIs('spare_part_orders.edit'); } public function test_manager_can_view_spare_part_order(): void { $sparePartOrder = SparePartOrder::factory()->create(); $response = $this->actingAs($this->managerUser) ->get(route('spare_part_orders.show', $sparePartOrder)); $response->assertStatus(200); $response->assertViewIs('spare_part_orders.edit'); } public function test_guest_cannot_view_spare_part_order(): void { $sparePartOrder = SparePartOrder::factory()->create(); $response = $this->get(route('spare_part_orders.show', $sparePartOrder)); $response->assertRedirect(route('login')); } // ==================== Create ==================== public function test_admin_can_access_create_form(): void { $response = $this->actingAs($this->adminUser) ->get(route('spare_part_orders.create')); $response->assertStatus(200); $response->assertViewIs('spare_part_orders.edit'); } public function test_manager_can_access_create_form(): void { $response = $this->actingAs($this->managerUser) ->get(route('spare_part_orders.create')); $response->assertStatus(200); $response->assertViewIs('spare_part_orders.edit'); } // ==================== Store ==================== public function test_admin_can_create_spare_part_order(): void { $sparePart = SparePart::factory()->create(); $response = $this->actingAs($this->adminUser) ->post(route('spare_part_orders.store'), [ 'spare_part_id' => $sparePart->id, 'status' => SparePartOrder::STATUS_ORDERED, 'ordered_quantity' => 10, 'source_text' => 'Test Supplier', ]); $response->assertRedirect(); $response->assertSessionHas('success'); $this->assertDatabaseHas('spare_part_orders', [ 'spare_part_id' => $sparePart->id, 'status' => SparePartOrder::STATUS_ORDERED, 'ordered_quantity' => 10, ]); } public function test_manager_can_create_spare_part_order(): void { $sparePart = SparePart::factory()->create(); $response = $this->actingAs($this->managerUser) ->post(route('spare_part_orders.store'), [ 'spare_part_id' => $sparePart->id, 'status' => SparePartOrder::STATUS_ORDERED, 'ordered_quantity' => 5, ]); $response->assertRedirect(); $response->assertSessionHas('success'); } public function test_store_validates_required_spare_part_id(): void { $response = $this->actingAs($this->adminUser) ->post(route('spare_part_orders.store'), [ 'status' => SparePartOrder::STATUS_ORDERED, 'ordered_quantity' => 10, ]); $response->assertSessionHasErrors('spare_part_id'); } public function test_store_validates_required_ordered_quantity(): void { $sparePart = SparePart::factory()->create(); $response = $this->actingAs($this->adminUser) ->post(route('spare_part_orders.store'), [ 'spare_part_id' => $sparePart->id, 'status' => SparePartOrder::STATUS_ORDERED, ]); $response->assertSessionHasErrors('ordered_quantity'); } // ==================== Update ==================== public function test_admin_can_update_spare_part_order(): void { $sparePartOrder = SparePartOrder::factory()->ordered()->create(); $response = $this->actingAs($this->adminUser) ->put(route('spare_part_orders.update', $sparePartOrder), [ 'spare_part_id' => $sparePartOrder->spare_part_id, 'status' => SparePartOrder::STATUS_ORDERED, 'ordered_quantity' => 20, 'order_number' => 'ORD-2024-001', ]); $response->assertRedirect(); $response->assertSessionHas('success'); $this->assertDatabaseHas('spare_part_orders', [ 'id' => $sparePartOrder->id, 'ordered_quantity' => 20, 'order_number' => 'ORD-2024-001', ]); } public function test_manager_can_update_spare_part_order(): void { $sparePartOrder = SparePartOrder::factory()->ordered()->create(); $response = $this->actingAs($this->managerUser) ->put(route('spare_part_orders.update', $sparePartOrder), [ 'spare_part_id' => $sparePartOrder->spare_part_id, 'status' => SparePartOrder::STATUS_ORDERED, 'ordered_quantity' => 15, ]); $response->assertRedirect(); $response->assertSessionHas('success'); } public function test_guest_cannot_update_spare_part_order(): void { $sparePartOrder = SparePartOrder::factory()->create(); $response = $this->put(route('spare_part_orders.update', $sparePartOrder), []); $response->assertRedirect(route('login')); } // ==================== Destroy ==================== public function test_admin_can_delete_spare_part_order_without_active_reservations(): void { $sparePartOrder = SparePartOrder::factory()->create(); $response = $this->actingAs($this->adminUser) ->delete(route('spare_part_orders.destroy', $sparePartOrder)); $response->assertRedirect(route('spare_part_orders.index')); $response->assertSessionHas('success'); $this->assertSoftDeleted('spare_part_orders', ['id' => $sparePartOrder->id]); } public function test_admin_cannot_delete_spare_part_order_with_active_reservations(): void { $sparePartOrder = SparePartOrder::factory()->inStock()->create(); Reservation::factory()->create([ 'spare_part_order_id' => $sparePartOrder->id, 'spare_part_id' => $sparePartOrder->spare_part_id, 'status' => Reservation::STATUS_ACTIVE, ]); $response = $this->actingAs($this->adminUser) ->delete(route('spare_part_orders.destroy', $sparePartOrder)); $response->assertRedirect(route('spare_part_orders.show', $sparePartOrder)); $response->assertSessionHas('error'); $this->assertDatabaseHas('spare_part_orders', ['id' => $sparePartOrder->id, 'deleted_at' => null]); } public function test_manager_cannot_delete_spare_part_order(): void { $sparePartOrder = SparePartOrder::factory()->create(); $response = $this->actingAs($this->managerUser) ->delete(route('spare_part_orders.destroy', $sparePartOrder)); $response->assertStatus(403); } public function test_guest_cannot_delete_spare_part_order(): void { $sparePartOrder = SparePartOrder::factory()->create(); $response = $this->delete(route('spare_part_orders.destroy', $sparePartOrder)); $response->assertRedirect(route('login')); } // ==================== SetInStock ==================== public function test_admin_can_set_order_in_stock(): void { $sparePartOrder = SparePartOrder::factory()->ordered()->create(); $response = $this->actingAs($this->adminUser) ->post(route('spare_part_orders.set_in_stock', $sparePartOrder)); $response->assertRedirect(route('spare_part_orders.show', $sparePartOrder)); $response->assertSessionHas('success'); $this->assertDatabaseHas('spare_part_orders', [ 'id' => $sparePartOrder->id, 'status' => SparePartOrder::STATUS_IN_STOCK, ]); } public function test_manager_can_set_order_in_stock(): void { $sparePartOrder = SparePartOrder::factory()->ordered()->create(); $response = $this->actingAs($this->managerUser) ->post(route('spare_part_orders.set_in_stock', $sparePartOrder)); $response->assertRedirect(route('spare_part_orders.show', $sparePartOrder)); $response->assertSessionHas('success'); } public function test_guest_cannot_set_order_in_stock(): void { $sparePartOrder = SparePartOrder::factory()->create(); $response = $this->post(route('spare_part_orders.set_in_stock', $sparePartOrder)); $response->assertRedirect(route('login')); } // ==================== Ship ==================== public function test_admin_can_ship_spare_part_order(): void { $sparePartOrder = SparePartOrder::factory()->inStock()->withQuantity(20)->create(); $response = $this->actingAs($this->adminUser) ->post(route('spare_part_orders.ship', $sparePartOrder), [ 'quantity' => 5, 'note' => 'Тестовая отгрузка', ]); $response->assertRedirect(route('spare_part_orders.show', $sparePartOrder)); $response->assertSessionHas('success'); $this->assertDatabaseHas('spare_part_orders', [ 'id' => $sparePartOrder->id, 'available_qty' => 15, ]); } public function test_ship_fails_if_quantity_exceeds_available(): void { $sparePartOrder = SparePartOrder::factory()->inStock()->withQuantity(3)->create(); $response = $this->actingAs($this->adminUser) ->post(route('spare_part_orders.ship', $sparePartOrder), [ 'quantity' => 10, 'note' => 'Попытка отгрузить больше чем есть', ]); $response->assertRedirect(route('spare_part_orders.show', $sparePartOrder)); $response->assertSessionHas('error'); $this->assertDatabaseHas('spare_part_orders', [ 'id' => $sparePartOrder->id, 'available_qty' => 3, ]); } public function test_ship_validates_required_quantity(): void { $sparePartOrder = SparePartOrder::factory()->inStock()->create(); $response = $this->actingAs($this->adminUser) ->post(route('spare_part_orders.ship', $sparePartOrder), [ 'note' => 'Без количества', ]); $response->assertSessionHasErrors('quantity'); } public function test_manager_can_ship_spare_part_order(): void { $sparePartOrder = SparePartOrder::factory()->inStock()->withQuantity(10)->create(); $response = $this->actingAs($this->managerUser) ->post(route('spare_part_orders.ship', $sparePartOrder), [ 'quantity' => 2, 'note' => 'Отгрузка менеджером', ]); $response->assertRedirect(route('spare_part_orders.show', $sparePartOrder)); $response->assertSessionHas('success'); } public function test_guest_cannot_ship_spare_part_order(): void { $sparePartOrder = SparePartOrder::factory()->create(); $response = $this->post(route('spare_part_orders.ship', $sparePartOrder), [ 'quantity' => 1, 'note' => 'Test', ]); $response->assertRedirect(route('login')); } // ==================== Correct (Inventory) ==================== public function test_admin_can_correct_inventory(): void { $sparePartOrder = SparePartOrder::factory()->inStock()->withQuantity(10)->create(); $response = $this->actingAs($this->adminUser) ->post(route('spare_part_orders.correct', $sparePartOrder), [ 'new_quantity' => 8, 'reason' => 'Инвентаризация — обнаружена недостача', ]); $response->assertRedirect(route('spare_part_orders.show', $sparePartOrder)); $response->assertSessionHas('success'); $this->assertDatabaseHas('spare_part_orders', [ 'id' => $sparePartOrder->id, 'available_qty' => 8, ]); } public function test_correct_fails_if_quantity_unchanged(): void { $sparePartOrder = SparePartOrder::factory()->inStock()->withQuantity(10)->create(); $response = $this->actingAs($this->adminUser) ->post(route('spare_part_orders.correct', $sparePartOrder), [ 'new_quantity' => 10, 'reason' => 'Без изменений', ]); $response->assertRedirect(route('spare_part_orders.show', $sparePartOrder)); $response->assertSessionHas('error'); } public function test_manager_cannot_correct_inventory(): void { $sparePartOrder = SparePartOrder::factory()->inStock()->create(); $response = $this->actingAs($this->managerUser) ->post(route('spare_part_orders.correct', $sparePartOrder), [ 'new_quantity' => 5, 'reason' => 'Test', ]); $response->assertStatus(403); } public function test_guest_cannot_correct_inventory(): void { $sparePartOrder = SparePartOrder::factory()->create(); $response = $this->post(route('spare_part_orders.correct', $sparePartOrder), [ 'new_quantity' => 5, 'reason' => 'Test', ]); $response->assertRedirect(route('login')); } }