# BankImport Modul - Entwicklernotizen

## Modul-Übersicht
- **Name**: BankImport
- **Version**: 3.5
- **Pfad**: `/srv/http/dolibarr/custom/bankimport/`
- **Funktion**: FinTS/HBCI Kontoauszüge importieren und mit Dolibarr-Rechnungen abgleichen

## Wichtige Dateien

| Datei | Funktion |
|-------|----------|
| `class/banktransaction.class.php` | Hauptklasse für Transaktionen, findMatches(), confirmMultiplePayment() |
| `confirm.php` | Übersicht aller Matches zur Bestätigung |
| `card.php` | Einzelansicht einer Transaktion mit manueller Zuordnung |
| `repair.php` | Admin-Seite für verwaiste Transaktionen |
| `cron/bankimport.cron.php` | Cronjob für automatischen Import |
| `admin/cronmonitor.php` | Cron-Monitoring und Pause/Resume |
| `pdfstatements.php` | PDF-Kontoauszüge hochladen und per FinTS abrufen |
| `vendor/.../Segment/EKP/*` | HKEKP-Segmente für PDF-Abruf (direkt) |
| `vendor/.../Segment/KAA/*` | HKKAA-Segmente für PDF-Abruf (Archiv) |
| `vendor/.../Action/GetStatementPDF.php` | Action-Klasse für HKEKP |
| `vendor/.../Action/GetStatementFromArchive.php` | Action-Klasse für HKKAA |

## PDF-Kontoauszüge per FinTS

### Übersicht
Seit Version 3.5 können PDF-Kontoauszüge von der Bank abgerufen werden. Es gibt zwei Methoden:

| Methode | Segment | Beschreibung | Bank-Beispiele |
|---------|---------|--------------|----------------|
| **HKEKP** | Elektronischer Kontoauszug PDF | Direkt-Abruf | Sparkassen, einige Volksbanken |
| **HKKAA** | Kontoauszug aus Archiv | Abruf aus Bank-Postfach | VR Banken (z.B. VR Bank Schleswig-Holstein) |

Das System wählt automatisch die beste verfügbare Methode.

### Neue Dateien in php-fints
```
vendor/nemiah/php-fints/lib/Fhp/
├── Action/
│   ├── GetStatementPDF.php        # HKEKP Action
│   └── GetStatementFromArchive.php # HKKAA Action
└── Segment/
    ├── EKP/                        # HKEKP Segmente
    │   ├── HKEKPv2.php
    │   ├── HIEKPv2.php
    │   └── ...
    └── KAA/                        # HKKAA Segmente
        ├── HKKAAv2.php
        ├── HIKAAv2.php
        ├── HIKAASv1.php
        └── ParameterKontoauszugArchiv.php
```

### Verwendung (empfohlen: Auto-Modus)
```php
$fints = new BankImportFinTS($db);
$fints->login();

// Automatische Methodenwahl
$method = $fints->getPdfStatementMethod();  // 'HKEKP', 'HKKAA' oder false
if ($method) {
    $result = $fints->getStatementPDFAuto(0);
    if (is_array($result) && !empty($result['pdfData'])) {
        $pdfData = $result['pdfData'];
        $info = $result['info'];
        $usedMethod = $result['method'];  // 'HKEKP' oder 'HKKAA'
    }
}
```

### Cronjob
- Aktivieren: `BANKIMPORT_PDF_AUTO_ENABLED = 1`
- Klasse: `BankImportCron::doAutoFetchPdf()`
- Frequenz: Wie Transaktions-Import konfigurierbar

## Multi-Invoice Matching (Sammelzahlungen)

### Ablauf
1. `findMatches()` sucht Einzelmatches und Multi-Matches
2. `findSupplierForMultiMatch()` findet Lieferant über IBAN oder Name (Similarity > 70%)
3. `findMultipleSupplierInvoiceMatches()` kombiniert Rechnungen deren ref_supplier im Buchungstext steht
4. Toleranz: **3% des Betrags** (für Skonto)

### Sortierung
Matches werden sortiert nach:
1. Betragsnähe (innerhalb 10% Threshold bevorzugt)
2. Score (Multi-Match: 98-100, Einzelmatch: variabel)

