create(['role' => Role::ADMIN]); $import = $this->createImport($user, 'Оборудование для благоустройства', withImage: true); $this->assertTrue((new ImportCommonCatalogService($import, $user->id))->handle()); $this->assertDatabaseHas('common_catalog_items', [ 'article' => '0254', 'calculator_name' => 'Оборудование для благоустройства', 'places' => 38, 'builders_price' => 141850000, 'recommended_plus_10_price' => 188802350, ]); $item = \App\Models\CommonCatalogItem::query()->firstOrFail(); $this->assertNotNull($item->imageFile); Storage::disk('public')->assertExists($item->imageFile->path); $secondImport = $this->createImport($user, 'Обновлённое наименование'); $this->assertTrue((new ImportCommonCatalogService($secondImport, $user->id))->handle()); $this->assertDatabaseCount('common_catalog_items', 1); $this->assertDatabaseHas('common_catalog_items', [ 'article' => '0254', 'calculator_name' => 'Обновлённое наименование', ]); } public function test_import_accepts_template_header_with_line_break(): void { Storage::fake('upload'); $user = User::factory()->create(['role' => Role::ADMIN]); $import = $this->createImport($user, 'Тест', "Единица измерения\nгабаритов"); $this->assertTrue((new ImportCommonCatalogService($import, $user->id))->handle()); $this->assertSame('DONE', $import->refresh()->status); } public function test_import_accepts_real_catalog_row_without_calculator_name(): void { Storage::fake('upload'); $user = User::factory()->create(['role' => Role::ADMIN]); $import = $this->createImport($user, null); $this->assertTrue((new ImportCommonCatalogService($import, $user->id))->handle()); $this->assertDatabaseHas('common_catalog_items', [ 'article' => '0254', 'calculator_name' => null, ]); $this->assertStringContainsString('ошибок: 0', (string) $import->refresh()->result); } public function test_import_does_not_change_prices_without_field_permission(): void { Storage::fake('upload'); $user = User::factory()->create(['role' => Role::ASSISTANT_HEAD]); $item = \App\Models\CommonCatalogItem::factory()->create([ 'article' => '0254', 'calculator_name' => 'Старое наименование', 'builders_price' => 100, ]); $import = $this->createImport($user, 'Новое наименование'); $this->assertTrue((new ImportCommonCatalogService($import, $user->id))->handle()); $item->refresh(); $this->assertSame('Новое наименование', $item->calculator_name); $this->assertSame(100.0, $item->builders_price); } public function test_import_preserves_rows_with_same_article_as_named_variants(): void { Storage::fake('upload'); $user = User::factory()->create(['role' => Role::ADMIN]); $import = $this->createImport( $user, 'Оборудование игровой площадки', duplicateVariant: true, ); $this->assertTrue((new ImportCommonCatalogService($import, $user->id))->handle()); $this->assertDatabaseCount('common_catalog_items', 2); $this->assertDatabaseHas('common_catalog_items', [ 'article' => '0254', 'calculator_name' => 'Оборудование игровой площадки', 'builders_price' => 141850000, ]); $this->assertDatabaseHas('common_catalog_items', [ 'article' => '0254', 'calculator_name' => 'Оборудование игровой площадки (Цинк)', 'builders_price' => 162280000, ]); } public function test_import_rejects_wrong_headers_with_clear_error(): void { Storage::fake('upload'); $user = User::factory()->create(['role' => Role::ADMIN]); $import = $this->createImport($user, 'Тест', 'Неверный заголовок'); $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Некорректные заголовки'); try { (new ImportCommonCatalogService($import, $user->id))->handle(); } finally { $this->assertSame('ERROR', $import->refresh()->status); } } private function createImport( User $user, ?string $calculatorName, string $dimensionHeader = "Единица измерения\nгабаритов", bool $withImage = false, bool $duplicateVariant = false, ): Import { $spreadsheet = new Spreadsheet; $sheet = $spreadsheet->getActiveSheet(); $headers = ExportCommonCatalogService::HEADERS; $headers[10] = $dimensionHeader; $sheet->fromArray($headers, null, 'A1'); $sheet->fromArray(ExportCommonCatalogService::SUBHEADERS, null, 'A2'); $sheet->setCellValueExplicit('A3', '0254', DataType::TYPE_STRING); $sheet->setCellValue('B3', $calculatorName); $sheet->setCellValue('C3', 'Теневой навес'); $sheet->setCellValue('D3', 'от 180'); $sheet->setCellValue('E3', '1,37-1,55'); $sheet->setCellValue('F3', 3.43); $sheet->setCellValue('G3', 9.15); $sheet->setCellValue('H3', 3.46); $sheet->setCellValue('I3', 0); $sheet->setCellValue('K3', 'м'); $sheet->setCellValue('L3', 2153.84); $sheet->setCellValue('M3', 7.93); $sheet->setCellValue('N3', 38); $sheet->setCellValue('P3', '0+'); $sheet->setCellValue('Q3', 10); $sheet->setCellValue('R3', 'шт.'); $sheet->setCellValue('T3', 'Теневые навесы'); $sheet->setCellValue('U3', 'Наш Двор'); $sheet->setCellValue('V3', 'да'); $sheet->setCellValue('W3', 1418500); $sheet->setCellValue('X3', 1489425); $sheet->setCellValue('Y3', 1560350); $sheet->setCellValue('Z3', 2127750); $sheet->setCellValue('AA3', 2837000); $sheet->setCellValue('AB3', 3404400); $sheet->setCellValue('AC3', 1560350); $sheet->setCellValue('AD3', 1888023.50); if ($duplicateVariant) { for ($index = 1; $index <= 30; $index++) { $column = Coordinate::stringFromColumnIndex($index); $sheet->setCellValue("{$column}4", $sheet->getCell("{$column}3")->getValue()); } $sheet->setCellValue('B4', $calculatorName.' (Цинк)'); $sheet->setCellValue('V4', 'нет'); $sheet->setCellValue('W4', 1622800); } if ($withImage) { $image = UploadedFile::fake()->image('catalog-item.png', 100, 100); $drawing = new Drawing; $drawing->setPath($image->getPathname()); $drawing->setCoordinates('S3'); $drawing->setWorksheet($sheet); } $filename = 'common_catalog_'.uniqid().'.xlsx'; $path = Storage::disk('upload')->path($filename); (new Xlsx($spreadsheet))->save($path); return Import::query()->create([ 'type' => 'common_catalog', 'filename' => $filename, 'status' => 'new', 'user_id' => $user->id, ]); } }