adminUser = User::factory()->create(['role' => Role::ADMIN]); $this->managerUser = User::factory()->create(['role' => Role::MANAGER]); $this->brigadierUser = User::factory()->create(['role' => Role::BRIGADIER]); } // ==================== Authentication ==================== public function test_guest_cannot_access_orders_index(): void { $response = $this->get(route('order.index')); $response->assertRedirect(route('login')); } public function test_authenticated_user_can_access_orders_index(): void { $response = $this->actingAs($this->managerUser) ->get(route('order.index')); $response->assertStatus(200); $response->assertViewIs('orders.index'); } // ==================== Index ==================== public function test_orders_index_displays_orders(): void { $order = Order::factory()->create(); $response = $this->actingAs($this->managerUser) ->get(route('order.index')); $response->assertStatus(200); $response->assertSee($order->object_address); } public function test_brigadier_sees_only_assigned_orders(): void { $assignedOrder = Order::factory()->create([ 'brigadier_id' => $this->brigadierUser->id, ]); $otherOrder = Order::factory()->create([ 'brigadier_id' => User::factory()->create(['role' => Role::BRIGADIER])->id, ]); $response = $this->actingAs($this->brigadierUser) ->get(route('order.index')); $response->assertStatus(200); $response->assertSee($assignedOrder->object_address); $response->assertDontSee($otherOrder->object_address); } // ==================== Create ==================== public function test_can_view_create_order_form(): void { $response = $this->actingAs($this->adminUser) ->get(route('order.create')); $response->assertStatus(200); $response->assertViewIs('orders.edit'); } // ==================== Store ==================== public function test_can_create_new_order(): void { $district = District::factory()->create(); $area = Area::factory()->create(); $objectType = ObjectType::factory()->create(); $response = $this->actingAs($this->managerUser) ->post(route('order.store'), [ 'name' => 'Тестовый заказ', 'user_id' => $this->managerUser->id, 'district_id' => $district->id, 'area_id' => $area->id, 'object_address' => 'ул. Тестовая, д. 1', 'object_type_id' => $objectType->id, 'comment' => 'Тестовый комментарий', ]); $response->assertRedirect(); $this->assertDatabaseHas('orders', [ 'object_address' => 'ул. Тестовая, д. 1', 'order_status_id' => Order::STATUS_NEW, ]); } public function test_creating_order_sets_tg_group_name(): void { $district = District::factory()->create(['shortname' => 'ЦАО']); $area = Area::factory()->create(['name' => 'Тверской']); $objectType = ObjectType::factory()->create(); $this->actingAs($this->managerUser) ->post(route('order.store'), [ 'name' => 'Тестовый заказ', 'user_id' => $this->managerUser->id, 'district_id' => $district->id, 'area_id' => $area->id, 'object_address' => 'ул. Пушкина', 'object_type_id' => $objectType->id, ]); $order = Order::where('object_address', 'ул. Пушкина')->first(); $this->assertStringContainsString('ЦАО', $order->tg_group_name); $this->assertStringContainsString('Тверской', $order->tg_group_name); } public function test_can_update_existing_order(): void { $order = Order::factory()->create([ 'object_address' => 'Старый адрес', ]); $response = $this->actingAs($this->managerUser) ->post(route('order.store'), [ 'id' => $order->id, 'name' => $order->name, 'user_id' => $order->user_id, 'district_id' => $order->district_id, 'area_id' => $order->area_id, 'object_address' => 'Новый адрес', 'object_type_id' => $order->object_type_id, ]); $response->assertRedirect(); $this->assertDatabaseHas('orders', [ 'id' => $order->id, 'object_address' => 'Новый адрес', ]); } // ==================== Show ==================== public function test_can_view_order_details(): void { $order = Order::factory()->create(); $response = $this->actingAs($this->managerUser) ->get(route('order.show', $order)); $response->assertStatus(200); $response->assertViewIs('orders.show'); $response->assertSee($order->object_address); } // ==================== Edit ==================== public function test_can_view_edit_order_form(): void { $order = Order::factory()->create(); $response = $this->actingAs($this->managerUser) ->get(route('order.edit', $order)); $response->assertStatus(200); $response->assertViewIs('orders.edit'); } // ==================== Destroy ==================== public function test_can_delete_order(): void { $order = Order::factory()->create(); $orderId = $order->id; $response = $this->actingAs($this->adminUser) ->delete(route('order.destroy', $order)); $response->assertRedirect(route('order.index')); // Order uses SoftDeletes, so check deleted_at is set $this->assertSoftDeleted('orders', ['id' => $orderId]); } public function test_deleting_order_removes_related_product_skus(): void { $order = Order::factory()->create(); $product = Product::factory()->create(); $sku = ProductSKU::factory()->create([ 'order_id' => $order->id, 'product_id' => $product->id, ]); $this->actingAs($this->adminUser) ->delete(route('order.destroy', $order)); // ProductSKU uses SoftDeletes, so check deleted_at is set $this->assertSoftDeleted('products_sku', ['id' => $sku->id]); } // ==================== Search ==================== public function test_search_returns_matching_orders(): void { $order = Order::factory()->create([ 'object_address' => 'ул. Уникальная Тестовая, д. 999', ]); $otherOrder = Order::factory()->create([ 'object_address' => 'ул. Другая, д. 1', ]); $response = $this->actingAs($this->managerUser) ->get(route('order.index', ['s' => 'Уникальная Тестовая'])); $response->assertStatus(200); $response->assertSee($order->object_address); $response->assertDontSee($otherOrder->object_address); } // ==================== MAF Operations ==================== public function test_get_maf_to_order_assigns_available_maf(): void { $product = Product::factory()->create(); $order = Order::factory()->create(); $productSku = ProductSKU::factory()->create([ 'order_id' => $order->id, 'product_id' => $product->id, 'maf_order_id' => null, 'status' => 'требуется', ]); $mafOrder = MafOrder::factory()->create([ 'product_id' => $product->id, 'in_stock' => 5, ]); // This route requires admin role $response = $this->actingAs($this->adminUser) ->get(route('order.get-maf', $order)); $response->assertRedirect(route('order.show', $order)); $productSku->refresh(); $this->assertEquals($mafOrder->id, $productSku->maf_order_id); $this->assertEquals('отгружен', $productSku->status); $mafOrder->refresh(); $this->assertEquals(4, $mafOrder->in_stock); } public function test_revert_maf_returns_maf_to_stock(): void { $product = Product::factory()->create(); $order = Order::factory()->create(); $mafOrder = MafOrder::factory()->create([ 'product_id' => $product->id, 'in_stock' => 3, ]); $productSku = ProductSKU::factory()->create([ 'order_id' => $order->id, 'product_id' => $product->id, 'maf_order_id' => $mafOrder->id, 'status' => 'отгружен', ]); // This route requires admin role $response = $this->actingAs($this->adminUser) ->get(route('order.revert-maf', $order)); $response->assertRedirect(route('order.show', $order)); $productSku->refresh(); $this->assertNull($productSku->maf_order_id); $this->assertEquals('требуется', $productSku->status); $mafOrder->refresh(); $this->assertEquals(4, $mafOrder->in_stock); } public function test_move_maf_transfers_sku_to_another_order(): void { $product = Product::factory()->create(); $order1 = Order::factory()->create(); $order2 = Order::factory()->create(); $productSku = ProductSKU::factory()->create([ 'order_id' => $order1->id, 'product_id' => $product->id, ]); // This route requires admin role $response = $this->actingAs($this->adminUser) ->post(route('order.move-maf'), [ 'new_order_id' => $order2->id, 'ids' => json_encode([$productSku->id]), ]); $response->assertStatus(200); $response->assertJson(['success' => true]); $productSku->refresh(); $this->assertEquals($order2->id, $productSku->order_id); } // ==================== Photo Management ==================== public function test_can_upload_photo_to_order(): void { Storage::fake('public'); $order = Order::factory()->create(); // Use create() instead of image() to avoid GD extension requirement $photo = UploadedFile::fake()->create('photo.jpg', 100, 'image/jpeg'); $response = $this->actingAs($this->managerUser) ->post(route('order.upload-photo', $order), [ 'photo' => [$photo], ]); $response->assertRedirect(route('order.show', $order)); $this->assertCount(1, $order->fresh()->photos); } public function test_can_delete_photo_from_order(): void { Storage::fake('public'); $order = Order::factory()->create(); $file = File::factory()->create(); $order->photos()->attach($file); // This route requires admin role $response = $this->actingAs($this->adminUser) ->delete(route('order.delete-photo', [$order, $file])); $response->assertRedirect(route('order.show', $order)); $this->assertCount(0, $order->fresh()->photos); } public function test_can_delete_all_photos_from_order(): void { Storage::fake('public'); $order = Order::factory()->create(); $files = File::factory()->count(3)->create(); $order->photos()->attach($files->pluck('id')); // This route requires admin role $response = $this->actingAs($this->adminUser) ->delete(route('order.delete-all-photos', $order)); $response->assertRedirect(route('order.show', $order)); $this->assertCount(0, $order->fresh()->photos); } // ==================== Document Management ==================== public function test_can_upload_document_to_order(): void { Storage::fake('public'); $order = Order::factory()->create(); $document = UploadedFile::fake()->create('document.pdf', 100); $response = $this->actingAs($this->managerUser) ->post(route('order.upload-document', $order), [ 'document' => [$document], ]); $response->assertRedirect(route('order.show', $order)); $this->assertCount(1, $order->fresh()->documents); } public function test_upload_document_limits_to_5_files(): void { Storage::fake('public'); $order = Order::factory()->create(); $documents = []; for ($i = 0; $i < 7; $i++) { $documents[] = UploadedFile::fake()->create("document{$i}.pdf", 100); } $this->actingAs($this->managerUser) ->post(route('order.upload-document', $order), [ 'document' => $documents, ]); $this->assertCount(5, $order->fresh()->documents); } // ==================== Generation ==================== public function test_generate_installation_pack_requires_correct_status(): void { $order = Order::factory()->create([ 'order_status_id' => Order::STATUS_NEW, ]); $response = $this->actingAs($this->managerUser) ->get(route('order.generate-installation-pack', $order)); $response->assertRedirect(route('order.show', $order)); $response->assertSessionHas('danger'); } public function test_generate_installation_pack_succeeds_with_correct_status(): void { $product = Product::factory()->create(); $mafOrder = MafOrder::factory()->create(['product_id' => $product->id]); $order = Order::factory()->create([ 'order_status_id' => Order::STATUS_READY_TO_MOUNT, ]); // Create SKU with MAF assigned ProductSKU::factory()->create([ 'order_id' => $order->id, 'product_id' => $product->id, 'maf_order_id' => $mafOrder->id, ]); $response = $this->actingAs($this->managerUser) ->get(route('order.generate-installation-pack', $order)); $response->assertRedirect(route('order.show', $order)); $response->assertSessionHas('success'); } // ==================== Export ==================== public function test_can_export_orders(): void { Order::factory()->count(3)->create(); // This route requires admin role $response = $this->actingAs($this->adminUser) ->post(route('order.export')); $response->assertRedirect(route('order.index')); $response->assertSessionHas('success'); } public function test_can_export_single_order(): void { $order = Order::factory()->create(); // This route requires admin role $response = $this->actingAs($this->adminUser) ->post(route('order.export-one', $order)); $response->assertRedirect(route('order.show', $order)); $response->assertSessionHas('success'); } }