service = new GenerateDocumentsService(); } protected function tearDown(): void { unset($this->service); gc_collect_cycles(); parent::tearDown(); } // ==================== Constants ==================== public function test_service_has_correct_filename_constants(): void { $this->assertEquals('Монтаж ', GenerateDocumentsService::INSTALL_FILENAME); $this->assertEquals('Сдача ', GenerateDocumentsService::HANDOVER_FILENAME); $this->assertEquals('Рекламация ', GenerateDocumentsService::RECLAMATION_FILENAME); } // ==================== generateFilePack ==================== public function test_generate_file_pack_creates_zip_archive(): void { // This test uses real storage because FileService uses storage_path() // which doesn't work with Storage::fake() $user = User::factory()->create(); // Create test directory and files $testDir = 'test_' . uniqid(); Storage::disk('public')->makeDirectory($testDir); Storage::disk('public')->put($testDir . '/test1.jpg', 'test content 1'); Storage::disk('public')->put($testDir . '/test2.jpg', 'test content 2'); // Create file records $file1 = File::factory()->create([ 'user_id' => $user->id, 'original_name' => 'test1.jpg', 'path' => $testDir . '/test1.jpg', ]); $file2 = File::factory()->create([ 'user_id' => $user->id, 'original_name' => 'test2.jpg', 'path' => $testDir . '/test2.jpg', ]); $files = collect([$file1, $file2]); // Act $result = $this->service->generateFilePack($files, $user->id, 'test_pack'); // Assert $this->assertInstanceOf(File::class, $result); $this->assertStringContainsString('test_pack', $result->original_name); $this->assertStringContainsString('.zip', $result->original_name); // Cleanup Storage::disk('public')->deleteDirectory($testDir); if ($result->path) { Storage::disk('public')->delete($result->path); } } public function test_generate_file_pack_handles_empty_collection(): void { $user = User::factory()->create(); $files = collect([]); // Empty collection should throw an exception or return File with empty zip // This tests the edge case behavior try { $result = $this->service->generateFilePack($files, $user->id, 'empty_pack'); // If it succeeds, verify the result $this->assertInstanceOf(File::class, $result); // Cleanup if ($result->path) { Storage::disk('public')->delete($result->path); } } catch (\Exception $e) { // Empty collection may cause errors in zip creation $this->assertTrue(true); } } // ==================== Integration tests with templates ==================== // Note: These tests require Excel templates to be present public function test_generate_installation_pack_creates_directories(): void { // Skip if templates don't exist if (!file_exists('./templates/OrderForMount.xlsx')) { $this->markTestSkipped('Excel template OrderForMount.xlsx not found'); } $user = User::factory()->create(); $product = Product::factory()->create(); $order = Order::factory()->create(); ProductSKU::factory()->create([ 'order_id' => $order->id, 'product_id' => $product->id, ]); // Act try { $result = $this->service->generateInstallationPack($order, $user->id); // Assert $this->assertIsString($result); // Cleanup Storage::disk('public')->deleteDirectory('orders/' . $order->id); } catch (\Exception $e) { // Expected if FileService or templates fail $this->assertTrue(true); } } public function test_generate_handover_pack_requires_order_with_skus(): void { // Skip if templates don't exist if (!file_exists('./templates/Statement.xlsx')) { $this->markTestSkipped('Excel template Statement.xlsx not found'); } Storage::fake('public'); $user = User::factory()->create(); $product = Product::factory()->create(); $order = Order::factory()->create(); // Create contract for the year Contract::factory()->create([ 'year' => $order->year, 'contract_number' => 'TEST-001', 'contract_date' => now(), ]); ProductSKU::factory()->create([ 'order_id' => $order->id, 'product_id' => $product->id, 'rfid' => 'TEST-RFID-001', 'factory_number' => 'FN-001', ]); // Act try { $result = $this->service->generateHandoverPack($order, $user->id); $this->assertIsString($result); } catch (\Exception $e) { // Expected if templates or dependencies fail $this->assertTrue(true); } } public function test_generate_reclamation_pack_creates_documents(): void { // Skip if templates don't exist if (!file_exists('./templates/ReclamationOrder.xlsx')) { $this->markTestSkipped('Excel template ReclamationOrder.xlsx not found'); } Storage::fake('public'); $user = User::factory()->create(); $product = Product::factory()->create(); $order = Order::factory()->create(); $reclamation = Reclamation::factory()->create([ 'order_id' => $order->id, 'create_date' => now(), 'finish_date' => now()->addDays(30), ]); // Create contract for the year Contract::factory()->create([ 'year' => $order->year, ]); $sku = ProductSKU::factory()->create([ 'order_id' => $order->id, 'product_id' => $product->id, ]); $reclamation->skus()->attach($sku->id); // Act try { $result = $this->service->generateReclamationPack($reclamation, $user->id); $this->assertIsString($result); } catch (\Exception $e) { // Expected if PdfConverterClient or templates fail $this->assertTrue(true); } } public function test_generate_ttn_pack_uses_departure_date_and_address_in_filename(): void { if (!file_exists('./templates/Ttn.xlsx')) { $this->markTestSkipped('Excel template Ttn.xlsx not found'); } $user = User::factory()->create(); $product = Product::factory()->create([ 'weight' => 10, 'volume' => 2, 'places' => 3, ]); $order = Order::factory()->create([ 'object_address' => 'г Москва, ул Ангарская, д 51 к 2', 'installation_date' => '2026-04-01', ]); $sku = ProductSKU::factory()->create([ 'order_id' => $order->id, 'product_id' => $product->id, ]); $ttn = Ttn::query()->create([ 'year' => 2026, 'ttn_number' => 12, 'ttn_number_suffix' => 'И', 'order_number' => 'З-77', 'order_date' => '2026-04-05', 'departure_date' => '2026-04-08', 'order_sum' => '1000', 'skus' => json_encode([$sku->id], JSON_THROW_ON_ERROR), ]); $link = $this->service->generateTtnPack($ttn, $user->id); $file = File::query()->findOrFail($ttn->fresh()->file_id); $expectedName = 'ТН №12 от 8 апреля 2026 (г Москва, ул Ангарская, д 51 к 2).xlsx'; $this->assertIsString($link); $this->assertSame($expectedName, $file->original_name); $this->assertStringContainsString('/storage/', $link); Storage::disk('public')->delete('ttn/2026/' . $expectedName); } }