'role-' . uniqid(), 'guard_name' => 'admin']); $role->givePermissionTo(Permission::firstOrCreate(['name' => 'module-vcenter.manager', 'guard_name' => 'admin'])); $admin = User::factory()->create(); $admin->assignRole($role); return $admin; } private function row(array $values): array { return array_map(fn ($header) => $values[$header] ?? null, self::HEADER); } private function xlsx(array $rows): UploadedFile { $spreadsheet = new Spreadsheet(); $spreadsheet->getActiveSheet()->setTitle('CONFIG'); $sheet = $spreadsheet->createSheet()->setTitle('IP_POOL'); $sheet->fromArray([self::HEADER, ...$rows]); $sheet->setCellValue('Y2', '=XLOOKUP(D2,CONFIG!A:A,CONFIG!B:B)'); $path = tempnam(sys_get_temp_dir(), 'ip') . '.xlsx'; (new Xlsx($spreadsheet))->setPreCalculateFormulas(false)->save($path); return new UploadedFile($path, 'ip.xlsx', null, null, true); } public function test_status_follows_sheet_unless_the_system_owns_the_ip(): void { $this->assertSame('assigned', IpPoolSheetImporter::resolveStatus(null, false, 'ALLOCATED')); $this->assertSame('assigned', IpPoolSheetImporter::resolveStatus('free', false, 'ALLOCATED')); $this->assertSame('free', IpPoolSheetImporter::resolveStatus('assigned', false, 'FREE')); $this->assertSame('assigned', IpPoolSheetImporter::resolveStatus('assigned', true, 'FREE')); $this->assertSame('reserved', IpPoolSheetImporter::resolveStatus('reserved', true, 'ALLOCATED')); $this->assertSame('free', IpPoolSheetImporter::resolveStatus(null, false, null)); } public function test_preview_reports_changes_without_writing_and_import_applies_them(): void { $network = ModuleNetwork::create(['name' => 'VM Network 56']); IpPool::create([ 'ip_address' => '10.0.0.5', 'module_network_id' => $network->id, 'cidr' => 24, 'gateway' => '10.0.0.1', 'status' => 'free', ]); IpPool::create([ 'ip_address' => '10.0.0.6', 'module_network_id' => $network->id, 'cidr' => 24, 'status' => 'free', ]); ModuleIpAddress::create(['ip' => '10.0.0.6', 'module_network_id' => $network->id, 'status' => 1]); $file = $this->xlsx([ $this->row([ 'TEN_MANG' => "THEGIOISO-VN\t\t", 'CIDR' => '/22', 'OWNER_TYPE' => 'thế giới số', 'IP_ADDRESS' => '10.0.0.5', 'TEN_KHACH_HANG' => 'Khách A', 'TRANG_THAI' => 'ALLOCATED', 'NGAY_CAP_PHAT' => ExcelDate::PHPToExcel(new \DateTime('2026-04-15')), 'CONTACT_EMAIL' => "\ta@example.com; b@example.com", 'CONTACT_PHONE' => 835123959, 'MONTHLY_COST' => 60000, ]), $this->row(['TEN_MANG' => 'THEGIOISO-VN', 'IP_ADDRESS' => '10.0.0.6', 'TRANG_THAI' => 'FREE']), $this->row(['TEN_MANG' => 'HOITUSO-VN', 'IP_ADDRESS' => '10.0.1.9', 'TRANG_THAI' => 'ALLOCATED']), $this->row(['CONTACT_CC' => 'kythuat@tgs.com.vn']), $this->row(['TEN_MANG' => 'HOITUSO-VN', 'IP_ADDRESS' => '10.0.1.10', 'CONTACT_EMAIL' => 'not-an-email']), ]); $admin = $this->admin(); $this->actingAs($admin, 'admin') ->post('/api/v1/administrator/ip-pool/import/preview', ['file' => $file], ['Accept' => 'application/json']) ->assertOk() ->assertJsonPath('data.valid', 3) ->assertJsonPath('data.skipped_blank', 1) ->assertJsonPath('data.error_count', 1) ->assertJsonPath('data.errors.0.row', 6) ->assertJsonPath('data.create', 1) ->assertJsonPath('data.update', 2) ->assertJsonPath('data.to_assigned', 2) ->assertJsonPath('data.kept_by_system', 1); $this->assertSame(2, IpPool::count()); $this->actingAs($admin, 'admin') ->post('/api/v1/administrator/ip-pool/import', ['file' => $file], ['Accept' => 'application/json']) ->assertOk(); $updated = IpPool::where('ip_address', '10.0.0.5')->sole(); $this->assertSame($network->id, $updated->module_network_id); $this->assertSame('assigned', $updated->status); $this->assertSame('THEGIOISO-VN', $updated->ip_block); $this->assertSame('THẾ GIỚI SỐ', $updated->owner_type); $this->assertSame(22, $updated->cidr); $this->assertSame('10.0.0.1', $updated->gateway); $this->assertSame('a@example.com, b@example.com', $updated->contact_email); $this->assertSame('0835123959', $updated->contact_phone); $this->assertSame('2026-04-15', $updated->allocated_at->toDateString()); $this->assertSame('60000.00', $updated->monthly_cost); $this->assertSame('free', IpPool::where('ip_address', '10.0.0.6')->value('status')); $created = IpPool::where('ip_address', '10.0.1.9')->sole(); $this->assertNull($created->module_network_id); $this->assertSame('assigned', $created->status); $this->assertFalse(IpPool::where('ip_address', '10.0.1.10')->exists()); } }