318 lines
9.0 KiB
PHP
318 lines
9.0 KiB
PHP
<?php
|
|
|
|
namespace UbsCsvTransformer;
|
|
|
|
/**
|
|
* Firefly III Data Importer Integration
|
|
*
|
|
* Diese Klasse integriert den Firefly III Data Importer.
|
|
* Der Import erfolgt über die offizielle Firefly III Data Importer CLI.
|
|
*
|
|
* SETUP-VORAUSSETZUNGEN:
|
|
* ----------------------
|
|
*
|
|
* 1. Firefly III Data Importer installiert und konfiguriert
|
|
* - Docker: firefly/data-importer:latest
|
|
* - Oder: Standalone Installation
|
|
*
|
|
* 2. Import-Konfiguration erstellt (config.json):
|
|
* - In Firefly III Web-UI: Import → Configure
|
|
* - CSV-Format konfigurieren
|
|
* - JSON-Konfiguration herunterladen
|
|
* - Speichern als z.B.: /opt/firefly/configs/ubs-import.json
|
|
*
|
|
* 3. Umgebungsvariablen für Firefly Data Importer:
|
|
* - FIREFLY_III_URL=https://your-firefly-instance.com
|
|
* - FIREFLY_III_ACCESS_TOKEN=<personal_access_token>
|
|
* - VANITY_URL (optional)
|
|
*
|
|
* INTEGRATION IN config.yaml:
|
|
* ---------------------------
|
|
*
|
|
* fireflyImport:
|
|
* # Pfad zur JSON-Konfiguration (aus Firefly III exportiert)
|
|
* jsonConfig: '/opt/firefly/configs/ubs-import.json'
|
|
*
|
|
* # Firefly Data Importer Kommando
|
|
* # Option 1: Docker
|
|
* importerCommand: 'docker exec -it firefly-importer php artisan importer:import'
|
|
*
|
|
* # Option 2: Standalone
|
|
* # importerCommand: 'cd /opt/firefly-data-importer && php artisan importer:import'
|
|
*
|
|
* # Automatisch nach Transformation importieren?
|
|
* autoImport: true
|
|
*
|
|
* # Output-Datei nach erfolgreichem Import löschen?
|
|
* deleteAfterImport: true
|
|
*
|
|
* # Timeout für Import (Sekunden)
|
|
* timeout: 300
|
|
*
|
|
* # Environment-Variablen für Firefly Data Importer
|
|
* environment:
|
|
* FIREFLY_III_URL: 'https://your-firefly.com'
|
|
* FIREFLY_III_ACCESS_TOKEN: 'your-token-here'
|
|
*
|
|
* VERWENDUNG:
|
|
* -----------
|
|
*
|
|
* // Automatisch beim Auto-Import
|
|
* ./bin/transformer auto-import config/config.yaml
|
|
*
|
|
* // Oder manuell nach Transformation
|
|
* $importer = new FireflyImporter($config['fireflyImport']);
|
|
* $result = $importer->import('/path/to/transformed.csv');
|
|
*/
|
|
class FireflyImporter
|
|
{
|
|
private array $config;
|
|
private string $jsonConfigPath;
|
|
private string $importerCommand;
|
|
private bool $deleteAfterImport;
|
|
private array $environment;
|
|
|
|
/**
|
|
* @param array $config Firefly Import-Konfiguration aus config.yaml
|
|
* @throws \RuntimeException wenn Konfiguration ungültig
|
|
*/
|
|
public function __construct(array $config)
|
|
{
|
|
$this->config = $config;
|
|
|
|
// JSON-Konfigurationspfad validieren
|
|
$this->jsonConfigPath = $config['jsonConfig'] ?? '';
|
|
if (empty($this->jsonConfigPath)) {
|
|
throw new \RuntimeException("Firefly Import: 'jsonConfig' nicht konfiguriert");
|
|
}
|
|
|
|
if (!file_exists($this->jsonConfigPath)) {
|
|
throw new \RuntimeException("Firefly JSON-Konfiguration nicht gefunden: {$this->jsonConfigPath}");
|
|
}
|
|
|
|
// Importer-Kommando
|
|
$this->importerCommand = $config['importerCommand'] ?? '';
|
|
if (empty($this->importerCommand)) {
|
|
throw new \RuntimeException("Firefly Import: 'importerCommand' nicht konfiguriert");
|
|
}
|
|
|
|
// Optionale Einstellungen
|
|
$this->deleteAfterImport = $config['deleteAfterImport'] ?? false;
|
|
$this->environment = $config['environment'] ?? [];
|
|
}
|
|
|
|
/**
|
|
* Importiert eine transformierte CSV-Datei in Firefly III
|
|
*
|
|
* Der Import erfolgt über den Firefly III Data Importer CLI:
|
|
* php artisan importer:import <csv_file> <config_file>
|
|
*
|
|
* @param string $csvFile Pfad zur transformierten CSV-Datei
|
|
* @return array Import-Ergebnis mit Status und Ausgabe
|
|
*/
|
|
public function import(string $csvFile): array
|
|
{
|
|
if (!file_exists($csvFile)) {
|
|
return [
|
|
'success' => false,
|
|
'error' => "CSV-Datei nicht gefunden: {$csvFile}",
|
|
'output' => '',
|
|
'exit_code' => -1
|
|
];
|
|
}
|
|
|
|
// Kommando zusammenbauen
|
|
$command = $this->buildImportCommand($csvFile);
|
|
|
|
// Environment-Variablen setzen
|
|
$env = $this->buildEnvironment();
|
|
|
|
// Import ausführen
|
|
$output = [];
|
|
$exitCode = 0;
|
|
|
|
$startTime = microtime(true);
|
|
|
|
try {
|
|
// Kommando ausführen mit Timeout
|
|
$descriptors = [
|
|
0 => ["pipe", "r"], // stdin
|
|
1 => ["pipe", "w"], // stdout
|
|
2 => ["pipe", "w"] // stderr
|
|
];
|
|
|
|
$process = proc_open($command, $descriptors, $pipes, null, $env);
|
|
|
|
if (!is_resource($process)) {
|
|
throw new \RuntimeException("Konnte Import-Prozess nicht starten");
|
|
}
|
|
|
|
// stdin schließen
|
|
fclose($pipes[0]);
|
|
|
|
// stdout und stderr lesen
|
|
$stdout = stream_get_contents($pipes[1]);
|
|
$stderr = stream_get_contents($pipes[2]);
|
|
|
|
fclose($pipes[1]);
|
|
fclose($pipes[2]);
|
|
|
|
// Auf Prozess-Ende warten
|
|
$exitCode = proc_close($process);
|
|
|
|
$output = [
|
|
'stdout' => $stdout,
|
|
'stderr' => $stderr
|
|
];
|
|
|
|
$duration = microtime(true) - $startTime;
|
|
|
|
$success = ($exitCode === 0);
|
|
|
|
// Bei Erfolg: Optional CSV-Datei löschen
|
|
if ($success && $this->deleteAfterImport) {
|
|
@unlink($csvFile);
|
|
}
|
|
|
|
return [
|
|
'success' => $success,
|
|
'exit_code' => $exitCode,
|
|
'output' => $output,
|
|
'duration' => round($duration, 2),
|
|
'csv_file' => $csvFile,
|
|
'config_file' => $this->jsonConfigPath,
|
|
'deleted' => ($success && $this->deleteAfterImport)
|
|
];
|
|
} catch (\Exception $e) {
|
|
return [
|
|
'success' => false,
|
|
'error' => $e->getMessage(),
|
|
'output' => $output,
|
|
'exit_code' => $exitCode
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Baut das Import-Kommando zusammen
|
|
*
|
|
* @param string $csvFile Pfad zur CSV-Datei
|
|
* @return string Vollständiges Kommando
|
|
*/
|
|
private function buildImportCommand(string $csvFile): string
|
|
{
|
|
// Firefly Data Importer CLI-Format:
|
|
// php artisan importer:import <csv_file> <config_file>
|
|
|
|
return sprintf(
|
|
'%s %s %s',
|
|
$this->importerCommand,
|
|
escapeshellarg($csvFile),
|
|
escapeshellarg($this->jsonConfigPath)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Baut Environment-Variablen zusammen
|
|
*
|
|
* @return array|null Environment-Variablen oder null
|
|
*/
|
|
private function buildEnvironment(): ?array
|
|
{
|
|
if (empty($this->environment)) {
|
|
return null;
|
|
}
|
|
|
|
// Aktuelle Environment übernehmen und mit Custom-Vars erweitern
|
|
$env = $_ENV;
|
|
|
|
foreach ($this->environment as $key => $value) {
|
|
$env[$key] = $value;
|
|
}
|
|
|
|
return $env;
|
|
}
|
|
|
|
/**
|
|
* Testet die Firefly-Verbindung
|
|
*
|
|
* @return array Test-Ergebnis
|
|
*/
|
|
public function testConnection(): array
|
|
{
|
|
// Test ob Importer-Kommando verfügbar ist
|
|
$testCommand = str_replace('importer:import', '--version', $this->importerCommand);
|
|
|
|
exec($testCommand . ' 2>&1', $output, $exitCode);
|
|
|
|
return [
|
|
'available' => ($exitCode === 0),
|
|
'output' => implode("\n", $output),
|
|
'exit_code' => $exitCode
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Validiert die JSON-Konfiguration
|
|
*
|
|
* @return array Validierungsergebnis
|
|
*/
|
|
public function validateConfig(): array
|
|
{
|
|
if (!file_exists($this->jsonConfigPath)) {
|
|
return [
|
|
'valid' => false,
|
|
'error' => 'JSON-Konfiguration nicht gefunden'
|
|
];
|
|
}
|
|
|
|
$json = file_get_contents($this->jsonConfigPath);
|
|
if ($json === false) {
|
|
return [
|
|
'valid' => false,
|
|
'error' => 'Konfigurationsdatei nicht lesbar'
|
|
];
|
|
}
|
|
$config = json_decode($json, true);
|
|
|
|
if ($config === null) {
|
|
return [
|
|
'valid' => false,
|
|
'error' => 'Ungültiges JSON: ' . json_last_error_msg()
|
|
];
|
|
}
|
|
|
|
// Prüfe erforderliche Felder in Firefly-Config
|
|
$requiredFields = ['file_type', 'import_account'];
|
|
$missingFields = [];
|
|
|
|
foreach ($requiredFields as $field) {
|
|
if (!isset($config[$field])) {
|
|
$missingFields[] = $field;
|
|
}
|
|
}
|
|
|
|
if (!empty($missingFields)) {
|
|
return [
|
|
'valid' => false,
|
|
'error' => 'Fehlende Felder: ' . implode(', ', $missingFields)
|
|
];
|
|
}
|
|
|
|
return [
|
|
'valid' => true,
|
|
'config' => $config
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Gibt die Konfiguration zurück
|
|
*
|
|
* @return array Firefly Import-Konfiguration
|
|
*/
|
|
public function getConfig(): array
|
|
{
|
|
return $this->config;
|
|
}
|
|
}
|