'csv', 'bezeichnung' => 'TestCSV', 'kuerzel' => 'TC', 'farbe' => '#abcdef', 'skip_rows' => 3, 'has_header_row' => 1, 'delimiter' => ';', 'enclosure' => '"', 'col_buchungstag' => 0, 'col_wertstellung' => 1, 'col_vorgang' => 2, 'col_buchungstext' => 3, 'col_wert' => 4, 'date_format' => 'd.m.Y', 'decimal_separator' => ',', 'thousands_separator' => '.', ]); $this->assertGreaterThan(0, $csvId, 'CSV-Quelle wurde angelegt'); $csv = BankSource::find($csvId); $this->assertNotEmpty($csv, 'CSV-Quelle gefunden'); $this->assertEquals('csv', $csv['type'], 'CSV-Quelle hat type=csv'); $this->assertEquals('TestCSV', $csv['name'], 'BankSource liefert Alias name = bezeichnung'); $this->assertEquals('TC', $csv['kuerzel'], 'Kürzel korrekt'); // 2. API-Quelle mit verschlüsselten Credentials $providerApi = Database::fetchOne("SELECT id FROM bank_providers WHERE verbindungstyp='API' LIMIT 1"); if ($providerApi) { $apiId = BankSource::create([ 'type' => 'api', 'provider_id' => (int)$providerApi['id'], 'bezeichnung' => 'TestAPI', 'app_name' => 'app-user', 'client_id' => 'secret-key-1', 'secret' => 'super-signature', 'sandbox' => 0, ]); $this->assertGreaterThan(0, $apiId, 'API-Quelle wurde angelegt'); // DB-Spalte muss verschlüsselt sein $raw = Database::fetchOne('SELECT client_id_enc, secret_enc FROM bank_sources WHERE id = ?', [$apiId]); $this->assert(str_starts_with($raw['client_id_enc'], 'enc:v1:'), 'client_id_enc ist verschlüsselt'); $this->assert(str_starts_with($raw['secret_enc'], 'enc:v1:'), 'secret_enc ist verschlüsselt'); // BankSource::find liefert entschlüsselt $api = BankSource::find($apiId); $this->assertEquals('secret-key-1', $api['client_id'], 'client_id entschlüsselt korrekt'); $this->assertEquals('super-signature', $api['secret'], 'secret entschlüsselt korrekt'); } // 3. FinTS-Quelle mit PIN $providerFints = Database::fetchOne("SELECT id FROM bank_providers WHERE verbindungstyp='FinTS' LIMIT 1"); if ($providerFints) { $fintsId = BankSource::create([ 'type' => 'fints', 'provider_id' => (int)$providerFints['id'], 'bezeichnung' => 'TestFinTS', 'blz' => '12030000', 'benutzerkennung' => 'kundennummer', 'pin' => 'g3h31m', ]); $this->assertGreaterThan(0, $fintsId, 'FinTS-Quelle wurde angelegt'); $raw = Database::fetchOne('SELECT pin_enc FROM bank_sources WHERE id = ?', [$fintsId]); $this->assert(str_starts_with($raw['pin_enc'], 'enc:v1:'), 'pin_enc ist verschlüsselt'); $fints = BankSource::find($fintsId); $this->assertEquals('g3h31m', $fints['pin'], 'PIN entschlüsselt korrekt'); $this->assertEquals('12030000', $fints['blz'], 'BLZ korrekt'); // 4. updateField mit Klartext-PIN → muss verschlüsselt landen BankSource::updateField($fintsId, 'pin', 'neue-pin'); $raw2 = Database::fetchOne('SELECT pin_enc FROM bank_sources WHERE id = ?', [$fintsId]); $this->assert(str_starts_with($raw2['pin_enc'], 'enc:v1:'), 'updateField verschlüsselt pin'); $fints2 = BankSource::find($fintsId); $this->assertEquals('neue-pin', $fints2['pin'], 'pin nach updateField wieder entschlüsselbar'); } // 5. Filter all('csv') liefert nur CSV-Einträge $allCsv = BankSource::all('csv'); foreach ($allCsv as $row) { $this->assertEquals('csv', $row['type'], 'all(csv) liefert nur csv-Einträge'); } // 6. Batch mit source_id anlegen funktioniert (FK) Database::execute( 'INSERT INTO bank_import_batches (source_id, filename, row_count) VALUES (?, ?, 0)', [$csvId, 'test-batch.csv'] ); $bid = (int)Database::lastInsertId(); $this->assertGreaterThan(0, $bid, 'Batch mit source_id angelegt'); } finally { if ($oldKey === null) { unset($_ENV['APP_KEY']); } else { $_ENV['APP_KEY'] = $oldKey; } Config::load(); } } }