### Skonto-Verarbeitung
In `confirmMultiplePayment()`:
1. Wenn gezahlter Betrag < Rechnungssumme (max 5% Abweichung)
2. Zahlungen werden proportional verteilt (`discountFactor = actualAmount / totalPayment`)
3. Rechnungen werden mit `setPaid($user, 'discount_vat', 'Skonto (X EUR)')` geschlossen

## Datenbank-Struktur

### llx_bankimport_transaction
| Feld | Bedeutung |
|------|-----------|
| `status` | 0=Neu, 1=Zugeordnet, 2=Abgestimmt, 9=Ignoriert |
| `fk_facture_fourn` | Verknüpfte Lieferantenrechnung (erste bei Multi) |
| `fk_paiementfourn` | Verknüpfte Zahlung |
| `fk_bank` | Verknüpfter Bank-Eintrag |
| `note_private` | Multi-invoice payment: SI..., SI..., SI... (Skonto: X EUR) |

### Rechnung (close_code)
| Code | Bedeutung |
|------|-----------|
| `NULL` | Normal bezahlt |
| `discount_vat` | Mit Skonto bezahlt |
| `badsupplier` | Zahlungsausfall |
| `abandon` | Aufgegeben |

## Bekannte Edge Cases

### Problem: Nur 1 statt 3 Rechnungen bestätigt
- **Ursache**: Multi-Match hatte niedrigeren Score als Einzelmatch
- **Lösung**: Score auf 98 erhöht + Sortierung nach Betragsnähe

### Problem: Skonto nicht erkannt
- **Ursache**: Toleranz war 5€ fix, Skonto war 6,29€
- **Lösung**: Toleranz auf 3% des Betrags geändert

### Problem: Bezahlte Rechnungen nicht in Liste
- **Ursache**: Filter prüfte payment.fk_bank statt BankImport-Verknüpfung
- **Lösung**: Nur `llx_bankimport_transaction.status > 0` prüfen

## Test-Datenbank
- **Host**: 192.168.155.1 (Produktiv) / 192.168.155.11 (Test)
- **User**: dolibarr
- **Passwort**: 8715

## Typische Debug-Queries

```sql
-- Transaktion mit Verknüpfungen
SELECT rowid, ref, amount, status, fk_facture_fourn, fk_paiementfourn, fk_bank, note_private
FROM llx_bankimport_transaction WHERE rowid = X;

-- Zahlungsverteilung prüfen
SELECT pf.fk_paiementfourn, pf.fk_facturefourn, pf.amount, f.ref
FROM llx_paiementfourn_facturefourn pf
JOIN llx_facture_fourn f ON f.rowid = pf.fk_facturefourn
WHERE pf.fk_paiementfourn = X;

-- Rechnungen mit Skonto-Status
SELECT rowid, ref, total_ttc, fk_statut, paye, close_code, close_note
FROM llx_facture_fourn WHERE rowid IN (X, Y, Z);
```

## Zurücksetzen einer Transaktion (für Tests)

```sql
-- 1. Zahlung-Rechnung Verknüpfung löschen
DELETE FROM llx_paiementfourn_facturefourn WHERE fk_paiementfourn = X;

-- 2. Bank-URL löschen
DELETE FROM llx_bank_url WHERE url_id = X AND type = 'payment_supplier';

-- 3. Zahlung löschen
DELETE FROM llx_paiementfourn WHERE rowid = X;

-- 4. Bank-Eintrag löschen
DELETE FROM llx_bank WHERE rowid = Y;

-- 5. Rechnung(en) auf offen setzen
UPDATE llx_facture_fourn SET fk_statut = 1, paye = 0, close_code = NULL, close_note = NULL WHERE rowid IN (...);

-- 6. BankImport-Transaktion zurücksetzen
UPDATE llx_bankimport_transaction
SET status = 0, fk_facture_fourn = NULL, fk_paiementfourn = NULL, fk_bank = NULL,
    fk_user_match = NULL, date_match = NULL
WHERE rowid = Z;
```
