|
@@ -0,0 +1,257 @@
|
|
|
|
|
+<?php
|
|
|
|
|
+
|
|
|
|
|
+namespace Tests\Unit\Services\Import;
|
|
|
|
|
+
|
|
|
|
|
+use App\Models\MafOrder;
|
|
|
|
|
+use App\Models\Product;
|
|
|
|
|
+use App\Services\Import\ImportMafOrdersService;
|
|
|
|
|
+use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
|
|
|
+use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
|
|
|
|
+use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
|
|
|
|
+use Tests\TestCase;
|
|
|
|
|
+
|
|
|
|
|
+class ImportMafOrdersServiceTest extends TestCase
|
|
|
|
|
+{
|
|
|
|
|
+ use RefreshDatabase;
|
|
|
|
|
+
|
|
|
|
|
+ protected $seed = true;
|
|
|
|
|
+
|
|
|
|
|
+ private string $tempFilePath;
|
|
|
|
|
+ private Product $product1;
|
|
|
|
|
+ private Product $product2;
|
|
|
|
|
+ private int $testYear = 2025;
|
|
|
|
|
+
|
|
|
|
|
+ protected function setUp(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ parent::setUp();
|
|
|
|
|
+ $this->product1 = Product::factory()->create(['article' => 'MAF.0001', 'year' => $this->testYear]);
|
|
|
|
|
+ $this->product2 = Product::factory()->create(['article' => 'MAF.0002', 'year' => $this->testYear]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ protected function tearDown(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ if (isset($this->tempFilePath) && file_exists($this->tempFilePath)) {
|
|
|
|
|
+ unlink($this->tempFilePath);
|
|
|
|
|
+ }
|
|
|
|
|
+ parent::tearDown();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function test_import_creates_maf_orders(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ $this->createTestFile([
|
|
|
|
|
+ ['MAF.0001', 10, '55/5224', 'На складе'],
|
|
|
|
|
+ ['MAF.0002', 5, '1554-55453', 'Заказан'],
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ $service = new ImportMafOrdersService($this->tempFilePath, 1, $this->testYear);
|
|
|
|
|
+ $result = $service->handle();
|
|
|
|
|
+
|
|
|
|
|
+ $this->assertTrue($result['success']);
|
|
|
|
|
+ $this->assertEquals(2, $result['imported']);
|
|
|
|
|
+ $this->assertEquals(0, $result['errors']);
|
|
|
|
|
+
|
|
|
|
|
+ $this->assertDatabaseHas('maf_orders', [
|
|
|
|
|
+ 'product_id' => $this->product1->id,
|
|
|
|
|
+ 'quantity' => 10,
|
|
|
|
|
+ 'in_stock' => 10,
|
|
|
|
|
+ 'order_number' => '55/5224',
|
|
|
|
|
+ 'status' => 'на складе',
|
|
|
|
|
+ 'year' => $this->testYear,
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ $this->assertDatabaseHas('maf_orders', [
|
|
|
|
|
+ 'product_id' => $this->product2->id,
|
|
|
|
|
+ 'quantity' => 5,
|
|
|
|
|
+ 'in_stock' => 0,
|
|
|
|
|
+ 'order_number' => '1554-55453',
|
|
|
|
|
+ 'status' => 'заказан',
|
|
|
|
|
+ 'year' => $this->testYear,
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function test_import_reports_error_for_unknown_article(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ $this->createTestFile([
|
|
|
|
|
+ ['UNKNOWN.ARTICLE', 10, '55/5224', 'На складе'],
|
|
|
|
|
+ ['MAF.0001', 5, '55/5224', 'На складе'],
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ $service = new ImportMafOrdersService($this->tempFilePath, 1, $this->testYear);
|
|
|
|
|
+ $result = $service->handle();
|
|
|
|
|
+
|
|
|
|
|
+ $this->assertFalse($result['success']);
|
|
|
|
|
+ $this->assertEquals(1, $result['imported']);
|
|
|
|
|
+ $this->assertEquals(1, $result['errors']);
|
|
|
|
|
+
|
|
|
|
|
+ $hasErrorLog = false;
|
|
|
|
|
+ foreach ($result['logs'] as $log) {
|
|
|
|
|
+ if (str_contains($log, 'UNKNOWN.ARTICLE') && str_contains($log, 'не найден')) {
|
|
|
|
|
+ $hasErrorLog = true;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ $this->assertTrue($hasErrorLog, 'Should log error for unknown article');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function test_import_reports_error_for_unknown_status(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ $this->createTestFile([
|
|
|
|
|
+ ['MAF.0001', 10, '55/5224', 'Неизвестный статус'],
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ $service = new ImportMafOrdersService($this->tempFilePath, 1, $this->testYear);
|
|
|
|
|
+ $result = $service->handle();
|
|
|
|
|
+
|
|
|
|
|
+ $this->assertFalse($result['success']);
|
|
|
|
|
+ $this->assertEquals(0, $result['imported']);
|
|
|
|
|
+ $this->assertEquals(1, $result['errors']);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function test_import_skips_empty_rows(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ $this->createTestFile([
|
|
|
|
|
+ ['', '', '', ''],
|
|
|
|
|
+ ['MAF.0001', 10, '55/5224', 'На складе'],
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ $service = new ImportMafOrdersService($this->tempFilePath, 1, $this->testYear);
|
|
|
|
|
+ $result = $service->handle();
|
|
|
|
|
+
|
|
|
|
|
+ $this->assertTrue($result['success']);
|
|
|
|
|
+ $this->assertEquals(1, $result['imported']);
|
|
|
|
|
+ $this->assertEquals(1, $result['skipped']);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function test_import_parses_status_correctly(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ $this->createTestFile([
|
|
|
|
|
+ ['MAF.0001', 1, 'order1', 'На складе'],
|
|
|
|
|
+ ['MAF.0002', 1, 'order2', 'Заказан'],
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ $service = new ImportMafOrdersService($this->tempFilePath, 1, $this->testYear);
|
|
|
|
|
+ $result = $service->handle();
|
|
|
|
|
+
|
|
|
|
|
+ $this->assertTrue($result['success']);
|
|
|
|
|
+
|
|
|
|
|
+ $this->assertDatabaseHas('maf_orders', [
|
|
|
|
|
+ 'product_id' => $this->product1->id,
|
|
|
|
|
+ 'status' => 'на складе',
|
|
|
|
|
+ 'in_stock' => 1,
|
|
|
|
|
+ ]);
|
|
|
|
|
+ $this->assertDatabaseHas('maf_orders', [
|
|
|
|
|
+ 'product_id' => $this->product2->id,
|
|
|
|
|
+ 'status' => 'заказан',
|
|
|
|
|
+ 'in_stock' => 0,
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function test_import_only_uses_products_from_specified_year(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ // Создаём продукт с другим годом
|
|
|
|
|
+ Product::factory()->create(['article' => 'MAF.OTHER', 'year' => 2020]);
|
|
|
|
|
+
|
|
|
|
|
+ $this->createTestFile([
|
|
|
|
|
+ ['MAF.OTHER', 10, '55/5224', 'На складе'],
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ $service = new ImportMafOrdersService($this->tempFilePath, 1, $this->testYear);
|
|
|
|
|
+ $result = $service->handle();
|
|
|
|
|
+
|
|
|
|
|
+ $this->assertFalse($result['success']);
|
|
|
|
|
+ $this->assertEquals(0, $result['imported']);
|
|
|
|
|
+ $this->assertEquals(1, $result['errors']);
|
|
|
|
|
+
|
|
|
|
|
+ $hasErrorLog = false;
|
|
|
|
|
+ foreach ($result['logs'] as $log) {
|
|
|
|
|
+ if (str_contains($log, 'MAF.OTHER') && str_contains($log, $this->testYear . ' года')) {
|
|
|
|
|
+ $hasErrorLog = true;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ $this->assertTrue($hasErrorLog, 'Should log error mentioning the year');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function test_import_returns_summary(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ $this->createTestFile([
|
|
|
|
|
+ ['MAF.0001', 10, '55/5224', 'На складе'],
|
|
|
|
|
+ ['UNKNOWN', 5, '55/5224', 'На складе'],
|
|
|
|
|
+ [' ', '', '', ''],
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ $service = new ImportMafOrdersService($this->tempFilePath, 1, $this->testYear);
|
|
|
|
|
+ $result = $service->handle();
|
|
|
|
|
+
|
|
|
|
|
+ $this->assertArrayHasKey('imported', $result);
|
|
|
|
|
+ $this->assertArrayHasKey('skipped', $result);
|
|
|
|
|
+ $this->assertArrayHasKey('errors', $result);
|
|
|
|
|
+ $this->assertArrayHasKey('logs', $result);
|
|
|
|
|
+
|
|
|
|
|
+ $this->assertEquals(1, $result['imported']);
|
|
|
|
|
+ $this->assertEquals(1, $result['skipped']);
|
|
|
|
|
+ $this->assertEquals(1, $result['errors']);
|
|
|
|
|
+
|
|
|
|
|
+ $hasSummary = false;
|
|
|
|
|
+ foreach ($result['logs'] as $log) {
|
|
|
|
|
+ if (str_contains($log, 'РЕЗЮМЕ')) {
|
|
|
|
|
+ $hasSummary = true;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ $this->assertTrue($hasSummary, 'Should include summary in logs');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public function test_import_sets_in_stock_based_on_status(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ $this->createTestFile([
|
|
|
|
|
+ ['MAF.0001', 15, 'order1', 'На складе'],
|
|
|
|
|
+ ['MAF.0002', 20, 'order2', 'Заказан'],
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ $service = new ImportMafOrdersService($this->tempFilePath, 1, $this->testYear);
|
|
|
|
|
+ $result = $service->handle();
|
|
|
|
|
+
|
|
|
|
|
+ $this->assertTrue($result['success']);
|
|
|
|
|
+
|
|
|
|
|
+ // На складе - in_stock = quantity
|
|
|
|
|
+ $this->assertDatabaseHas('maf_orders', [
|
|
|
|
|
+ 'product_id' => $this->product1->id,
|
|
|
|
|
+ 'quantity' => 15,
|
|
|
|
|
+ 'in_stock' => 15,
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ // Заказан - in_stock = 0
|
|
|
|
|
+ $this->assertDatabaseHas('maf_orders', [
|
|
|
|
|
+ 'product_id' => $this->product2->id,
|
|
|
|
|
+ 'quantity' => 20,
|
|
|
|
|
+ 'in_stock' => 0,
|
|
|
|
|
+ ]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private function createTestFile(array $rows): void
|
|
|
|
|
+ {
|
|
|
|
|
+ $spreadsheet = new Spreadsheet();
|
|
|
|
|
+ $sheet = $spreadsheet->getActiveSheet();
|
|
|
|
|
+
|
|
|
|
|
+ // Headers
|
|
|
|
|
+ $sheet->setCellValue('A1', 'Артикул МАФ');
|
|
|
|
|
+ $sheet->setCellValue('B1', 'кол-во');
|
|
|
|
|
+ $sheet->setCellValue('C1', 'Номер заказа');
|
|
|
|
|
+ $sheet->setCellValue('D1', 'Статус');
|
|
|
|
|
+
|
|
|
|
|
+ // Data rows
|
|
|
|
|
+ $rowNum = 2;
|
|
|
|
|
+ foreach ($rows as $row) {
|
|
|
|
|
+ $sheet->setCellValue('A' . $rowNum, $row[0] ?? '');
|
|
|
|
|
+ $sheet->setCellValue('B' . $rowNum, $row[1] ?? '');
|
|
|
|
|
+ $sheet->setCellValue('C' . $rowNum, $row[2] ?? '');
|
|
|
|
|
+ $sheet->setCellValue('D' . $rowNum, $row[3] ?? '');
|
|
|
|
|
+ $rowNum++;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $this->tempFilePath = sys_get_temp_dir() . '/test_maf_orders_' . uniqid() . '.xlsx';
|
|
|
|
|
+ $writer = new Xlsx($spreadsheet);
|
|
|
|
|
+ $writer->save($this->tempFilePath);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|