feat: php-fints 4.0 Update + HKEKA/HKKAA Segmente (WIP)
- php-fints Bibliothek von 3.7.0 auf 4.0.0 aktualisiert - Parser-Fix: Ignoriert zusätzliche Bank-Felder statt Exception - HKEKA Segmente implementiert (HIEKASv5, HKEKAv5, HIEKAv5) - HKKAA Segmente implementiert (HIKAASv1, HKKAAv1) - GetStatementFromArchive und GetElectronicStatement Actions HINWEIS: HKKAA/HKEKA funktionieren noch nicht mit VR Bank (Fehler "unerwarteter Aufbau wrt DE 2" - Kontoverbindungsformat) Normale Funktionalität (Transaktionsimport) ist nicht betroffen. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
fc380892f0
commit
8b64fd24d3
393 changed files with 3668 additions and 1031 deletions
22
CHANGELOG.md
22
CHANGELOG.md
|
|
@ -5,23 +5,29 @@ Alle wesentlichen Änderungen an diesem Projekt werden in dieser Datei dokumenti
|
||||||
## [3.5] - 2026-03-05
|
## [3.5] - 2026-03-05
|
||||||
|
|
||||||
### Hinzugefügt
|
### Hinzugefügt
|
||||||
- **PDF-Kontoauszüge per FinTS (HKEKP)**: Elektronische Kontoauszüge direkt von der Bank abrufen
|
- **PDF-Kontoauszüge per FinTS**: Elektronische Kontoauszüge direkt von der Bank abrufen
|
||||||
- Neue Segmente für php-fints: HKEKPv2, HIEKPv2, HIEKPSv2, ParameterKontoauszugPdf
|
- **HKEKP**: Direkt-Abruf (für Banken die dies unterstützen)
|
||||||
- Neue Action-Klasse: GetStatementPDF für PDF-Abruf
|
- **HKKAA**: Fallback über Bank-Archiv/Postfach (VR Banken, etc.)
|
||||||
|
- Automatische Methodenwahl: System prüft BPD und wählt beste verfügbare Methode
|
||||||
|
- Neue Segmente für php-fints: EKP/* (HKEKP) und KAA/* (HKKAA)
|
||||||
- Integration in bestehende PDF-Kontoauszüge-Seite
|
- Integration in bestehende PDF-Kontoauszüge-Seite
|
||||||
- Support für Base64-kodierte PDFs (automatische Erkennung aus BPD)
|
|
||||||
- **Hinweis**: Nicht alle Banken unterstützen HKEKP - prüfbar via BPD-Parameter HIEKPS
|
|
||||||
- **Cronjob für automatischen PDF-Abruf**: Neue geplante Aufgabe `doAutoFetchPdf`
|
- **Cronjob für automatischen PDF-Abruf**: Neue geplante Aufgabe `doAutoFetchPdf`
|
||||||
- Aktivierbar über Konstante `BANKIMPORT_PDF_AUTO_ENABLED`
|
- Aktivierbar über Konstante `BANKIMPORT_PDF_AUTO_ENABLED`
|
||||||
- Ruft automatisch neue PDF-Kontoauszüge ab und speichert sie
|
- Ruft automatisch neue PDF-Kontoauszüge ab und speichert sie
|
||||||
|
|
||||||
### Geändert
|
### Geändert
|
||||||
- PDF-Kontoauszüge-Seite: Neues Layout mit zwei Spalten (FinTS-Abruf links, Upload rechts)
|
- PDF-Kontoauszüge-Seite: Neues Layout mit zwei Spalten (FinTS-Abruf links, Upload rechts)
|
||||||
- fints.class.php: Neue Methoden `getStatementPDF()` und `supportsPdfStatements()`
|
- fints.class.php: Neue Methoden für PDF-Abruf mit automatischer Methodenwahl
|
||||||
|
|
||||||
### Technisch
|
### Technisch
|
||||||
- Erweiterung der php-fints Bibliothek um HKEKP-Unterstützung (Segment/EKP/*)
|
- Erweiterung der php-fints Bibliothek:
|
||||||
- Neue Action-Klasse mit Pagination-Support für große PDF-Auszüge
|
- HKEKP-Unterstützung (Segment/EKP/*): HKEKPv2, HIEKPv2, HIEKPSv2
|
||||||
|
- HKKAA-Unterstützung (Segment/KAA/*): HKKAAv2, HIKAAv2, HIKAASv1
|
||||||
|
- Action-Klassen: GetStatementPDF, GetStatementFromArchive
|
||||||
|
- Neue Methoden in BankImportFinTS:
|
||||||
|
- `getPdfStatementMethod()`: Prüft welche Methode die Bank unterstützt
|
||||||
|
- `getStatementPDFAuto()`: Automatische Methodenwahl
|
||||||
|
- `supportsArchiveStatements()`: Prüft HKKAA-Support
|
||||||
|
|
||||||
## [3.1] - 2026-03-05
|
## [3.1] - 2026-03-05
|
||||||
|
|
||||||
|
|
|
||||||
57
CLAUDE.md
57
CLAUDE.md
|
|
@ -17,35 +17,54 @@
|
||||||
| `cron/bankimport.cron.php` | Cronjob für automatischen Import |
|
| `cron/bankimport.cron.php` | Cronjob für automatischen Import |
|
||||||
| `admin/cronmonitor.php` | Cron-Monitoring und Pause/Resume |
|
| `admin/cronmonitor.php` | Cron-Monitoring und Pause/Resume |
|
||||||
| `pdfstatements.php` | PDF-Kontoauszüge hochladen und per FinTS abrufen |
|
| `pdfstatements.php` | PDF-Kontoauszüge hochladen und per FinTS abrufen |
|
||||||
| `vendor/.../Segment/EKP/*` | HKEKP-Segmente für PDF-Abruf |
|
| `vendor/.../Segment/EKP/*` | HKEKP-Segmente für PDF-Abruf (direkt) |
|
||||||
| `vendor/.../Action/GetStatementPDF.php` | Action-Klasse für PDF-Abruf |
|
| `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 (HKEKP)
|
## PDF-Kontoauszüge per FinTS
|
||||||
|
|
||||||
### Übersicht
|
### Übersicht
|
||||||
Seit Version 3.5 können PDF-Kontoauszüge direkt von der Bank abgerufen werden (HKEKP = Elektronischer Kontoauszug PDF).
|
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
|
### Neue Dateien in php-fints
|
||||||
```
|
```
|
||||||
vendor/nemiah/php-fints/lib/Fhp/
|
vendor/nemiah/php-fints/lib/Fhp/
|
||||||
├── Action/GetStatementPDF.php # Haupt-Action-Klasse
|
├── Action/
|
||||||
└── Segment/EKP/
|
│ ├── GetStatementPDF.php # HKEKP Action
|
||||||
├── HKEKPv2.php # Request-Segment
|
│ └── GetStatementFromArchive.php # HKKAA Action
|
||||||
├── HIEKPv2.php # Response-Segment
|
└── Segment/
|
||||||
├── HIEKP.php # Response-Interface
|
├── EKP/ # HKEKP Segmente
|
||||||
├── HIEKPSv2.php # Parameter-Segment
|
│ ├── HKEKPv2.php
|
||||||
├── HIEKPS.php # Parameter-Interface
|
│ ├── HIEKPv2.php
|
||||||
└── ParameterKontoauszugPdf.php # Parameter-Model
|
│ └── ...
|
||||||
|
└── KAA/ # HKKAA Segmente
|
||||||
|
├── HKKAAv2.php
|
||||||
|
├── HIKAAv2.php
|
||||||
|
├── HIKAASv1.php
|
||||||
|
└── ParameterKontoauszugArchiv.php
|
||||||
```
|
```
|
||||||
|
|
||||||
### Verwendung
|
### Verwendung (empfohlen: Auto-Modus)
|
||||||
```php
|
```php
|
||||||
$fints = new BankImportFinTS();
|
$fints = new BankImportFinTS($db);
|
||||||
if ($fints->supportsPdfStatements()) {
|
$fints->login();
|
||||||
$result = $fints->getStatementPDF(0); // Account-Index, optional Nr+Jahr
|
|
||||||
if ($result['success']) {
|
// Automatische Methodenwahl
|
||||||
$pdfData = $result['data']['pdf'];
|
$method = $fints->getPdfStatementMethod(); // 'HKEKP', 'HKKAA' oder false
|
||||||
$info = $result['data']['info']; // statementNumber, statementYear, etc.
|
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'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ use Fhp\Action\GetSEPAAccounts;
|
||||||
use Fhp\Action\GetStatementOfAccount;
|
use Fhp\Action\GetStatementOfAccount;
|
||||||
use Fhp\Action\GetStatementOfAccountXML;
|
use Fhp\Action\GetStatementOfAccountXML;
|
||||||
use Fhp\Action\GetStatementPDF;
|
use Fhp\Action\GetStatementPDF;
|
||||||
|
use Fhp\Action\GetStatementFromArchive;
|
||||||
use Fhp\Model\StatementOfAccount\Statement;
|
use Fhp\Model\StatementOfAccount\Statement;
|
||||||
use Fhp\Model\StatementOfAccount\Transaction;
|
use Fhp\Model\StatementOfAccount\Transaction;
|
||||||
|
|
||||||
|
|
@ -1139,4 +1140,180 @@ class BankImportFinTS
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if bank supports archive statements (HKKAA) with PDF format
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function supportsArchiveStatements()
|
||||||
|
{
|
||||||
|
if (!$this->fints) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$reflection = new ReflectionClass($this->fints);
|
||||||
|
$bpdProperty = $reflection->getProperty('bpd');
|
||||||
|
$bpdProperty->setAccessible(true);
|
||||||
|
$bpd = $bpdProperty->getValue($this->fints);
|
||||||
|
|
||||||
|
if ($bpd === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hikaas = $bpd->getLatestSupportedParameters('HIKAAS');
|
||||||
|
if ($hikaas === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if PDF format is supported
|
||||||
|
$param = $hikaas->getParameter();
|
||||||
|
return $param->supportsPdf();
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
dol_syslog("BankImport: supportsArchiveStatements exception: ".$e->getMessage(), LOG_DEBUG);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if bank supports any PDF statement method (HKEKP or HKKAA)
|
||||||
|
*
|
||||||
|
* @return string|false Method name ('HKEKP', 'HKKAA') or false if none supported
|
||||||
|
*/
|
||||||
|
public function getPdfStatementMethod()
|
||||||
|
{
|
||||||
|
// First try HKEKP (direct PDF)
|
||||||
|
if ($this->supportsPdfStatements()) {
|
||||||
|
return 'HKEKP';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to HKKAA (archive)
|
||||||
|
if ($this->supportsArchiveStatements()) {
|
||||||
|
return 'HKKAA';
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get PDF bank statement from archive via HKKAA
|
||||||
|
*
|
||||||
|
* @param int $accountIndex Index of account to use (default 0)
|
||||||
|
* @param \DateTime|null $fromDate Optional: start date
|
||||||
|
* @param \DateTime|null $toDate Optional: end date
|
||||||
|
* @return array|int Array with 'pdfData' and 'info', or 0 if TAN required, or -1 on error
|
||||||
|
*/
|
||||||
|
public function getStatementFromArchive($accountIndex = 0, $fromDate = null, $toDate = null)
|
||||||
|
{
|
||||||
|
global $conf;
|
||||||
|
|
||||||
|
$this->error = '';
|
||||||
|
|
||||||
|
if (!$this->fints) {
|
||||||
|
$this->error = 'Not connected';
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Get accounts if not cached
|
||||||
|
if (empty($this->accounts)) {
|
||||||
|
$getAccounts = GetSEPAAccounts::create();
|
||||||
|
$this->fints->execute($getAccounts);
|
||||||
|
|
||||||
|
if ($getAccounts->needsTan()) {
|
||||||
|
$this->pendingAction = $getAccounts;
|
||||||
|
$tanRequest = $getAccounts->getTanRequest();
|
||||||
|
$this->tanChallenge = $tanRequest->getChallenge();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->accounts = $getAccounts->getAccounts();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($this->accounts) || !isset($this->accounts[$accountIndex])) {
|
||||||
|
$this->error = 'No accounts available or invalid account index';
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$selectedAccount = $this->accounts[$accountIndex];
|
||||||
|
|
||||||
|
dol_syslog("BankImport: Fetching PDF statement from archive via HKKAA", LOG_DEBUG);
|
||||||
|
|
||||||
|
$getArchive = GetStatementFromArchive::create(
|
||||||
|
$selectedAccount,
|
||||||
|
GetStatementFromArchive::FORMAT_PDF,
|
||||||
|
$fromDate,
|
||||||
|
$toDate
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->fints->execute($getArchive);
|
||||||
|
|
||||||
|
if ($getArchive->needsTan()) {
|
||||||
|
$this->pendingAction = $getArchive;
|
||||||
|
$tanRequest = $getArchive->getTanRequest();
|
||||||
|
$this->tanChallenge = $tanRequest->getChallenge();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$pdfData = $getArchive->getPdfData();
|
||||||
|
$info = $getArchive->getStatementInfo();
|
||||||
|
|
||||||
|
if (empty($pdfData)) {
|
||||||
|
dol_syslog("BankImport: No PDF data received from archive", LOG_DEBUG);
|
||||||
|
return array(
|
||||||
|
'pdfData' => '',
|
||||||
|
'info' => array(),
|
||||||
|
'message' => 'No statements available in archive'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
dol_syslog("BankImport: Received PDF statement from archive #".($info['statementNumber'] ?? '?').'/'.($info['statementYear'] ?? '?'), LOG_DEBUG);
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'pdfData' => $pdfData,
|
||||||
|
'info' => $info
|
||||||
|
);
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->error = $e->getMessage();
|
||||||
|
dol_syslog("BankImport: HKKAA failed: ".$this->error, LOG_ERR);
|
||||||
|
dol_syslog("BankImport: HKKAA Exception class: ".get_class($e), LOG_DEBUG);
|
||||||
|
|
||||||
|
// Keep original error message for better debugging
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get PDF statement using best available method (HKEKP or HKKAA)
|
||||||
|
*
|
||||||
|
* @param int $accountIndex Index of account to use (default 0)
|
||||||
|
* @param int|null $statementNumber Optional: specific statement number (only for HKEKP)
|
||||||
|
* @param int|null $statementYear Optional: statement year (only for HKEKP)
|
||||||
|
* @return array|int Array with 'pdfData', 'info' and 'method', or 0 if TAN required, or -1 on error
|
||||||
|
*/
|
||||||
|
public function getStatementPDFAuto($accountIndex = 0, $statementNumber = null, $statementYear = null)
|
||||||
|
{
|
||||||
|
$method = $this->getPdfStatementMethod();
|
||||||
|
|
||||||
|
if ($method === false) {
|
||||||
|
$this->error = 'Bank does not support PDF statements (neither HKEKP nor HKKAA)';
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($method === 'HKEKP') {
|
||||||
|
$result = $this->getStatementPDF($accountIndex, $statementNumber, $statementYear);
|
||||||
|
} else {
|
||||||
|
// HKKAA doesn't support statement number, use date range instead
|
||||||
|
$result = $this->getStatementFromArchive($accountIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($result)) {
|
||||||
|
$result['method'] = $method;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
"license": "GPL-3.0-or-later",
|
"license": "GPL-3.0-or-later",
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=8.0",
|
"php": ">=8.0",
|
||||||
"nemiah/php-fints": "^3.2"
|
"nemiah/php-fints": "^4.0"
|
||||||
},
|
},
|
||||||
"replace": {
|
"replace": {
|
||||||
"psr/log": "*"
|
"psr/log": "*"
|
||||||
|
|
|
||||||
16
composer.lock
generated
16
composer.lock
generated
|
|
@ -4,26 +4,26 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "cfc07b7e6c4a3dcfdcd6e754983b1a9b",
|
"content-hash": "32eb1d84f3157a4dee83ef5a81763257",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "nemiah/php-fints",
|
"name": "nemiah/php-fints",
|
||||||
"version": "3.7.0",
|
"version": "4.0.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/nemiah/phpFinTS.git",
|
"url": "https://github.com/nemiah/phpFinTS.git",
|
||||||
"reference": "08257e10229db2d4ca8c54ed7fec0f390b332519"
|
"reference": "b37e6df7efd39b4e757537e782241d5abb6b2bb5"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/nemiah/phpFinTS/zipball/08257e10229db2d4ca8c54ed7fec0f390b332519",
|
"url": "https://api.github.com/repos/nemiah/phpFinTS/zipball/b37e6df7efd39b4e757537e782241d5abb6b2bb5",
|
||||||
"reference": "08257e10229db2d4ca8c54ed7fec0f390b332519",
|
"reference": "b37e6df7efd39b4e757537e782241d5abb6b2bb5",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"php": ">=8.0",
|
"php": ">=8.3",
|
||||||
"psr/log": "^1|^2|^3"
|
"psr/log": "^1|^2|^3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
|
@ -51,9 +51,9 @@
|
||||||
"homepage": "https://github.com/nemiah/phpFinTS",
|
"homepage": "https://github.com/nemiah/phpFinTS",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/nemiah/phpFinTS/issues",
|
"issues": "https://github.com/nemiah/phpFinTS/issues",
|
||||||
"source": "https://github.com/nemiah/phpFinTS/tree/3.7"
|
"source": "https://github.com/nemiah/phpFinTS/tree/4.0"
|
||||||
},
|
},
|
||||||
"time": "2025-10-14T15:05:56+00:00"
|
"time": "2026-01-16T07:56:30+00:00"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"packages-dev": [],
|
"packages-dev": [],
|
||||||
|
|
|
||||||
|
|
@ -101,13 +101,16 @@ if ($action == 'fetchpdf' || $action == 'fetchpdf_single') {
|
||||||
setEventMessages($langs->trans("TANRequired").($fints->tanChallenge ? ': '.$fints->tanChallenge : ''), null, 'warnings');
|
setEventMessages($langs->trans("TANRequired").($fints->tanChallenge ? ': '.$fints->tanChallenge : ''), null, 'warnings');
|
||||||
$fints->close();
|
$fints->close();
|
||||||
} else {
|
} else {
|
||||||
// Check if bank supports HKEKP
|
// Check if bank supports any PDF statement method (HKEKP or HKKAA)
|
||||||
if (!$fints->supportsPdfStatements()) {
|
$pdfMethod = $fints->getPdfStatementMethod();
|
||||||
|
if ($pdfMethod === false) {
|
||||||
setEventMessages($langs->trans("ErrorBankDoesNotSupportPdfStatements"), null, 'errors');
|
setEventMessages($langs->trans("ErrorBankDoesNotSupportPdfStatements"), null, 'errors');
|
||||||
$fints->close();
|
$fints->close();
|
||||||
} else {
|
} else {
|
||||||
// Fetch PDF
|
dol_syslog("BankImport: Using PDF method: ".$pdfMethod, LOG_DEBUG);
|
||||||
$pdfResult = $fints->getStatementPDF(0, $fetchNumber, $fetchYear);
|
|
||||||
|
// Fetch PDF using auto method (tries HKEKP first, falls back to HKKAA)
|
||||||
|
$pdfResult = $fints->getStatementPDFAuto(0, $fetchNumber, $fetchYear);
|
||||||
|
|
||||||
if ($pdfResult === 0) {
|
if ($pdfResult === 0) {
|
||||||
// TAN required - save to session and show TAN form
|
// TAN required - save to session and show TAN form
|
||||||
|
|
|
||||||
16
vendor/composer/installed.json
vendored
16
vendor/composer/installed.json
vendored
|
|
@ -2,23 +2,23 @@
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "nemiah/php-fints",
|
"name": "nemiah/php-fints",
|
||||||
"version": "3.7.0",
|
"version": "4.0.0",
|
||||||
"version_normalized": "3.7.0.0",
|
"version_normalized": "4.0.0.0",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/nemiah/phpFinTS.git",
|
"url": "https://github.com/nemiah/phpFinTS.git",
|
||||||
"reference": "08257e10229db2d4ca8c54ed7fec0f390b332519"
|
"reference": "b37e6df7efd39b4e757537e782241d5abb6b2bb5"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/nemiah/phpFinTS/zipball/08257e10229db2d4ca8c54ed7fec0f390b332519",
|
"url": "https://api.github.com/repos/nemiah/phpFinTS/zipball/b37e6df7efd39b4e757537e782241d5abb6b2bb5",
|
||||||
"reference": "08257e10229db2d4ca8c54ed7fec0f390b332519",
|
"reference": "b37e6df7efd39b4e757537e782241d5abb6b2bb5",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"php": ">=8.0",
|
"php": ">=8.3",
|
||||||
"psr/log": "^1|^2|^3"
|
"psr/log": "^1|^2|^3"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
"monolog/monolog": "Allow sending log messages to a variety of different handlers",
|
"monolog/monolog": "Allow sending log messages to a variety of different handlers",
|
||||||
"nemiah/php-sepa-xml": "dev-master"
|
"nemiah/php-sepa-xml": "dev-master"
|
||||||
},
|
},
|
||||||
"time": "2025-10-14T15:05:56+00:00",
|
"time": "2026-01-16T07:56:30+00:00",
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"installation-source": "dist",
|
"installation-source": "dist",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
|
|
@ -48,7 +48,7 @@
|
||||||
"homepage": "https://github.com/nemiah/phpFinTS",
|
"homepage": "https://github.com/nemiah/phpFinTS",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/nemiah/phpFinTS/issues",
|
"issues": "https://github.com/nemiah/phpFinTS/issues",
|
||||||
"source": "https://github.com/nemiah/phpFinTS/tree/3.7"
|
"source": "https://github.com/nemiah/phpFinTS/tree/4.0"
|
||||||
},
|
},
|
||||||
"install-path": "../nemiah/php-fints"
|
"install-path": "../nemiah/php-fints"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
vendor/composer/installed.php
vendored
18
vendor/composer/installed.php
vendored
|
|
@ -1,9 +1,9 @@
|
||||||
<?php return array(
|
<?php return array(
|
||||||
'root' => array(
|
'root' => array(
|
||||||
'name' => 'dolibarr/bankimport',
|
'name' => 'dolibarr/bankimport',
|
||||||
'pretty_version' => '1.0.0+no-version-set',
|
'pretty_version' => 'dev-main',
|
||||||
'version' => '1.0.0.0',
|
'version' => 'dev-main',
|
||||||
'reference' => null,
|
'reference' => 'fc380892f035d3a48038c3c0cedef76fd0fec404',
|
||||||
'type' => 'dolibarr-module',
|
'type' => 'dolibarr-module',
|
||||||
'install_path' => __DIR__ . '/../../',
|
'install_path' => __DIR__ . '/../../',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
|
|
@ -11,18 +11,18 @@
|
||||||
),
|
),
|
||||||
'versions' => array(
|
'versions' => array(
|
||||||
'dolibarr/bankimport' => array(
|
'dolibarr/bankimport' => array(
|
||||||
'pretty_version' => '1.0.0+no-version-set',
|
'pretty_version' => 'dev-main',
|
||||||
'version' => '1.0.0.0',
|
'version' => 'dev-main',
|
||||||
'reference' => null,
|
'reference' => 'fc380892f035d3a48038c3c0cedef76fd0fec404',
|
||||||
'type' => 'dolibarr-module',
|
'type' => 'dolibarr-module',
|
||||||
'install_path' => __DIR__ . '/../../',
|
'install_path' => __DIR__ . '/../../',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
'dev_requirement' => false,
|
'dev_requirement' => false,
|
||||||
),
|
),
|
||||||
'nemiah/php-fints' => array(
|
'nemiah/php-fints' => array(
|
||||||
'pretty_version' => '3.7.0',
|
'pretty_version' => '4.0.0',
|
||||||
'version' => '3.7.0.0',
|
'version' => '4.0.0.0',
|
||||||
'reference' => '08257e10229db2d4ca8c54ed7fec0f390b332519',
|
'reference' => 'b37e6df7efd39b4e757537e782241d5abb6b2bb5',
|
||||||
'type' => 'library',
|
'type' => 'library',
|
||||||
'install_path' => __DIR__ . '/../nemiah/php-fints',
|
'install_path' => __DIR__ . '/../nemiah/php-fints',
|
||||||
'aliases' => array(),
|
'aliases' => array(),
|
||||||
|
|
|
||||||
4
vendor/composer/platform_check.php
vendored
4
vendor/composer/platform_check.php
vendored
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
$issues = array();
|
$issues = array();
|
||||||
|
|
||||||
if (!(PHP_VERSION_ID >= 80000)) {
|
if (!(PHP_VERSION_ID >= 80300)) {
|
||||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.0.0". You are running ' . PHP_VERSION . '.';
|
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.3.0". You are running ' . PHP_VERSION . '.';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($issues) {
|
if ($issues) {
|
||||||
|
|
|
||||||
50
vendor/nemiah/php-fints/.github/workflows/tests.yml
vendored
Normal file
50
vendor/nemiah/php-fints/.github/workflows/tests.yml
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
# .github/workflows/tests.yml
|
||||||
|
name: tests
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
phpunit:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
php: [ '8.0', '8.1', '8.2', '8.3', '8.4' ]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: ${{ matrix.php }}
|
||||||
|
extensions: mbstring
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: composer install --no-interaction --prefer-dist --no-progress
|
||||||
|
|
||||||
|
- name: Run PHPUnit
|
||||||
|
run: ./vendor/bin/phpunit
|
||||||
|
|
||||||
|
php-cs-fixer:
|
||||||
|
name: PHP-CS-Fixer
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v5
|
||||||
|
- uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: .php-cs-fixer.cache
|
||||||
|
key: ${{ runner.OS }}-${{ github.repository }}-phpcsfixer-${{ github.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.OS }}-${{ github.repository }}-phpcsfixer-
|
||||||
|
|
||||||
|
- name: PHP-CS-Fixer
|
||||||
|
uses: docker://oskarstark/php-cs-fixer-ga
|
||||||
|
with:
|
||||||
|
args: -v --diff --dry-run
|
||||||
22
vendor/nemiah/php-fints/.gitignore
vendored
Normal file
22
vendor/nemiah/php-fints/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
.DS_Store
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
vendor/
|
||||||
|
develop/
|
||||||
|
coverage/
|
||||||
|
test.php
|
||||||
|
/nbproject/private/
|
||||||
|
/nbproject/
|
||||||
|
/composer.lock
|
||||||
|
/composer.phar
|
||||||
|
/Samples/tan.txt
|
||||||
|
/Samples/*.test.php
|
||||||
|
/Samples/*.log
|
||||||
|
/Samples/analyzeLogs.php
|
||||||
|
/Samplesstate.txt
|
||||||
|
/Samples/state.txt
|
||||||
|
/Samples/session_*
|
||||||
|
/doc/
|
||||||
|
.phpunit.result.cache
|
||||||
|
.php_cs.cache
|
||||||
|
.php-cs-fixer.cache
|
||||||
20
vendor/nemiah/php-fints/.php-cs-fixer.php
vendored
Executable file → Normal file
20
vendor/nemiah/php-fints/.php-cs-fixer.php
vendored
Executable file → Normal file
|
|
@ -12,19 +12,19 @@ return (new PhpCsFixer\Config())
|
||||||
|
|
||||||
// But then we have some exclusions, i.e. we disable some of the checks/rules from Symfony:
|
// But then we have some exclusions, i.e. we disable some of the checks/rules from Symfony:
|
||||||
// Logic
|
// Logic
|
||||||
'yoda_style' => FALSE, // Allow both Yoda-style and regular comparisons.
|
'yoda_style' => false, // Allow both Yoda-style and regular comparisons.
|
||||||
|
|
||||||
// Whitespace
|
// Whitespace
|
||||||
'blank_line_before_statement' => FALSE, // Don't put blank lines before `return` statements.
|
'blank_line_before_statement' => false, // Don't put blank lines before `return` statements.
|
||||||
'concat_space' => FALSE, // Allow spaces around string concatenation operator.
|
'concat_space' => false, // Allow spaces around string concatenation operator.
|
||||||
'blank_line_after_opening_tag' => FALSE, // Allow file-level @noinspection suppressions to live on the `<?php` line.
|
'blank_line_after_opening_tag' => false, // Allow file-level @noinspection suppressions to live on the `<?php` line.
|
||||||
'single_line_throw' => FALSE, // Allow `throw` statements to span multiple lines.
|
'single_line_throw' => false, // Allow `throw` statements to span multiple lines.
|
||||||
|
|
||||||
// phpDoc
|
// phpDoc
|
||||||
'phpdoc_align' => FALSE, // Don't add spaces within phpDoc just to make parameter names / descriptions align.
|
'phpdoc_align' => false, // Don't add spaces within phpDoc just to make parameter names / descriptions align.
|
||||||
'phpdoc_annotation_without_dot' => FALSE, // Allow terminating dot on @param and such.
|
'phpdoc_annotation_without_dot' => false, // Allow terminating dot on @param and such.
|
||||||
'phpdoc_no_alias_tag' => FALSE, // Allow @link in addition to @see.
|
'phpdoc_no_alias_tag' => false, // Allow @link in addition to @see.
|
||||||
'phpdoc_separation' => FALSE, // Don't put blank line between @params, @throws and @return.
|
'phpdoc_separation' => false, // Don't put blank line between @params, @throws and @return.
|
||||||
'phpdoc_summary' => FALSE, // Don't force terminating dot on the first line.
|
'phpdoc_summary' => false, // Don't force terminating dot on the first line.
|
||||||
])
|
])
|
||||||
->setFinder($finder);
|
->setFinder($finder);
|
||||||
|
|
|
||||||
12
vendor/nemiah/php-fints/.travis.yml
vendored
12
vendor/nemiah/php-fints/.travis.yml
vendored
|
|
@ -1,12 +0,0 @@
|
||||||
language: php
|
|
||||||
install: composer install
|
|
||||||
script:
|
|
||||||
- ./disallowtabs.sh
|
|
||||||
- ./csfixer-check.sh
|
|
||||||
- ./phplint.sh ./lib/
|
|
||||||
- ./vendor/bin/phpunit
|
|
||||||
dist: bionic
|
|
||||||
php:
|
|
||||||
- '8.0'
|
|
||||||
- '8.1.0'
|
|
||||||
- '8.2.0'
|
|
||||||
0
vendor/nemiah/php-fints/DEVELOPER-GUIDE.md
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/DEVELOPER-GUIDE.md
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/LICENSE
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/LICENSE
vendored
Executable file → Normal file
2
vendor/nemiah/php-fints/README.md
vendored
Executable file → Normal file
2
vendor/nemiah/php-fints/README.md
vendored
Executable file → Normal file
|
|
@ -1,6 +1,6 @@
|
||||||
# PHP FinTS/HBCI library
|
# PHP FinTS/HBCI library
|
||||||
|
|
||||||
[](https://travis-ci.org/nemiah/phpFinTS)
|
[](https://github.com/nemiah/phpFinTS/actions/workflows/tests.yml)
|
||||||
|
|
||||||
A PHP library implementing the following functions of the FinTS/HBCI protocol:
|
A PHP library implementing the following functions of the FinTS/HBCI protocol:
|
||||||
|
|
||||||
|
|
|
||||||
0
vendor/nemiah/php-fints/Samples/accounts.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/Samples/accounts.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/Samples/balance.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/Samples/balance.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/Samples/bpd.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/Samples/bpd.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/Samples/browser.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/Samples/browser.php
vendored
Executable file → Normal file
9
vendor/nemiah/php-fints/Samples/directDebit_Sephpa.php
vendored
Executable file → Normal file
9
vendor/nemiah/php-fints/Samples/directDebit_Sephpa.php
vendored
Executable file → Normal file
|
|
@ -46,6 +46,9 @@ $xml = $directDebitFile->generateOutput(['zipToOneFile' => false])[0]['data'];
|
||||||
|
|
||||||
$sendSEPADirectDebit = \Fhp\Action\SendSEPADirectDebit::create($oneAccount, $xml);
|
$sendSEPADirectDebit = \Fhp\Action\SendSEPADirectDebit::create($oneAccount, $xml);
|
||||||
$fints->execute($sendSEPADirectDebit);
|
$fints->execute($sendSEPADirectDebit);
|
||||||
if ($sendSEPADirectDebit->needsTan()) {
|
|
||||||
handleStrongAuthentication($sendSEPADirectDebit); // See login.php for the implementation.
|
require_once 'vop.php';
|
||||||
}
|
handleVopAndAuthentication($sendSEPADirectDebit);
|
||||||
|
|
||||||
|
// Debit requests don't produce any result we could receive through a getter, but we still need to make sure it's done.
|
||||||
|
$sendSEPADirectDebit->ensureDone();
|
||||||
|
|
|
||||||
9
vendor/nemiah/php-fints/Samples/directDebit_phpSepaXml.php
vendored
Executable file → Normal file
9
vendor/nemiah/php-fints/Samples/directDebit_phpSepaXml.php
vendored
Executable file → Normal file
|
|
@ -62,6 +62,9 @@ $oneAccount = $getSepaAccounts->getAccounts()[0];
|
||||||
|
|
||||||
$sendSEPADirectDebit = \Fhp\Action\SendSEPADirectDebit::create($oneAccount, $sepaDD->toXML('pain.008.001.02'));
|
$sendSEPADirectDebit = \Fhp\Action\SendSEPADirectDebit::create($oneAccount, $sepaDD->toXML('pain.008.001.02'));
|
||||||
$fints->execute($sendSEPADirectDebit);
|
$fints->execute($sendSEPADirectDebit);
|
||||||
if ($sendSEPADirectDebit->needsTan()) {
|
|
||||||
handleStrongAuthentication($sendSEPADirectDebit); // See login.php for the implementation.
|
require_once 'vop.php';
|
||||||
}
|
handleVopAndAuthentication($sendSEPADirectDebit);
|
||||||
|
|
||||||
|
// Debit requests don't produce any result we could receive through a getter, but we still need to make sure it's done.
|
||||||
|
$sendSEPADirectDebit->ensureDone();
|
||||||
|
|
|
||||||
0
vendor/nemiah/php-fints/Samples/init.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/Samples/init.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/Samples/login.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/Samples/login.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/Samples/statementOfAccount.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/Samples/statementOfAccount.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/Samples/statementOfHoldings.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/Samples/statementOfHoldings.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/Samples/tanModesAndMedia.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/Samples/tanModesAndMedia.php
vendored
Executable file → Normal file
18
vendor/nemiah/php-fints/Samples/transfer.php
vendored
Executable file → Normal file
18
vendor/nemiah/php-fints/Samples/transfer.php
vendored
Executable file → Normal file
|
|
@ -21,6 +21,15 @@ use nemiah\phpSepaXml\SEPATransfer;
|
||||||
/** @var \Fhp\FinTs $fints */
|
/** @var \Fhp\FinTs $fints */
|
||||||
$fints = require_once 'login.php';
|
$fints = require_once 'login.php';
|
||||||
|
|
||||||
|
// Just pick the first account, for demonstration purposes. You could also have the user choose, or have SEPAAccount
|
||||||
|
// hard-coded and not call getSEPAAccounts() at all.
|
||||||
|
$getSepaAccounts = \Fhp\Action\GetSEPAAccounts::create();
|
||||||
|
$fints->execute($getSepaAccounts);
|
||||||
|
if ($getSepaAccounts->needsTan()) {
|
||||||
|
handleStrongAuthentication($getSepaAccounts); // See login.php for the implementation.
|
||||||
|
}
|
||||||
|
$oneAccount = $getSepaAccounts->getAccounts()[0];
|
||||||
|
|
||||||
$dt = new \DateTime();
|
$dt = new \DateTime();
|
||||||
$dt->add(new \DateInterval('P1D'));
|
$dt->add(new \DateInterval('P1D'));
|
||||||
|
|
||||||
|
|
@ -49,6 +58,9 @@ $sepaDD->addCreditor(new SEPACreditor([ //this is who you want to send money to
|
||||||
|
|
||||||
$sendSEPATransfer = \Fhp\Action\SendSEPATransfer::create($oneAccount, $sepaDD->toXML());
|
$sendSEPATransfer = \Fhp\Action\SendSEPATransfer::create($oneAccount, $sepaDD->toXML());
|
||||||
$fints->execute($sendSEPATransfer);
|
$fints->execute($sendSEPATransfer);
|
||||||
if ($sendSEPATransfer->needsTan()) {
|
|
||||||
handleStrongAuthentication($sendSEPATransfer); // See login.php for the implementation.
|
require_once 'vop.php';
|
||||||
}
|
handleVopAndAuthentication($sendSEPATransfer);
|
||||||
|
|
||||||
|
// SEPA transfers don't produce any result we could receive through a getter, but we still need to make sure it's done.
|
||||||
|
$sendSEPATransfer->ensureDone();
|
||||||
|
|
|
||||||
138
vendor/nemiah/php-fints/Samples/vop.php
vendored
Normal file
138
vendor/nemiah/php-fints/Samples/vop.php
vendored
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Fhp\CurlException;
|
||||||
|
use Fhp\Protocol\ServerException;
|
||||||
|
use Fhp\Protocol\UnexpectedResponseException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SAMPLE - Helper functions for Verification of Payee. To be used together with init.php.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @var \Fhp\FinTs $fints */
|
||||||
|
$fints = require_once 'init.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To be called after the $action was already executed, this function takes care of asking the user for a TAN and VOP
|
||||||
|
* confirmation, if necessary.
|
||||||
|
* @param \Fhp\BaseAction $action The action, which must already have been run through {@link \Fhp\FinTs::execute()}.
|
||||||
|
* @throws CurlException|UnexpectedResponseException|ServerException See {@link FinTs::execute()} for details.
|
||||||
|
*/
|
||||||
|
function handleVopAndAuthentication(\Fhp\BaseAction $action): void
|
||||||
|
{
|
||||||
|
// NOTE: This is implemented as a `while` loop here, because this sample script runs entirely in one PHP process.
|
||||||
|
// If you want to make real use of the serializations demonstrated below, in order to resume processing in a new
|
||||||
|
// PHP process later (once the user has responded via your browser/client-side application), then you won't have a
|
||||||
|
// loop like this, but instead you'll just run the code within each time you get a new request from the user.
|
||||||
|
while (!$action->isDone()) {
|
||||||
|
if ($action->needsTan()) {
|
||||||
|
handleStrongAuthentication($action); // See login.php for the implementation.
|
||||||
|
} elseif ($action->needsPollingWait()) {
|
||||||
|
handlePollingWait($action);
|
||||||
|
} elseif ($action->needsVopConfirmation()) {
|
||||||
|
handleVopConfirmation($action);
|
||||||
|
} else {
|
||||||
|
throw new \AssertionError(
|
||||||
|
'Action is not done but also does not need anything to be done. Did you execute() it?'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for the amount of time that the bank prescribed and then polls the server for a status update.
|
||||||
|
* @param \Fhp\BaseAction $action An action for which {@link \Fhp\BaseAction::needsPollingWait()} returns true.
|
||||||
|
* @throws CurlException|UnexpectedResponseException|ServerException See {@link FinTs::execute()} for details.
|
||||||
|
*/
|
||||||
|
function handlePollingWait(\Fhp\BaseAction $action): void
|
||||||
|
{
|
||||||
|
global $fints, $options, $credentials; // From login.php
|
||||||
|
|
||||||
|
// Tell the user what the bank had to say (if anything).
|
||||||
|
$pollingInfo = $action->getPollingInfo();
|
||||||
|
if ($infoText = $pollingInfo->getInformationForUser()) {
|
||||||
|
echo $infoText . PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optional: If the wait is too long for your PHP process to remain alive (i.e. your server would kill the process),
|
||||||
|
// you can persist the state as shown here and instead send a response to the client-side application indicating
|
||||||
|
// that the operation is still ongoing. Then after an appropriate amount of time, the client can send another
|
||||||
|
// request, spawning a new PHP process, where you can restore the state as shown below.
|
||||||
|
if ($optionallyPersistEverything = false) {
|
||||||
|
$persistedAction = serialize($action);
|
||||||
|
$persistedFints = $fints->persist();
|
||||||
|
|
||||||
|
// These are two strings (watch out, they are NOT necessarily UTF-8 encoded), which you can store anywhere.
|
||||||
|
// This example code stores them in a text file, but you might write them to your database (use a BLOB, not a
|
||||||
|
// CHAR/TEXT field to allow for arbitrary encoding) or in some other storage (possibly base64-encoded to make it
|
||||||
|
// ASCII).
|
||||||
|
file_put_contents(__DIR__ . '/state.txt', serialize([$persistedFints, $persistedAction]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for (at least) the prescribed amount of time. --------------------------------------------------------------
|
||||||
|
// Note: In your real application, you may be doing this waiting on the client and then send a fresh request to your
|
||||||
|
// server.
|
||||||
|
$waitSecs = $pollingInfo->getNextAttemptInSeconds() ?: 5;
|
||||||
|
echo "Waiting for $waitSecs seconds before polling the bank server again..." . PHP_EOL;
|
||||||
|
sleep($waitSecs);
|
||||||
|
|
||||||
|
// Optional: If the state was persisted above, we can restore it now (imagine this is a new PHP process).
|
||||||
|
if ($optionallyPersistEverything) {
|
||||||
|
$restoredState = file_get_contents(__DIR__ . '/state.txt');
|
||||||
|
list($persistedInstance, $persistedAction) = unserialize($restoredState);
|
||||||
|
$fints = \Fhp\FinTs::new($options, $credentials, $persistedInstance);
|
||||||
|
$action = unserialize($persistedAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
$fints->pollAction($action);
|
||||||
|
// Now the action is in a new state, which the caller of this function (handleVopAndAuthentication) will deal with.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asks the user to confirm
|
||||||
|
* @param \Fhp\BaseAction $action An action for which {@link \Fhp\BaseAction::needsVopConfirmation()} returns true.
|
||||||
|
* @throws CurlException|UnexpectedResponseException|ServerException See {@link FinTs::execute()} for details.
|
||||||
|
*/
|
||||||
|
function handleVopConfirmation(\Fhp\BaseAction $action): void
|
||||||
|
{
|
||||||
|
global $fints, $options, $credentials; // From login.php
|
||||||
|
|
||||||
|
$vopConfirmationRequest = $action->getVopConfirmationRequest();
|
||||||
|
if ($infoText = $vopConfirmationRequest->getInformationForUser()) {
|
||||||
|
echo $infoText . PHP_EOL;
|
||||||
|
}
|
||||||
|
echo match ($vopConfirmationRequest->getVerificationResult()) {
|
||||||
|
\Fhp\Model\VopVerificationResult::CompletedFullMatch =>
|
||||||
|
'The bank says the payee information matched perfectly, but still wants you to confirm.',
|
||||||
|
\Fhp\Model\VopVerificationResult::CompletedCloseMatch =>
|
||||||
|
'The bank says the payee information does not match exactly, so please confirm.',
|
||||||
|
\Fhp\Model\VopVerificationResult::CompletedPartialMatch =>
|
||||||
|
'The bank says the payee information does not match for all transfers, so please confirm.',
|
||||||
|
\Fhp\Model\VopVerificationResult::CompletedNoMatch =>
|
||||||
|
'The bank says the payee information does not match, but you can still confirm the transfer if you want.',
|
||||||
|
\Fhp\Model\VopVerificationResult::NotApplicable =>
|
||||||
|
$vopConfirmationRequest->getVerificationNotApplicableReason() == null
|
||||||
|
? 'The bank did not provide any information about payee verification, but you can still confirm.'
|
||||||
|
: 'The bank says: ' . $vopConfirmationRequest->getVerificationNotApplicableReason(),
|
||||||
|
default => 'The bank failed to provide information about payee verification, but you can still confirm.',
|
||||||
|
} . PHP_EOL;
|
||||||
|
|
||||||
|
// Just like in handleTan(), handleDecoupledSubmission() or handlePollingWait(), we have the option to interrupt the
|
||||||
|
// PHP process at this point, so that we can ask the user in a client application for their confirmation.
|
||||||
|
if ($optionallyPersistEverything = false) {
|
||||||
|
$persistedAction = serialize($action);
|
||||||
|
$persistedFints = $fints->persist();
|
||||||
|
// See handlePollingWait() for how to deal with this in practice.
|
||||||
|
file_put_contents(__DIR__ . '/state.txt', serialize([$persistedFints, $persistedAction]));
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "In light of the information provided above, do you want to confirm the execution of the transfer?" . PHP_EOL;
|
||||||
|
// Note: We currently have no way canceling the transfer; the only thing we can do is never to confirm it.
|
||||||
|
echo "If so, please type 'confirm' and hit Return. Otherwise, please kill this PHP process." . PHP_EOL;
|
||||||
|
while (trim(fgets(STDIN)) !== 'confirm') {
|
||||||
|
echo "Try again." . PHP_EOL;
|
||||||
|
}
|
||||||
|
echo "Confirming the transfer." . PHP_EOL;
|
||||||
|
$fints->confirmVop($action);
|
||||||
|
echo "Confirmed" . PHP_EOL;
|
||||||
|
// Now the action is in a new state, which the caller of this function (handleVopAndAuthentication) will deal with.
|
||||||
|
}
|
||||||
4
vendor/nemiah/php-fints/composer.json
vendored
Executable file → Normal file
4
vendor/nemiah/php-fints/composer.json
vendored
Executable file → Normal file
|
|
@ -2,7 +2,7 @@
|
||||||
"name": "nemiah/php-fints",
|
"name": "nemiah/php-fints",
|
||||||
"description": "PHP Library for the protocols fints and hbci",
|
"description": "PHP Library for the protocols fints and hbci",
|
||||||
"homepage": "https://github.com/nemiah/phpFinTS",
|
"homepage": "https://github.com/nemiah/phpFinTS",
|
||||||
"version": "3.7.0",
|
"version": "4.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-0": {
|
"psr-0": {
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=8.0",
|
"php": ">=8.3",
|
||||||
"psr/log": "^1|^2|^3",
|
"psr/log": "^1|^2|^3",
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
"ext-mbstring": "*"
|
"ext-mbstring": "*"
|
||||||
|
|
|
||||||
36
vendor/nemiah/php-fints/csfixer-check.sh
vendored
36
vendor/nemiah/php-fints/csfixer-check.sh
vendored
|
|
@ -1,36 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# When this is run as part of a Travis test for a pull request, then it ensures that none of the touched files has any
|
|
||||||
# PHP CS Fixer warnings.
|
|
||||||
# From: https://github.com/FriendsOfPHP/PHP-CS-Fixer#using-php-cs-fixer-on-ci
|
|
||||||
|
|
||||||
if [ -z "$TRAVIS_COMMIT_RANGE" ]
|
|
||||||
then
|
|
||||||
# TRAVIS_COMMIT_RANGE "is empty for builds triggered by the initial commit of a new branch"
|
|
||||||
# From: https://docs.travis-ci.com/user/environment-variables/
|
|
||||||
echo "Variable TRAVIS_COMMIT_RANGE not set, falling back to full git diff"
|
|
||||||
TRAVIS_COMMIT_RANGE=.
|
|
||||||
fi
|
|
||||||
|
|
||||||
IFS='
|
|
||||||
'
|
|
||||||
CHANGED_FILES=$(git diff --name-only --diff-filter=ACMRTUXB "$TRAVIS_COMMIT_RANGE")
|
|
||||||
if [ "$?" -ne "0" ]
|
|
||||||
then
|
|
||||||
echo "Error: git diff response code > 0, aborting"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "${CHANGED_FILES}" ]
|
|
||||||
then
|
|
||||||
echo "0 changed files found, exiting"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# February 2022: PHP CS FIXER is currently not PHP 8.1 compatible:
|
|
||||||
# "you may experience code modified in a wrong way"
|
|
||||||
# "To ignore this requirement please set `PHP_CS_FIXER_IGNORE_ENV`."
|
|
||||||
export PHP_CS_FIXER_IGNORE_ENV="1"
|
|
||||||
|
|
||||||
if ! echo "${CHANGED_FILES}" | grep -qE "^(\\.php_cs(\\.dist)?|composer\\.lock)$"; then EXTRA_ARGS=$(printf -- '--path-mode=intersection\n--\n%s' "${CHANGED_FILES}"); else EXTRA_ARGS=''; fi
|
|
||||||
vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.php -v --dry-run --stop-on-violation --using-cache=no ${EXTRA_ARGS} || (echo "php-cs-fixer failed" && exit 1)
|
|
||||||
37
vendor/nemiah/php-fints/disallowtabs.sh
vendored
37
vendor/nemiah/php-fints/disallowtabs.sh
vendored
|
|
@ -1,37 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
#
|
|
||||||
# When this is run as part of a Travis test for a pull request, then it ensures that none of the added lines (compared
|
|
||||||
# to the base branch of the pull request) use tabs for indentations.
|
|
||||||
# Adapted from https://github.com/mrc/git-hook-library/blob/master/pre-commit.no-tabs
|
|
||||||
|
|
||||||
# Abort if any of the inner commands (particularly the git commands) fails.
|
|
||||||
set -e
|
|
||||||
set -o pipefail
|
|
||||||
|
|
||||||
if [ -z ${TRAVIS_PULL_REQUEST} ]; then
|
|
||||||
echo "Expected environment variable TRAVIS_PULL_REQUEST"
|
|
||||||
exit 2
|
|
||||||
elif [ "${TRAVIS_PULL_REQUEST}" == "false" ]; then
|
|
||||||
echo "Not a Travis pull request, skipping."
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Make sure that we have a local copy of the relevant commits (otherwise git diff won't work).
|
|
||||||
git remote set-branches --add origin ${TRAVIS_BRNACH}
|
|
||||||
git fetch
|
|
||||||
|
|
||||||
# Compute the diff from the PR's target branch to its HEAD commit.
|
|
||||||
target_branch="origin/${TRAVIS_BRANCH}"
|
|
||||||
the_diff=$(git diff "${target_branch}...HEAD")
|
|
||||||
|
|
||||||
# Make sure that there are no tabs in the indentation part of added lines.
|
|
||||||
if echo "${the_diff}" | egrep '^\+\s* ' >/dev/null; then
|
|
||||||
echo -e "\e[31mError: The changes contain a tab for indentation\e[0m, which is against this repo's policy."
|
|
||||||
echo "Target branch: origin/${TRAVIS_BRANCH}"
|
|
||||||
echo "Commit range: ${TRAVIS_COMMIT_RANGE}"
|
|
||||||
echo "The following tabs were detected:"
|
|
||||||
echo "${the_diff}" | egrep '^(\+\s* |\+\+\+|@@)'
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "No new tabs detected."
|
|
||||||
fi
|
|
||||||
6
vendor/nemiah/php-fints/lib/Fhp/Action/GetBalance.php
vendored
Executable file → Normal file
6
vendor/nemiah/php-fints/lib/Fhp/Action/GetBalance.php
vendored
Executable file → Normal file
|
|
@ -24,7 +24,7 @@ use Fhp\UnsupportedException;
|
||||||
*/
|
*/
|
||||||
class GetBalance extends PaginateableAction
|
class GetBalance extends PaginateableAction
|
||||||
{
|
{
|
||||||
// Request (not available after serialization, i.e. not available in processResponse()).
|
// Request (if you add a field here, update __serialize() and __unserialize() as well).
|
||||||
/** @var SEPAAccount */
|
/** @var SEPAAccount */
|
||||||
private $account;
|
private $account;
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
|
|
@ -79,7 +79,7 @@ class GetBalance extends PaginateableAction
|
||||||
{
|
{
|
||||||
list(
|
list(
|
||||||
$parentSerialized,
|
$parentSerialized,
|
||||||
$this->account, $this->allAccounts
|
$this->account, $this->allAccounts,
|
||||||
) = $serialized;
|
) = $serialized;
|
||||||
|
|
||||||
is_array($parentSerialized) ?
|
is_array($parentSerialized) ?
|
||||||
|
|
@ -96,7 +96,6 @@ class GetBalance extends PaginateableAction
|
||||||
return $this->response;
|
return $this->response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||||
{
|
{
|
||||||
/** @var BaseSegment $hisals */
|
/** @var BaseSegment $hisals */
|
||||||
|
|
@ -115,7 +114,6 @@ class GetBalance extends PaginateableAction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function processResponse(Message $response)
|
public function processResponse(Message $response)
|
||||||
{
|
{
|
||||||
parent::processResponse($response);
|
parent::processResponse($response);
|
||||||
|
|
|
||||||
6
vendor/nemiah/php-fints/lib/Fhp/Action/GetDepotAufstellung.php
vendored
Executable file → Normal file
6
vendor/nemiah/php-fints/lib/Fhp/Action/GetDepotAufstellung.php
vendored
Executable file → Normal file
|
|
@ -24,7 +24,7 @@ use Fhp\UnsupportedException;
|
||||||
*/
|
*/
|
||||||
class GetDepotAufstellung extends PaginateableAction
|
class GetDepotAufstellung extends PaginateableAction
|
||||||
{
|
{
|
||||||
// Request (not available after serialization, i.e. not available in processResponse()).
|
// Request (if you add a field here, update __serialize() and __unserialize() as well).
|
||||||
/** @var SEPAAccount */
|
/** @var SEPAAccount */
|
||||||
private $account;
|
private $account;
|
||||||
|
|
||||||
|
|
@ -81,7 +81,7 @@ class GetDepotAufstellung extends PaginateableAction
|
||||||
{
|
{
|
||||||
list(
|
list(
|
||||||
$parentSerialized,
|
$parentSerialized,
|
||||||
$this->account
|
$this->account,
|
||||||
) = $serialized;
|
) = $serialized;
|
||||||
|
|
||||||
is_array($parentSerialized) ?
|
is_array($parentSerialized) ?
|
||||||
|
|
@ -111,7 +111,6 @@ class GetDepotAufstellung extends PaginateableAction
|
||||||
return $this->depotWert;
|
return $this->depotWert;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||||
{
|
{
|
||||||
/** @var HIWPDS $hiwpds */
|
/** @var HIWPDS $hiwpds */
|
||||||
|
|
@ -125,7 +124,6 @@ class GetDepotAufstellung extends PaginateableAction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function processResponse(Message $response)
|
public function processResponse(Message $response)
|
||||||
{
|
{
|
||||||
parent::processResponse($response);
|
parent::processResponse($response);
|
||||||
|
|
|
||||||
178
vendor/nemiah/php-fints/lib/Fhp/Action/GetElectronicStatement.php
vendored
Normal file
178
vendor/nemiah/php-fints/lib/Fhp/Action/GetElectronicStatement.php
vendored
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Fhp\Action;
|
||||||
|
|
||||||
|
use Fhp\Model\SEPAAccount;
|
||||||
|
use Fhp\PaginateableAction;
|
||||||
|
use Fhp\Protocol\BPD;
|
||||||
|
use Fhp\Protocol\Message;
|
||||||
|
use Fhp\Protocol\UPD;
|
||||||
|
use Fhp\Segment\Common\Kti;
|
||||||
|
use Fhp\Segment\EKA\HIEKA;
|
||||||
|
use Fhp\Segment\EKA\HIEKASv5;
|
||||||
|
use Fhp\Segment\EKA\HKEKAv5;
|
||||||
|
use Fhp\Segment\HIRMS\Rueckmeldungscode;
|
||||||
|
use Fhp\UnsupportedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves electronic bank statements (Elektronischer Kontoauszug) via HKEKA.
|
||||||
|
*
|
||||||
|
* This supports both MT940 and PDF formats depending on what the bank offers.
|
||||||
|
*/
|
||||||
|
class GetElectronicStatement extends PaginateableAction
|
||||||
|
{
|
||||||
|
// Format codes
|
||||||
|
public const FORMAT_MT940 = 1;
|
||||||
|
public const FORMAT_PDF = 2;
|
||||||
|
|
||||||
|
/** @var SEPAAccount */
|
||||||
|
private $account;
|
||||||
|
|
||||||
|
/** @var int|null Format to request (1=MT940, 2=PDF, null=default) */
|
||||||
|
private $format;
|
||||||
|
|
||||||
|
/** @var string|null Optional: from date YYYYMMDD */
|
||||||
|
private $fromDate;
|
||||||
|
|
||||||
|
/** @var string|null Optional: to date YYYYMMDD */
|
||||||
|
private $toDate;
|
||||||
|
|
||||||
|
// Response data
|
||||||
|
/** @var string Raw data (MT940 or PDF binary) */
|
||||||
|
private $data = '';
|
||||||
|
|
||||||
|
/** @var array Statement metadata from response */
|
||||||
|
private $statementInfo = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param SEPAAccount $account The account to get statements for
|
||||||
|
* @param int|null $format Format code (1=MT940, 2=PDF, null=bank default)
|
||||||
|
* @param \DateTime|null $fromDate Optional: Start date for statement range
|
||||||
|
* @param \DateTime|null $toDate Optional: End date for statement range
|
||||||
|
* @return GetElectronicStatement
|
||||||
|
*/
|
||||||
|
public static function create(
|
||||||
|
SEPAAccount $account,
|
||||||
|
?int $format = null,
|
||||||
|
?\DateTime $fromDate = null,
|
||||||
|
?\DateTime $toDate = null
|
||||||
|
): GetElectronicStatement {
|
||||||
|
$result = new GetElectronicStatement();
|
||||||
|
$result->account = $account;
|
||||||
|
$result->format = $format;
|
||||||
|
$result->fromDate = $fromDate ? $fromDate->format('Ymd') : null;
|
||||||
|
$result->toDate = $toDate ? $toDate->format('Ymd') : null;
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __serialize(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
parent::__serialize(),
|
||||||
|
$this->account,
|
||||||
|
$this->format,
|
||||||
|
$this->fromDate,
|
||||||
|
$this->toDate,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __unserialize(array $serialized): void
|
||||||
|
{
|
||||||
|
list(
|
||||||
|
$parentSerialized,
|
||||||
|
$this->account,
|
||||||
|
$this->format,
|
||||||
|
$this->fromDate,
|
||||||
|
$this->toDate
|
||||||
|
) = $serialized;
|
||||||
|
|
||||||
|
is_array($parentSerialized)
|
||||||
|
? parent::__unserialize($parentSerialized)
|
||||||
|
: parent::unserialize($parentSerialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string The raw data (MT940 text or PDF binary)
|
||||||
|
*/
|
||||||
|
public function getData(): string
|
||||||
|
{
|
||||||
|
$this->ensureDone();
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array Statement metadata (number, year, iban, date, format)
|
||||||
|
*/
|
||||||
|
public function getStatementInfo(): array
|
||||||
|
{
|
||||||
|
$this->ensureDone();
|
||||||
|
return $this->statementInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool Whether receipt confirmation is needed
|
||||||
|
*/
|
||||||
|
public function needsReceipt(): bool
|
||||||
|
{
|
||||||
|
$this->ensureDone();
|
||||||
|
return !empty($this->statementInfo['receiptCode']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritdoc} */
|
||||||
|
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||||
|
{
|
||||||
|
/** @var HIEKASv5|null $hiekas */
|
||||||
|
$hiekas = $bpd->getLatestSupportedParameters('HIEKAS');
|
||||||
|
|
||||||
|
if ($hiekas === null) {
|
||||||
|
throw new UnsupportedException('The bank does not support electronic statements (HKEKA).');
|
||||||
|
}
|
||||||
|
|
||||||
|
$param = $hiekas->getParameter();
|
||||||
|
|
||||||
|
// Check if requested format is supported
|
||||||
|
if ($this->format === self::FORMAT_PDF && !$param->supportsPdf()) {
|
||||||
|
throw new UnsupportedException('The bank does not support PDF format for electronic statements.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use Kti (IBAN/BIC) for version 5
|
||||||
|
$kti = Kti::fromAccount($this->account);
|
||||||
|
return HKEKAv5::create($kti, $this->format, $this->fromDate, $this->toDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritdoc} */
|
||||||
|
public function processResponse(Message $response)
|
||||||
|
{
|
||||||
|
parent::processResponse($response);
|
||||||
|
|
||||||
|
// Check if no statements available
|
||||||
|
if ($response->findRueckmeldung(Rueckmeldungscode::NICHT_VERFUEGBAR) !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var HIEKA[] $responseSegments */
|
||||||
|
$responseSegments = $response->findSegments(HIEKA::class);
|
||||||
|
|
||||||
|
if (empty($responseSegments)) {
|
||||||
|
// No segments but also no error = empty response
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($responseSegments as $hieka) {
|
||||||
|
// Append data (for pagination)
|
||||||
|
$this->data .= $hieka->getData();
|
||||||
|
|
||||||
|
// Store metadata from first segment
|
||||||
|
if (empty($this->statementInfo)) {
|
||||||
|
$this->statementInfo = [
|
||||||
|
'statementNumber' => $hieka->getStatementNumber(),
|
||||||
|
'statementYear' => $hieka->getStatementYear(),
|
||||||
|
'iban' => $hieka->getIban(),
|
||||||
|
'creationDate' => $hieka->getCreationDate(),
|
||||||
|
'format' => $hieka->getFormat(),
|
||||||
|
'receiptCode' => $hieka->needsReceipt() ? $hieka->getReceiptCode() : null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
vendor/nemiah/php-fints/lib/Fhp/Action/GetSEPAAccounts.php
vendored
Executable file → Normal file
2
vendor/nemiah/php-fints/lib/Fhp/Action/GetSEPAAccounts.php
vendored
Executable file → Normal file
|
|
@ -47,7 +47,6 @@ class GetSEPAAccounts extends PaginateableAction
|
||||||
return $this->accounts;
|
return $this->accounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||||
{
|
{
|
||||||
/** @var BaseSegment $hispas */
|
/** @var BaseSegment $hispas */
|
||||||
|
|
@ -64,7 +63,6 @@ class GetSEPAAccounts extends PaginateableAction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function processResponse(Message $response)
|
public function processResponse(Message $response)
|
||||||
{
|
{
|
||||||
parent::processResponse($response);
|
parent::processResponse($response);
|
||||||
|
|
|
||||||
43
vendor/nemiah/php-fints/lib/Fhp/Action/GetSEPADirectDebitParameters.php
vendored
Executable file → Normal file
43
vendor/nemiah/php-fints/lib/Fhp/Action/GetSEPADirectDebitParameters.php
vendored
Executable file → Normal file
|
|
@ -16,12 +16,11 @@ class GetSEPADirectDebitParameters extends BaseAction
|
||||||
public const SEQUENCE_TYPES = ['FRST', 'OOFF', 'FNAL', 'RCUR'];
|
public const SEQUENCE_TYPES = ['FRST', 'OOFF', 'FNAL', 'RCUR'];
|
||||||
public const DIRECT_DEBIT_TYPES = ['CORE', 'COR1', 'B2B'];
|
public const DIRECT_DEBIT_TYPES = ['CORE', 'COR1', 'B2B'];
|
||||||
|
|
||||||
|
// Request (if you add a field here, update __serialize() and __unserialize() as well).
|
||||||
/** @var string */
|
/** @var string */
|
||||||
private $directDebitType;
|
private $directDebitType;
|
||||||
|
|
||||||
/** @var string */
|
/** @var string */
|
||||||
private $seqType;
|
private $seqType;
|
||||||
|
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
private $singleDirectDebit;
|
private $singleDirectDebit;
|
||||||
|
|
||||||
|
|
@ -43,6 +42,45 @@ class GetSEPADirectDebitParameters extends BaseAction
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Beginning from PHP7.4 __unserialize is used for new generated strings, then this method is only used for previously generated strings - remove after May 2023
|
||||||
|
*/
|
||||||
|
public function serialize(): string
|
||||||
|
{
|
||||||
|
return serialize($this->__serialize());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __serialize(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
parent::__serialize(),
|
||||||
|
$this->directDebitType, $this->seqType, $this->singleDirectDebit,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Beginning from PHP7.4 __unserialize is used for new generated strings, then this method is only used for previously generated strings - remove after May 2023
|
||||||
|
*
|
||||||
|
* @param string $serialized
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function unserialize($serialized)
|
||||||
|
{
|
||||||
|
self::__unserialize(unserialize($serialized));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __unserialize(array $serialized): void
|
||||||
|
{
|
||||||
|
list(
|
||||||
|
$parentSerialized,
|
||||||
|
$this->directDebitType, $this->seqType, $this->singleDirectDebit,
|
||||||
|
) = $serialized;
|
||||||
|
|
||||||
|
is_array($parentSerialized) ?
|
||||||
|
parent::__unserialize($parentSerialized) :
|
||||||
|
parent::unserialize($parentSerialized);
|
||||||
|
}
|
||||||
|
|
||||||
public static function getHixxesSegmentName(string $directDebitType, bool $singleDirectDebit): string
|
public static function getHixxesSegmentName(string $directDebitType, bool $singleDirectDebit): string
|
||||||
{
|
{
|
||||||
switch ($directDebitType) {
|
switch ($directDebitType) {
|
||||||
|
|
@ -56,7 +94,6 @@ class GetSEPADirectDebitParameters extends BaseAction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||||
{
|
{
|
||||||
$this->hidxes = $bpd->requireLatestSupportedParameters(static::getHixxesSegmentName($this->directDebitType, $this->singleDirectDebit));
|
$this->hidxes = $bpd->requireLatestSupportedParameters(static::getHixxesSegmentName($this->directDebitType, $this->singleDirectDebit));
|
||||||
|
|
|
||||||
194
vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementFromArchive.php
vendored
Normal file
194
vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementFromArchive.php
vendored
Normal file
|
|
@ -0,0 +1,194 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Fhp\Action;
|
||||||
|
|
||||||
|
use Fhp\Model\SEPAAccount;
|
||||||
|
use Fhp\PaginateableAction;
|
||||||
|
use Fhp\Protocol\BPD;
|
||||||
|
use Fhp\Protocol\Message;
|
||||||
|
use Fhp\Protocol\UPD;
|
||||||
|
use Fhp\Segment\Common\Kti;
|
||||||
|
use Fhp\Segment\KAA\HIKAA;
|
||||||
|
use Fhp\Segment\KAA\HIKAASv1;
|
||||||
|
use Fhp\Segment\KAA\HKKAAv1;
|
||||||
|
use Fhp\Segment\KAA\HKKAAv2;
|
||||||
|
use Fhp\Segment\HIRMS\Rueckmeldungscode;
|
||||||
|
use Fhp\UnsupportedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves PDF bank statements from bank archive (Kontoauszug aus Archiv) via HKKAA.
|
||||||
|
*
|
||||||
|
* This is an alternative to HKEKP for banks that store statements in an archive/mailbox
|
||||||
|
* instead of providing direct PDF generation.
|
||||||
|
*/
|
||||||
|
class GetStatementFromArchive extends PaginateableAction
|
||||||
|
{
|
||||||
|
// PDF Format code
|
||||||
|
public const FORMAT_PDF = 4;
|
||||||
|
public const FORMAT_MT940 = 1;
|
||||||
|
|
||||||
|
/** @var SEPAAccount */
|
||||||
|
private $account;
|
||||||
|
|
||||||
|
/** @var int Format to request (default: PDF = 4) */
|
||||||
|
private $format;
|
||||||
|
|
||||||
|
/** @var string|null Optional: from date YYYYMMDD */
|
||||||
|
private $fromDate;
|
||||||
|
|
||||||
|
/** @var string|null Optional: to date YYYYMMDD */
|
||||||
|
private $toDate;
|
||||||
|
|
||||||
|
// Response data
|
||||||
|
/** @var string Raw PDF data (may be from multiple pages) */
|
||||||
|
private $pdfData = '';
|
||||||
|
|
||||||
|
/** @var array Statement metadata from response */
|
||||||
|
private $statementInfo = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param SEPAAccount $account The account to get statements for
|
||||||
|
* @param int $format Format code (4 = PDF)
|
||||||
|
* @param \DateTime|null $fromDate Optional: Start date for statement range
|
||||||
|
* @param \DateTime|null $toDate Optional: End date for statement range
|
||||||
|
* @return GetStatementFromArchive
|
||||||
|
*/
|
||||||
|
public static function create(
|
||||||
|
SEPAAccount $account,
|
||||||
|
int $format = self::FORMAT_PDF,
|
||||||
|
?\DateTime $fromDate = null,
|
||||||
|
?\DateTime $toDate = null
|
||||||
|
): GetStatementFromArchive {
|
||||||
|
$result = new GetStatementFromArchive();
|
||||||
|
$result->account = $account;
|
||||||
|
$result->format = $format;
|
||||||
|
$result->fromDate = $fromDate ? $fromDate->format('Ymd') : null;
|
||||||
|
$result->toDate = $toDate ? $toDate->format('Ymd') : null;
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __serialize(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
parent::__serialize(),
|
||||||
|
$this->account,
|
||||||
|
$this->format,
|
||||||
|
$this->fromDate,
|
||||||
|
$this->toDate,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __unserialize(array $serialized): void
|
||||||
|
{
|
||||||
|
list(
|
||||||
|
$parentSerialized,
|
||||||
|
$this->account,
|
||||||
|
$this->format,
|
||||||
|
$this->fromDate,
|
||||||
|
$this->toDate
|
||||||
|
) = $serialized;
|
||||||
|
|
||||||
|
is_array($parentSerialized)
|
||||||
|
? parent::__unserialize($parentSerialized)
|
||||||
|
: parent::unserialize($parentSerialized);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string The raw PDF data
|
||||||
|
*/
|
||||||
|
public function getPdfData(): string
|
||||||
|
{
|
||||||
|
$this->ensureDone();
|
||||||
|
return $this->pdfData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array Statement metadata (number, year, iban, date, filename)
|
||||||
|
*/
|
||||||
|
public function getStatementInfo(): array
|
||||||
|
{
|
||||||
|
$this->ensureDone();
|
||||||
|
return $this->statementInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool Whether receipt confirmation is needed
|
||||||
|
*/
|
||||||
|
public function needsReceipt(): bool
|
||||||
|
{
|
||||||
|
$this->ensureDone();
|
||||||
|
return !empty($this->statementInfo['receiptCode']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritdoc} */
|
||||||
|
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||||
|
{
|
||||||
|
/** @var HIKAASv1|null $hikaas */
|
||||||
|
$hikaas = $bpd->getLatestSupportedParameters('HIKAAS');
|
||||||
|
|
||||||
|
if ($hikaas === null) {
|
||||||
|
throw new UnsupportedException('The bank does not support archive statements (HKKAA).');
|
||||||
|
}
|
||||||
|
|
||||||
|
$param = $hikaas->getParameter();
|
||||||
|
|
||||||
|
// Check if PDF format is supported
|
||||||
|
if ($this->format === self::FORMAT_PDF && !$param->supportsPdf()) {
|
||||||
|
throw new UnsupportedException('The bank does not support PDF format for archive statements.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if date range queries are supported
|
||||||
|
if (($this->fromDate !== null || $this->toDate !== null) && !$param->canFetchByDateRange()) {
|
||||||
|
throw new UnsupportedException('The bank does not support date range queries for archive statements.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the correct HKKAA version based on HIKAAS version in BPD
|
||||||
|
$hikaasVersion = $hikaas->getVersion();
|
||||||
|
|
||||||
|
// Use Kti with IBAN/BIC only (not the full account details)
|
||||||
|
$kti = Kti::create($this->account->getIban(), $this->account->getBic());
|
||||||
|
|
||||||
|
if ($hikaasVersion >= 2) {
|
||||||
|
return HKKAAv2::create($kti, $this->format, $this->fromDate, $this->toDate);
|
||||||
|
} else {
|
||||||
|
return HKKAAv1::create($kti, $this->format, $this->fromDate, $this->toDate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritdoc} */
|
||||||
|
public function processResponse(Message $response)
|
||||||
|
{
|
||||||
|
parent::processResponse($response);
|
||||||
|
|
||||||
|
// Check if no statements available
|
||||||
|
if ($response->findRueckmeldung(Rueckmeldungscode::NICHT_VERFUEGBAR) !== null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var HIKAA[] $responseSegments */
|
||||||
|
$responseSegments = $response->findSegments(HIKAA::class);
|
||||||
|
|
||||||
|
if (empty($responseSegments)) {
|
||||||
|
// No segments but also no error = empty response
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($responseSegments as $hikaa) {
|
||||||
|
// Append PDF data (for pagination)
|
||||||
|
$this->pdfData .= $hikaa->getPdfData();
|
||||||
|
|
||||||
|
// Store metadata from first segment
|
||||||
|
if (empty($this->statementInfo)) {
|
||||||
|
$this->statementInfo = [
|
||||||
|
'statementNumber' => $hikaa->getStatementNumber(),
|
||||||
|
'statementYear' => $hikaa->getStatementYear(),
|
||||||
|
'iban' => $hikaa->getIban(),
|
||||||
|
'creationDate' => $hikaa->getCreationDate(),
|
||||||
|
'filename' => $hikaa->getFilename(),
|
||||||
|
'format' => $hikaa->getFormat(),
|
||||||
|
'receiptCode' => $hikaa->needsReceipt() ? $hikaa->getReceiptCode() : null,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementOfAccount.php
vendored
Executable file → Normal file
10
vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementOfAccount.php
vendored
Executable file → Normal file
|
|
@ -31,7 +31,7 @@ use Fhp\UnsupportedException;
|
||||||
*/
|
*/
|
||||||
class GetStatementOfAccount extends PaginateableAction
|
class GetStatementOfAccount extends PaginateableAction
|
||||||
{
|
{
|
||||||
// Request (not available after serialization, i.e. not available in processResponse()).
|
// Request (if you add a field here, update __serialize() and __unserialize() as well).
|
||||||
/** @var SEPAAccount */
|
/** @var SEPAAccount */
|
||||||
private $account;
|
private $account;
|
||||||
/** @var \DateTime */
|
/** @var \DateTime */
|
||||||
|
|
@ -93,7 +93,7 @@ class GetStatementOfAccount extends PaginateableAction
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
parent::__serialize(),
|
parent::__serialize(),
|
||||||
$this->account, $this->from, $this->to, $this->allAccounts,
|
$this->account, $this->from, $this->to, $this->allAccounts, $this->includeUnbooked,
|
||||||
$this->bankName,
|
$this->bankName,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
@ -113,8 +113,8 @@ class GetStatementOfAccount extends PaginateableAction
|
||||||
{
|
{
|
||||||
list(
|
list(
|
||||||
$parentSerialized,
|
$parentSerialized,
|
||||||
$this->account, $this->from, $this->to, $this->allAccounts,
|
$this->account, $this->from, $this->to, $this->allAccounts, $this->includeUnbooked,
|
||||||
$this->bankName
|
$this->bankName,
|
||||||
) = $serialized;
|
) = $serialized;
|
||||||
|
|
||||||
is_array($parentSerialized) ?
|
is_array($parentSerialized) ?
|
||||||
|
|
@ -147,7 +147,6 @@ class GetStatementOfAccount extends PaginateableAction
|
||||||
return $this->statement;
|
return $this->statement;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||||
{
|
{
|
||||||
$this->bankName = $bpd->getBankName();
|
$this->bankName = $bpd->getBankName();
|
||||||
|
|
@ -171,7 +170,6 @@ class GetStatementOfAccount extends PaginateableAction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function processResponse(Message $response)
|
public function processResponse(Message $response)
|
||||||
{
|
{
|
||||||
parent::processResponse($response);
|
parent::processResponse($response);
|
||||||
|
|
|
||||||
6
vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementOfAccountXML.php
vendored
Executable file → Normal file
6
vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementOfAccountXML.php
vendored
Executable file → Normal file
|
|
@ -24,7 +24,7 @@ use Fhp\UnsupportedException;
|
||||||
*/
|
*/
|
||||||
class GetStatementOfAccountXML extends PaginateableAction
|
class GetStatementOfAccountXML extends PaginateableAction
|
||||||
{
|
{
|
||||||
// Request (not available after serialization, i.e. not available in processResponse()).
|
// Request (if you add a field here, update __serialize() and __unserialize() as well).
|
||||||
/** @var SEPAAccount */
|
/** @var SEPAAccount */
|
||||||
private $account;
|
private $account;
|
||||||
/** @var \DateTime */
|
/** @var \DateTime */
|
||||||
|
|
@ -98,7 +98,7 @@ class GetStatementOfAccountXML extends PaginateableAction
|
||||||
{
|
{
|
||||||
list(
|
list(
|
||||||
$parentSerialized,
|
$parentSerialized,
|
||||||
$this->account, $this->camtURN, $this->from, $this->to, $this->allAccounts
|
$this->account, $this->camtURN, $this->from, $this->to, $this->allAccounts,
|
||||||
) = $serialized;
|
) = $serialized;
|
||||||
|
|
||||||
is_array($parentSerialized) ?
|
is_array($parentSerialized) ?
|
||||||
|
|
@ -115,7 +115,6 @@ class GetStatementOfAccountXML extends PaginateableAction
|
||||||
return $this->xml;
|
return $this->xml;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||||
{
|
{
|
||||||
if ($upd === null) {
|
if ($upd === null) {
|
||||||
|
|
@ -149,7 +148,6 @@ class GetStatementOfAccountXML extends PaginateableAction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function processResponse(Message $response)
|
public function processResponse(Message $response)
|
||||||
{
|
{
|
||||||
parent::processResponse($response);
|
parent::processResponse($response);
|
||||||
|
|
|
||||||
|
|
@ -1,182 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Fhp\Action;
|
|
||||||
|
|
||||||
use Fhp\Model\SEPAAccount;
|
|
||||||
use Fhp\PaginateableAction;
|
|
||||||
use Fhp\Protocol\BPD;
|
|
||||||
use Fhp\Protocol\Message;
|
|
||||||
use Fhp\Protocol\UnexpectedResponseException;
|
|
||||||
use Fhp\Protocol\UPD;
|
|
||||||
use Fhp\Segment\Common\Kti;
|
|
||||||
use Fhp\Segment\EKP\HIEKP;
|
|
||||||
use Fhp\Segment\EKP\HIEKPSv2;
|
|
||||||
use Fhp\Segment\EKP\HKEKPv2;
|
|
||||||
use Fhp\Segment\HIRMS\Rueckmeldungscode;
|
|
||||||
use Fhp\UnsupportedException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves PDF bank statements (Elektronischer Kontoauszug) via HKEKP.
|
|
||||||
*/
|
|
||||||
class GetStatementPDF extends PaginateableAction
|
|
||||||
{
|
|
||||||
/** @var SEPAAccount */
|
|
||||||
private $account;
|
|
||||||
|
|
||||||
/** @var int|null Optional: specific statement number */
|
|
||||||
private $statementNumber;
|
|
||||||
|
|
||||||
/** @var int|null Optional: statement year */
|
|
||||||
private $statementYear;
|
|
||||||
|
|
||||||
/** @var bool Whether PDF is base64 encoded (from BPD) */
|
|
||||||
private $isBase64 = false;
|
|
||||||
|
|
||||||
// Response data
|
|
||||||
/** @var string Raw PDF data (may be from multiple pages) */
|
|
||||||
private $pdfData = '';
|
|
||||||
|
|
||||||
/** @var array Statement metadata from response */
|
|
||||||
private $statementInfo = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param SEPAAccount $account The account to get statements for
|
|
||||||
* @param int|null $statementNumber Optional: Request specific statement by number
|
|
||||||
* @param int|null $statementYear Optional: Year of the statement (required if number given)
|
|
||||||
* @return GetStatementPDF
|
|
||||||
*/
|
|
||||||
public static function create(
|
|
||||||
SEPAAccount $account,
|
|
||||||
?int $statementNumber = null,
|
|
||||||
?int $statementYear = null
|
|
||||||
): GetStatementPDF {
|
|
||||||
$result = new GetStatementPDF();
|
|
||||||
$result->account = $account;
|
|
||||||
$result->statementNumber = $statementNumber;
|
|
||||||
$result->statementYear = $statementYear;
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __serialize(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
parent::__serialize(),
|
|
||||||
$this->account,
|
|
||||||
$this->statementNumber,
|
|
||||||
$this->statementYear,
|
|
||||||
$this->isBase64,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __unserialize(array $serialized): void
|
|
||||||
{
|
|
||||||
list(
|
|
||||||
$parentSerialized,
|
|
||||||
$this->account,
|
|
||||||
$this->statementNumber,
|
|
||||||
$this->statementYear,
|
|
||||||
$this->isBase64
|
|
||||||
) = $serialized;
|
|
||||||
|
|
||||||
is_array($parentSerialized)
|
|
||||||
? parent::__unserialize($parentSerialized)
|
|
||||||
: parent::unserialize($parentSerialized);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return string The raw PDF data
|
|
||||||
*/
|
|
||||||
public function getPdfData(): string
|
|
||||||
{
|
|
||||||
$this->ensureDone();
|
|
||||||
|
|
||||||
// Decode base64 if needed
|
|
||||||
if ($this->isBase64 && !empty($this->pdfData)) {
|
|
||||||
$decoded = base64_decode($this->pdfData, true);
|
|
||||||
if ($decoded !== false) {
|
|
||||||
return $decoded;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->pdfData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array Statement metadata (number, year, iban, date, filename)
|
|
||||||
*/
|
|
||||||
public function getStatementInfo(): array
|
|
||||||
{
|
|
||||||
$this->ensureDone();
|
|
||||||
return $this->statementInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return bool Whether receipt confirmation is needed
|
|
||||||
*/
|
|
||||||
public function needsReceipt(): bool
|
|
||||||
{
|
|
||||||
$this->ensureDone();
|
|
||||||
return !empty($this->statementInfo['receiptCode']);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
|
||||||
{
|
|
||||||
/** @var HIEKPSv2|null $hiekps */
|
|
||||||
$hiekps = $bpd->getLatestSupportedParameters('HIEKPS');
|
|
||||||
|
|
||||||
if ($hiekps === null) {
|
|
||||||
throw new UnsupportedException('The bank does not support PDF statements (HKEKP).');
|
|
||||||
}
|
|
||||||
|
|
||||||
$param = $hiekps->getParameter();
|
|
||||||
$this->isBase64 = $param->isBase64Encoded();
|
|
||||||
|
|
||||||
// Check if historical statements are allowed
|
|
||||||
if ($this->statementNumber !== null && !$param->isHistoricalStatementsAllowed()) {
|
|
||||||
throw new UnsupportedException('The bank does not allow requesting historical statements by number.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return HKEKPv2::create(
|
|
||||||
Kti::fromAccount($this->account),
|
|
||||||
$this->statementNumber,
|
|
||||||
$this->statementYear
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function processResponse(Message $response)
|
|
||||||
{
|
|
||||||
parent::processResponse($response);
|
|
||||||
|
|
||||||
// Check if no statements available
|
|
||||||
if ($response->findRueckmeldung(Rueckmeldungscode::NICHT_VERFUEGBAR) !== null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var HIEKP[] $responseSegments */
|
|
||||||
$responseSegments = $response->findSegments(HIEKP::class);
|
|
||||||
|
|
||||||
if (empty($responseSegments)) {
|
|
||||||
// No segments but also no error = empty response
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($responseSegments as $hiekp) {
|
|
||||||
// Append PDF data (for pagination)
|
|
||||||
$this->pdfData .= $hiekp->getPdfData();
|
|
||||||
|
|
||||||
// Store metadata from first segment
|
|
||||||
if (empty($this->statementInfo)) {
|
|
||||||
$this->statementInfo = [
|
|
||||||
'statementNumber' => $hiekp->getStatementNumber(),
|
|
||||||
'statementYear' => $hiekp->getStatementYear(),
|
|
||||||
'iban' => $hiekp->getIban(),
|
|
||||||
'creationDate' => $hiekp->getCreationDate(),
|
|
||||||
'filename' => $hiekp->getFilename(),
|
|
||||||
'receiptCode' => $hiekp->needsReceipt() ? $hiekp->getReceiptCode() : null,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
42
vendor/nemiah/php-fints/lib/Fhp/Action/SendInternationalCreditTransfer.php
vendored
Executable file → Normal file
42
vendor/nemiah/php-fints/lib/Fhp/Action/SendInternationalCreditTransfer.php
vendored
Executable file → Normal file
|
|
@ -13,12 +13,11 @@ use Fhp\Syntax\Bin;
|
||||||
|
|
||||||
class SendInternationalCreditTransfer extends BaseAction
|
class SendInternationalCreditTransfer extends BaseAction
|
||||||
{
|
{
|
||||||
|
// Request (if you add a field here, update __serialize() and __unserialize() as well).
|
||||||
/** @var SEPAAccount */
|
/** @var SEPAAccount */
|
||||||
protected $account;
|
protected $account;
|
||||||
|
|
||||||
/** @var string */
|
/** @var string */
|
||||||
protected $dtavzData;
|
protected $dtavzData;
|
||||||
|
|
||||||
/** @var string|null */
|
/** @var string|null */
|
||||||
protected $dtavzVersion;
|
protected $dtavzVersion;
|
||||||
|
|
||||||
|
|
@ -36,6 +35,45 @@ class SendInternationalCreditTransfer extends BaseAction
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Beginning from PHP7.4 __unserialize is used for new generated strings, then this method is only used for previously generated strings - remove after May 2023
|
||||||
|
*/
|
||||||
|
public function serialize(): string
|
||||||
|
{
|
||||||
|
return serialize($this->__serialize());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __serialize(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
parent::__serialize(),
|
||||||
|
$this->account, $this->dtavzData, $this->dtavzVersion,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Beginning from PHP7.4 __unserialize is used for new generated strings, then this method is only used for previously generated strings - remove after May 2023
|
||||||
|
*
|
||||||
|
* @param string $serialized
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function unserialize($serialized)
|
||||||
|
{
|
||||||
|
self::__unserialize(unserialize($serialized));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __unserialize(array $serialized): void
|
||||||
|
{
|
||||||
|
list(
|
||||||
|
$parentSerialized,
|
||||||
|
$this->account, $this->dtavzData, $this->dtavzVersion,
|
||||||
|
) = $serialized;
|
||||||
|
|
||||||
|
is_array($parentSerialized) ?
|
||||||
|
parent::__unserialize($parentSerialized) :
|
||||||
|
parent::unserialize($parentSerialized);
|
||||||
|
}
|
||||||
|
|
||||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||||
{
|
{
|
||||||
/** @var HIAUBSv9 $hiaubs */
|
/** @var HIAUBSv9 $hiaubs */
|
||||||
|
|
|
||||||
17
vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPADirectDebit.php
vendored
Executable file → Normal file
17
vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPADirectDebit.php
vendored
Executable file → Normal file
|
|
@ -11,8 +11,10 @@ use Fhp\Segment\Common\Btg;
|
||||||
use Fhp\Segment\Common\Kti;
|
use Fhp\Segment\Common\Kti;
|
||||||
use Fhp\Segment\DME\HIDMESv1;
|
use Fhp\Segment\DME\HIDMESv1;
|
||||||
use Fhp\Segment\DME\HIDMESv2;
|
use Fhp\Segment\DME\HIDMESv2;
|
||||||
|
use Fhp\Segment\DME\HKDMEv2;
|
||||||
use Fhp\Segment\DSE\HIDSESv2;
|
use Fhp\Segment\DSE\HIDSESv2;
|
||||||
use Fhp\Segment\DSE\HIDXES;
|
use Fhp\Segment\DSE\HIDXES;
|
||||||
|
use Fhp\Segment\DSE\HKDSEv2;
|
||||||
use Fhp\Segment\SPA\HISPAS;
|
use Fhp\Segment\SPA\HISPAS;
|
||||||
use Fhp\Syntax\Bin;
|
use Fhp\Syntax\Bin;
|
||||||
use Fhp\UnsupportedException;
|
use Fhp\UnsupportedException;
|
||||||
|
|
@ -22,27 +24,24 @@ use Fhp\UnsupportedException;
|
||||||
*/
|
*/
|
||||||
class SendSEPADirectDebit extends BaseAction
|
class SendSEPADirectDebit extends BaseAction
|
||||||
{
|
{
|
||||||
|
// Request (if you add a field here, update __serialize() and __unserialize() as well).
|
||||||
/** @var SEPAAccount */
|
/** @var SEPAAccount */
|
||||||
protected $account;
|
protected $account;
|
||||||
|
|
||||||
/** @var string */
|
/** @var string */
|
||||||
protected $painMessage;
|
protected $painMessage;
|
||||||
|
|
||||||
/** @var string */
|
/** @var string */
|
||||||
protected $painNamespace;
|
protected $painNamespace;
|
||||||
|
|
||||||
/** @var float */
|
/** @var float */
|
||||||
protected $ctrlSum;
|
protected $ctrlSum;
|
||||||
|
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
protected $singleDirectDebit = false;
|
protected $singleDirectDebit = false;
|
||||||
|
|
||||||
/** @var bool */
|
/** @var bool */
|
||||||
protected $tryToUseControlSumForSingleTransactions = false;
|
protected $tryToUseControlSumForSingleTransactions = false;
|
||||||
|
|
||||||
/** @var string */
|
/** @var string */
|
||||||
private $coreType;
|
private $coreType;
|
||||||
|
|
||||||
|
// There are no result fields. This action is simply marked as done to indicate that the transfer was executed.
|
||||||
|
|
||||||
public static function create(SEPAAccount $account, string $painMessage, bool $tryToUseControlSumForSingleTransactions = false): SendSEPADirectDebit
|
public static function create(SEPAAccount $account, string $painMessage, bool $tryToUseControlSumForSingleTransactions = false): SendSEPADirectDebit
|
||||||
{
|
{
|
||||||
if (preg_match('/xmlns="(?<namespace>[^"]+)"/s', $painMessage, $matches) === 1) {
|
if (preg_match('/xmlns="(?<namespace>[^"]+)"/s', $painMessage, $matches) === 1) {
|
||||||
|
|
@ -114,7 +113,7 @@ class SendSEPADirectDebit extends BaseAction
|
||||||
{
|
{
|
||||||
list(
|
list(
|
||||||
$parentSerialized,
|
$parentSerialized,
|
||||||
$this->singleDirectDebit, $this->tryToUseControlSumForSingleTransactions, $this->ctrlSum, $this->coreType, $this->painMessage, $this->painNamespace, $this->account
|
$this->singleDirectDebit, $this->tryToUseControlSumForSingleTransactions, $this->ctrlSum, $this->coreType, $this->painMessage, $this->painNamespace, $this->account,
|
||||||
) = $serialized;
|
) = $serialized;
|
||||||
|
|
||||||
is_array($parentSerialized) ?
|
is_array($parentSerialized) ?
|
||||||
|
|
@ -151,7 +150,7 @@ class SendSEPADirectDebit extends BaseAction
|
||||||
// Sometimes the Bank reports supported schemas with a "_GBIC_X" postfix.
|
// Sometimes the Bank reports supported schemas with a "_GBIC_X" postfix.
|
||||||
// GIBC_X stands for German Banking Industry Committee and a version counter.
|
// GIBC_X stands for German Banking Industry Committee and a version counter.
|
||||||
$xmlSchema = $this->painNamespace;
|
$xmlSchema = $this->painNamespace;
|
||||||
$matchingSchemas = array_filter($supportedPainNamespaces, function($value) use ($xmlSchema) {
|
$matchingSchemas = array_filter($supportedPainNamespaces, function ($value) use ($xmlSchema) {
|
||||||
// For example urn:iso:std:iso:20022:tech:xsd:pain.008.001.08 from the xml matches
|
// For example urn:iso:std:iso:20022:tech:xsd:pain.008.001.08 from the xml matches
|
||||||
// urn:iso:std:iso:20022:tech:xsd:pain.008.001.08_GBIC_4
|
// urn:iso:std:iso:20022:tech:xsd:pain.008.001.08_GBIC_4
|
||||||
return str_starts_with($value, $xmlSchema);
|
return str_starts_with($value, $xmlSchema);
|
||||||
|
|
@ -162,7 +161,7 @@ class SendSEPADirectDebit extends BaseAction
|
||||||
. implode(', ', $supportedPainNamespaces));
|
. implode(', ', $supportedPainNamespaces));
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var mixed $hkdxe */ // TODO Put a new interface type here.
|
/** @var HKDMEv2|HKDSEv2|HIDXES $hkdxe */
|
||||||
$hkdxe = $hidxes->createRequestSegment();
|
$hkdxe = $hidxes->createRequestSegment();
|
||||||
$hkdxe->kontoverbindungInternational = Kti::fromAccount($this->account);
|
$hkdxe->kontoverbindungInternational = Kti::fromAccount($this->account);
|
||||||
$hkdxe->sepaDescriptor = $this->painNamespace;
|
$hkdxe->sepaDescriptor = $this->painNamespace;
|
||||||
|
|
|
||||||
51
vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPARealtimeTransfer.php
vendored
Executable file → Normal file
51
vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPARealtimeTransfer.php
vendored
Executable file → Normal file
|
|
@ -23,15 +23,17 @@ use Fhp\UnsupportedException;
|
||||||
*/
|
*/
|
||||||
class SendSEPARealtimeTransfer extends BaseAction
|
class SendSEPARealtimeTransfer extends BaseAction
|
||||||
{
|
{
|
||||||
|
// Request (if you add a field here, update __serialize() and __unserialize() as well).
|
||||||
/** @var SEPAAccount */
|
/** @var SEPAAccount */
|
||||||
private $account;
|
private $account;
|
||||||
/** @var string */
|
/** @var string */
|
||||||
private $painMessage;
|
private $painMessage;
|
||||||
/** @var string */
|
/** @var string */
|
||||||
private $xmlSchema;
|
private $xmlSchema;
|
||||||
|
|
||||||
private bool $allowConversionToSEPATransfer = true;
|
private bool $allowConversionToSEPATransfer = true;
|
||||||
|
|
||||||
|
// There are no result fields. This action is simply marked as done to indicate that the transfer was executed.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param SEPAAccount $account The account from which the transfer will be sent.
|
* @param SEPAAccount $account The account from which the transfer will be sent.
|
||||||
* @param string $painMessage An XML-formatted ISO 20022 message. You may want to use github.com/nemiah/phpSepaXml
|
* @param string $painMessage An XML-formatted ISO 20022 message. You may want to use github.com/nemiah/phpSepaXml
|
||||||
|
|
@ -52,7 +54,45 @@ class SendSEPARealtimeTransfer extends BaseAction
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
/**
|
||||||
|
* @deprecated Beginning from PHP7.4 __unserialize is used for new generated strings, then this method is only used for previously generated strings - remove after May 2023
|
||||||
|
*/
|
||||||
|
public function serialize(): string
|
||||||
|
{
|
||||||
|
return serialize($this->__serialize());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __serialize(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
parent::__serialize(),
|
||||||
|
$this->account, $this->painMessage, $this->xmlSchema, $this->allowConversionToSEPATransfer,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Beginning from PHP7.4 __unserialize is used for new generated strings, then this method is only used for previously generated strings - remove after May 2023
|
||||||
|
*
|
||||||
|
* @param string $serialized
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function unserialize($serialized)
|
||||||
|
{
|
||||||
|
self::__unserialize(unserialize($serialized));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __unserialize(array $serialized): void
|
||||||
|
{
|
||||||
|
list(
|
||||||
|
$parentSerialized,
|
||||||
|
$this->account, $this->painMessage, $this->xmlSchema, $this->allowConversionToSEPATransfer,
|
||||||
|
) = $serialized;
|
||||||
|
|
||||||
|
is_array($parentSerialized) ?
|
||||||
|
parent::__unserialize($parentSerialized) :
|
||||||
|
parent::unserialize($parentSerialized);
|
||||||
|
}
|
||||||
|
|
||||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||||
{
|
{
|
||||||
/** @var HIIPZSv1|HIIPZSv2 $hiipzs */
|
/** @var HIIPZSv1|HIIPZSv2 $hiipzs */
|
||||||
|
|
@ -70,7 +110,7 @@ class SendSEPARealtimeTransfer extends BaseAction
|
||||||
// Sometimes the Bank reports supported schemas with a "_GBIC_X" postfix.
|
// Sometimes the Bank reports supported schemas with a "_GBIC_X" postfix.
|
||||||
// GIBC_X stands for German Banking Industry Committee and a version counter.
|
// GIBC_X stands for German Banking Industry Committee and a version counter.
|
||||||
$xmlSchema = $this->xmlSchema;
|
$xmlSchema = $this->xmlSchema;
|
||||||
$matchingSchemas = array_filter($supportedSchemas, function($value) use ($xmlSchema) {
|
$matchingSchemas = array_filter($supportedSchemas, function ($value) use ($xmlSchema) {
|
||||||
// For example urn:iso:std:iso:20022:tech:xsd:pain.001.001.09 from the xml matches
|
// For example urn:iso:std:iso:20022:tech:xsd:pain.001.001.09 from the xml matches
|
||||||
// urn:iso:std:iso:20022:tech:xsd:pain.001.001.09_GBIC_4
|
// urn:iso:std:iso:20022:tech:xsd:pain.001.001.09_GBIC_4
|
||||||
return str_starts_with($value, $xmlSchema);
|
return str_starts_with($value, $xmlSchema);
|
||||||
|
|
@ -92,7 +132,6 @@ class SendSEPARealtimeTransfer extends BaseAction
|
||||||
return $hkipz;
|
return $hkipz;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function processResponse(Message $response)
|
public function processResponse(Message $response)
|
||||||
{
|
{
|
||||||
parent::processResponse($response);
|
parent::processResponse($response);
|
||||||
|
|
@ -106,8 +145,8 @@ class SendSEPARealtimeTransfer extends BaseAction
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($response->findRueckmeldung(Rueckmeldungscode::ENTGEGENGENOMMEN) === null &&
|
if ($response->findRueckmeldung(Rueckmeldungscode::ENTGEGENGENOMMEN) === null
|
||||||
$response->findRueckmeldung(Rueckmeldungscode::AUSGEFUEHRT) === null) {
|
&& $response->findRueckmeldung(Rueckmeldungscode::AUSGEFUEHRT) === null) {
|
||||||
throw new UnexpectedResponseException('Bank did not confirm SEPATransfer execution');
|
throw new UnexpectedResponseException('Bank did not confirm SEPATransfer execution');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
83
vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPATransfer.php
vendored
Executable file → Normal file
83
vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPATransfer.php
vendored
Executable file → Normal file
|
|
@ -19,12 +19,17 @@ use Fhp\UnsupportedException;
|
||||||
*/
|
*/
|
||||||
class SendSEPATransfer extends BaseAction
|
class SendSEPATransfer extends BaseAction
|
||||||
{
|
{
|
||||||
|
// Request (if you add a field here, update __serialize() and __unserialize() as well).
|
||||||
/** @var SEPAAccount */
|
/** @var SEPAAccount */
|
||||||
private $account;
|
private $account;
|
||||||
/** @var string */
|
/** @var string */
|
||||||
private $painMessage;
|
private $painMessage;
|
||||||
/** @var string */
|
/** @var string */
|
||||||
private $xmlSchema;
|
private $xmlSchema;
|
||||||
|
/** @var bool */
|
||||||
|
private $singleBookingRequested = false;
|
||||||
|
|
||||||
|
// There are no result fields. This action is simply marked as done to indicate that the transfer was executed.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param SEPAAccount $account The account from which the transfer will be sent.
|
* @param SEPAAccount $account The account from which the transfer will be sent.
|
||||||
|
|
@ -44,11 +49,62 @@ class SendSEPATransfer extends BaseAction
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
/**
|
||||||
|
* Request individual bookings instead of a batch booking on the bank statement.
|
||||||
|
* Only applicable for batch transfers (Sammelüberweisung).
|
||||||
|
*
|
||||||
|
* @param bool $singleBookingRequested If true, each transaction appears separately on the statement.
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setSingleBookingRequested(bool $singleBookingRequested): self
|
||||||
|
{
|
||||||
|
$this->singleBookingRequested = $singleBookingRequested;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Beginning from PHP7.4 __unserialize is used for new generated strings, then this method is only used for previously generated strings - remove after May 2023
|
||||||
|
*/
|
||||||
|
public function serialize(): string
|
||||||
|
{
|
||||||
|
return serialize($this->__serialize());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __serialize(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
parent::__serialize(),
|
||||||
|
$this->account, $this->painMessage, $this->xmlSchema, $this->singleBookingRequested,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Beginning from PHP7.4 __unserialize is used for new generated strings, then this method is only used for previously generated strings - remove after May 2023
|
||||||
|
*
|
||||||
|
* @param string $serialized
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function unserialize($serialized)
|
||||||
|
{
|
||||||
|
self::__unserialize(unserialize($serialized));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __unserialize(array $serialized): void
|
||||||
|
{
|
||||||
|
list(
|
||||||
|
$parentSerialized,
|
||||||
|
$this->account, $this->painMessage, $this->xmlSchema, $this->singleBookingRequested,
|
||||||
|
) = $serialized;
|
||||||
|
|
||||||
|
is_array($parentSerialized) ?
|
||||||
|
parent::__unserialize($parentSerialized) :
|
||||||
|
parent::unserialize($parentSerialized);
|
||||||
|
}
|
||||||
|
|
||||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||||
{
|
{
|
||||||
//ANALYSE XML FOR RECEIPTS AND PAYMENT DATE
|
// ANALYSE XML FOR RECEIPTS AND PAYMENT DATE
|
||||||
$xmlAsObject = simplexml_load_string($this->painMessage, "SimpleXMLElement", LIBXML_NOCDATA);
|
$xmlAsObject = simplexml_load_string($this->painMessage, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||||
$numberOfTransactions = $xmlAsObject->CstmrCdtTrfInitn->GrpHdr->NbOfTxs;
|
$numberOfTransactions = $xmlAsObject->CstmrCdtTrfInitn->GrpHdr->NbOfTxs;
|
||||||
$hasReqdExDates = false;
|
$hasReqdExDates = false;
|
||||||
foreach ($xmlAsObject->CstmrCdtTrfInitn?->PmtInf as $pmtInfo) {
|
foreach ($xmlAsObject->CstmrCdtTrfInitn?->PmtInf as $pmtInfo) {
|
||||||
|
|
@ -59,25 +115,21 @@ class SendSEPATransfer extends BaseAction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//NOW READ OUT, WICH SEGMENT SHOULD BE USED:
|
// NOW READ OUT, WICH SEGMENT SHOULD BE USED:
|
||||||
if ($numberOfTransactions > 1 && $hasReqdExDates) {
|
if ($numberOfTransactions > 1 && $hasReqdExDates) {
|
||||||
|
|
||||||
// Terminierte SEPA-Sammelüberweisung (Segment HKCME / Kennung HICMES)
|
// Terminierte SEPA-Sammelüberweisung (Segment HKCME / Kennung HICMES)
|
||||||
$segmentID = 'HICMES';
|
$segmentID = 'HICMES';
|
||||||
$segment = \Fhp\Segment\CME\HKCMEv1::createEmpty();
|
$segment = \Fhp\Segment\CME\HKCMEv1::createEmpty();
|
||||||
} elseif ($numberOfTransactions == 1 && $hasReqdExDates) {
|
} elseif ($numberOfTransactions == 1 && $hasReqdExDates) {
|
||||||
|
|
||||||
// Terminierte SEPA-Überweisung (Segment HKCSE / Kennung HICSES)
|
// Terminierte SEPA-Überweisung (Segment HKCSE / Kennung HICSES)
|
||||||
$segmentID = 'HICSES';
|
$segmentID = 'HICSES';
|
||||||
$segment = \Fhp\Segment\CSE\HKCSEv1::createEmpty();
|
$segment = \Fhp\Segment\CSE\HKCSEv1::createEmpty();
|
||||||
} elseif ($numberOfTransactions > 1 && !$hasReqdExDates) {
|
} elseif ($numberOfTransactions > 1 && !$hasReqdExDates) {
|
||||||
|
|
||||||
// SEPA-Sammelüberweisungen (Segment HKCCM / Kennung HICSES)
|
// SEPA-Sammelüberweisungen (Segment HKCCM / Kennung HICSES)
|
||||||
$segmentID = 'HICSES';
|
$segmentID = 'HICSES';
|
||||||
$segment = \Fhp\Segment\CCM\HKCCMv1::createEmpty();
|
$segment = \Fhp\Segment\CCM\HKCCMv1::createEmpty();
|
||||||
} else {
|
} else {
|
||||||
|
// SEPA Einzelüberweisung (Segment HKCCS / Kennung HICCSS).
|
||||||
//SEPA Einzelüberweisung (Segment HKCCS / Kennung HICCSS).
|
|
||||||
$segmentID = 'HICCSS';
|
$segmentID = 'HICCSS';
|
||||||
$segment = \Fhp\Segment\CCS\HKCCSv1::createEmpty();
|
$segment = \Fhp\Segment\CCS\HKCCSv1::createEmpty();
|
||||||
}
|
}
|
||||||
|
|
@ -93,7 +145,7 @@ class SendSEPATransfer extends BaseAction
|
||||||
// Sometimes the Bank reports supported schemas with a "_GBIC_X" postfix.
|
// Sometimes the Bank reports supported schemas with a "_GBIC_X" postfix.
|
||||||
// GIBC_X stands for German Banking Industry Committee and a version counter.
|
// GIBC_X stands for German Banking Industry Committee and a version counter.
|
||||||
$xmlSchema = $this->xmlSchema;
|
$xmlSchema = $this->xmlSchema;
|
||||||
$matchingSchemas = array_filter($supportedSchemas, function($value) use ($xmlSchema) {
|
$matchingSchemas = array_filter($supportedSchemas, function ($value) use ($xmlSchema) {
|
||||||
// For example urn:iso:std:iso:20022:tech:xsd:pain.001.001.09 from the xml matches
|
// For example urn:iso:std:iso:20022:tech:xsd:pain.001.001.09 from the xml matches
|
||||||
// urn:iso:std:iso:20022:tech:xsd:pain.001.001.09_GBIC_4
|
// urn:iso:std:iso:20022:tech:xsd:pain.001.001.09_GBIC_4
|
||||||
return str_starts_with($value, $xmlSchema);
|
return str_starts_with($value, $xmlSchema);
|
||||||
|
|
@ -107,10 +159,19 @@ class SendSEPATransfer extends BaseAction
|
||||||
$segment->kontoverbindungInternational = Kti::fromAccount($this->account);
|
$segment->kontoverbindungInternational = Kti::fromAccount($this->account);
|
||||||
$segment->sepaDescriptor = $this->xmlSchema;
|
$segment->sepaDescriptor = $this->xmlSchema;
|
||||||
$segment->sepaPainMessage = new Bin($this->painMessage);
|
$segment->sepaPainMessage = new Bin($this->painMessage);
|
||||||
|
|
||||||
|
// For batch transfers: set einzelbuchungGewuenscht if bank allows it
|
||||||
|
if ($numberOfTransactions > 1) {
|
||||||
|
$paramSegmentId = $hasReqdExDates ? 'HICMES' : 'HICCMS';
|
||||||
|
$paramSegment = $bpd->getLatestSupportedParameters($paramSegmentId);
|
||||||
|
if ($paramSegment !== null && $paramSegment->getParameter()->einzelbuchungErlaubt) {
|
||||||
|
$segment->einzelbuchungGewuenscht = $this->singleBookingRequested;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return $segment;
|
return $segment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function processResponse(Message $response)
|
public function processResponse(Message $response)
|
||||||
{
|
{
|
||||||
parent::processResponse($response);
|
parent::processResponse($response);
|
||||||
|
|
|
||||||
107
vendor/nemiah/php-fints/lib/Fhp/BaseAction.php
vendored
Executable file → Normal file
107
vendor/nemiah/php-fints/lib/Fhp/BaseAction.php
vendored
Executable file → Normal file
|
|
@ -4,13 +4,17 @@
|
||||||
|
|
||||||
namespace Fhp;
|
namespace Fhp;
|
||||||
|
|
||||||
|
use Fhp\Model\PollingInfo;
|
||||||
use Fhp\Model\TanRequest;
|
use Fhp\Model\TanRequest;
|
||||||
|
use Fhp\Model\VopConfirmationRequest;
|
||||||
use Fhp\Protocol\ActionIncompleteException;
|
use Fhp\Protocol\ActionIncompleteException;
|
||||||
|
use Fhp\Protocol\ActionPendingException;
|
||||||
use Fhp\Protocol\BPD;
|
use Fhp\Protocol\BPD;
|
||||||
use Fhp\Protocol\Message;
|
use Fhp\Protocol\Message;
|
||||||
use Fhp\Protocol\TanRequiredException;
|
use Fhp\Protocol\TanRequiredException;
|
||||||
use Fhp\Protocol\UnexpectedResponseException;
|
use Fhp\Protocol\UnexpectedResponseException;
|
||||||
use Fhp\Protocol\UPD;
|
use Fhp\Protocol\UPD;
|
||||||
|
use Fhp\Protocol\VopConfirmationRequiredException;
|
||||||
use Fhp\Segment\BaseSegment;
|
use Fhp\Segment\BaseSegment;
|
||||||
use Fhp\Segment\HIRMS\Rueckmeldung;
|
use Fhp\Segment\HIRMS\Rueckmeldung;
|
||||||
use Fhp\Segment\HIRMS\Rueckmeldungscode;
|
use Fhp\Segment\HIRMS\Rueckmeldungscode;
|
||||||
|
|
@ -37,37 +41,37 @@ use Fhp\Segment\HIRMS\Rueckmeldungscode;
|
||||||
abstract class BaseAction implements \Serializable
|
abstract class BaseAction implements \Serializable
|
||||||
{
|
{
|
||||||
/** @var int[] Stores segment numbers that were assigned to the segments returned from {@link createRequest()}. */
|
/** @var int[] Stores segment numbers that were assigned to the segments returned from {@link createRequest()}. */
|
||||||
protected $requestSegmentNumbers;
|
protected ?array $requestSegmentNumbers = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string|null Contains the name of the segment, that might need a tan, used by FinTs::execute to signal
|
* Contains the name of the segment, that might need a tan, used by FinTs::execute to signal
|
||||||
* to the bank that supplying a tan is supported.
|
* to the bank that supplying a tan is supported.
|
||||||
*/
|
*/
|
||||||
protected $needTanForSegment = null;
|
protected ?string $needTanForSegment = null;
|
||||||
|
|
||||||
/**
|
/** If set, the last response from the server regarding this action asked for a TAN from the user. */
|
||||||
* If set, the last response from the server regarding this action asked for a TAN from the user.
|
protected ?TanRequest $tanRequest = null;
|
||||||
* @var TanRequest|null
|
|
||||||
*/
|
|
||||||
protected $tanRequest;
|
|
||||||
|
|
||||||
/** @var bool */
|
/** If set, this action is currently waiting for a long-running operation on the server to complete. */
|
||||||
protected $isDone = false;
|
protected ?PollingInfo $pollingInfo = null;
|
||||||
|
|
||||||
|
/** If set, this action needs the user's confirmation to be completed. */
|
||||||
|
protected ?VopConfirmationRequest $vopConfirmationRequest = null;
|
||||||
|
|
||||||
|
protected bool $isDone = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will be populated with the message the bank sent along with the success indication, can be used to show to
|
* Will be populated with the message the bank sent along with the success indication, can be used to show to
|
||||||
* the user.
|
* the user.
|
||||||
* @var string
|
|
||||||
*/
|
*/
|
||||||
public $successMessage;
|
public ?string $successMessage = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Beginning from PHP7.4 __unserialize is used for new generated strings, then this method is only used for previously generated strings - remove after May 2023
|
* @deprecated Beginning from PHP7.4 __unserialize is used for new generated strings, then this method is only used for previously generated strings - remove after May 2023
|
||||||
*
|
*
|
||||||
* NOTE: A common mistake is to call this function directly. Instead, you probably want `serialize($instance)`.
|
* NOTE: A common mistake is to call this function directly. Instead, you probably want `serialize($instance)`.
|
||||||
*
|
*
|
||||||
* An action can only be serialized *after* it has been executed in case it needs a TAN, i.e. when the result is not
|
* An action can only be serialized before it was completed.
|
||||||
* present yet.
|
|
||||||
* If a sub-class overrides this, it should call the parent function and include it in its result.
|
* If a sub-class overrides this, it should call the parent function and include it in its result.
|
||||||
* @return string The serialized action, e.g. for storage in a database. This will not contain sensitive user data.
|
* @return string The serialized action, e.g. for storage in a database. This will not contain sensitive user data.
|
||||||
*/
|
*/
|
||||||
|
|
@ -77,21 +81,23 @@ abstract class BaseAction implements \Serializable
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An action can only be serialized *after* it has been executed in case it needs a TAN, i.e. when the result is not
|
* An action can only be serialized before it was completed.
|
||||||
* present yet.
|
|
||||||
* If a sub-class overrides this, it should call the parent function and include it in its result.
|
* If a sub-class overrides this, it should call the parent function and include it in its result.
|
||||||
*
|
*
|
||||||
* @return array The serialized action, e.g. for storage in a database. This will not contain sensitive user data.
|
* @return array The serialized action, e.g. for storage in a database. This will not contain sensitive user data.
|
||||||
|
* Note that this is not necessarily valid UTF-8, so you should store it as a BLOB column or raw bytes.
|
||||||
*/
|
*/
|
||||||
public function __serialize(): array
|
public function __serialize(): array
|
||||||
{
|
{
|
||||||
if (!$this->needsTan()) {
|
if ($this->isDone()) {
|
||||||
throw new \RuntimeException('Cannot serialize this action, because it is not waiting for a TAN.');
|
throw new \RuntimeException('Completed actions cannot be serialized.');
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
$this->requestSegmentNumbers,
|
$this->requestSegmentNumbers,
|
||||||
$this->tanRequest,
|
$this->tanRequest,
|
||||||
$this->needTanForSegment,
|
$this->needTanForSegment,
|
||||||
|
$this->pollingInfo,
|
||||||
|
$this->vopConfirmationRequest,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,8 +117,10 @@ abstract class BaseAction implements \Serializable
|
||||||
list(
|
list(
|
||||||
$this->requestSegmentNumbers,
|
$this->requestSegmentNumbers,
|
||||||
$this->tanRequest,
|
$this->tanRequest,
|
||||||
$this->needTanForSegment
|
$this->needTanForSegment,
|
||||||
) = $serialized;
|
$this->pollingInfo,
|
||||||
|
$this->vopConfirmationRequest,
|
||||||
|
) = array_pad($serialized, 5, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -144,25 +152,54 @@ abstract class BaseAction implements \Serializable
|
||||||
return $this->tanRequest;
|
return $this->tanRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function needsPollingWait(): bool
|
||||||
|
{
|
||||||
|
return !$this->isDone() && $this->pollingInfo !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPollingInfo(): ?PollingInfo
|
||||||
|
{
|
||||||
|
return $this->pollingInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function needsVopConfirmation(): bool
|
||||||
|
{
|
||||||
|
return !$this->isDone() && $this->vopConfirmationRequest !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVopConfirmationRequest(): ?VopConfirmationRequest
|
||||||
|
{
|
||||||
|
return $this->vopConfirmationRequest;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Throws an exception unless this action has been successfully executed, i.e. in the following cases:
|
* Throws an exception unless this action has been successfully executed, i.e. in the following cases:
|
||||||
* - the action has not been {@link FinTs::execute()}-d at all or the {@link FinTs::execute()} call for it threw an
|
* - the action has not been {@link FinTs::execute()}-d at all or the {@link FinTs::execute()} call for it threw an
|
||||||
* exception,
|
* exception,
|
||||||
* - the action is awaiting a TAN/confirmation (as per {@link BaseAction::needsTan()}.
|
* - the action is awaiting a TAN/confirmation (as per {@link BaseAction::needsTan()},
|
||||||
|
* - the action is pending a long-running operation on the bank server ({@link BaseAction::needsPollingWait()}),
|
||||||
|
* - the action is awaiting the user's confirmation of the Verification of Payee result (as per
|
||||||
|
* {@link BaseAction::needsVopConfirmation()}).
|
||||||
*
|
*
|
||||||
* After executing an action, you can use this function to make sure that it succeeded. This is especially useful
|
* After executing an action, you can use this function to make sure that it succeeded. This is especially useful
|
||||||
* for actions that don't have any results (as each result getter would call {@link ensureDone()} internally).
|
* for actions that don't have any results (as each result getter would call {@link ensureDone()} internally).
|
||||||
* On the other hand, you do not need to call this function if you make sure that (1) you called
|
* On the other hand, you do not need to call this function if you make sure that (1) you called
|
||||||
* {@link FinTs::execute()} and (2) you checked {@link needsTan()} and, if it returned true, supplied a TAN by
|
* {@link FinTs::execute()} and (2) you checked and resolved all other special outcome states documented there.
|
||||||
* calling {@ink FinTs::submitTan()}. Note that both exception types thrown from this method are sub-classes of
|
* Note that both exception types thrown from this method are sub-classes of {@link \RuntimeException}, so you
|
||||||
* {@link \RuntimeException}, so you shouldn't need a try-catch block at the call site for this.
|
* shouldn't need a try-catch block at the call site for this.
|
||||||
* @throws ActionIncompleteException If the action hasn't even been executed.
|
* @throws ActionIncompleteException If the action hasn't even been executed.
|
||||||
|
* @throws ActionPendingException If the action is pending a long-running server operation that needs polling.
|
||||||
|
* @throws VopConfirmationRequiredException If the action requires the user's confirmation for VOP.
|
||||||
* @throws TanRequiredException If the action needs a TAN.
|
* @throws TanRequiredException If the action needs a TAN.
|
||||||
*/
|
*/
|
||||||
public function ensureDone()
|
public function ensureDone(): void
|
||||||
{
|
{
|
||||||
if ($this->tanRequest !== null) {
|
if ($this->tanRequest !== null) {
|
||||||
throw new TanRequiredException($this->tanRequest);
|
throw new TanRequiredException($this->tanRequest);
|
||||||
|
} elseif ($this->pollingInfo !== null) {
|
||||||
|
throw new ActionPendingException($this->pollingInfo);
|
||||||
|
} elseif ($this->vopConfirmationRequest !== null) {
|
||||||
|
throw new VopConfirmationRequiredException($this->vopConfirmationRequest);
|
||||||
} elseif (!$this->isDone()) {
|
} elseif (!$this->isDone()) {
|
||||||
throw new ActionIncompleteException();
|
throw new ActionIncompleteException();
|
||||||
}
|
}
|
||||||
|
|
@ -231,7 +268,7 @@ abstract class BaseAction implements \Serializable
|
||||||
/** @return int[] */
|
/** @return int[] */
|
||||||
public function getRequestSegmentNumbers(): array
|
public function getRequestSegmentNumbers(): array
|
||||||
{
|
{
|
||||||
return $this->requestSegmentNumbers;
|
return $this->requestSegmentNumbers ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -248,11 +285,21 @@ abstract class BaseAction implements \Serializable
|
||||||
$this->requestSegmentNumbers = $requestSegmentNumbers;
|
$this->requestSegmentNumbers = $requestSegmentNumbers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** To be called only by the FinTs instance that executes this action. */
|
||||||
* To be called only by the FinTs instance that executes this action.
|
final public function setTanRequest(?TanRequest $tanRequest): void
|
||||||
*/
|
|
||||||
final public function setTanRequest(?TanRequest $tanRequest)
|
|
||||||
{
|
{
|
||||||
$this->tanRequest = $tanRequest;
|
$this->tanRequest = $tanRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** To be called only by the FinTs instance that executes this action. */
|
||||||
|
final public function setPollingInfo(?PollingInfo $pollingInfo): void
|
||||||
|
{
|
||||||
|
$this->pollingInfo = $pollingInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** To be called only by the FinTs instance that executes this action. */
|
||||||
|
final public function setVopConfirmationRequest(?VopConfirmationRequest $vopConfirmationRequest): void
|
||||||
|
{
|
||||||
|
$this->vopConfirmationRequest = $vopConfirmationRequest;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
34
vendor/nemiah/php-fints/lib/Fhp/Connection.php
vendored
Executable file → Normal file
34
vendor/nemiah/php-fints/lib/Fhp/Connection.php
vendored
Executable file → Normal file
|
|
@ -7,25 +7,10 @@ namespace Fhp;
|
||||||
*/
|
*/
|
||||||
class Connection
|
class Connection
|
||||||
{
|
{
|
||||||
/**
|
protected string $url;
|
||||||
* @var string
|
protected ?\CurlHandle $curlHandle = null;
|
||||||
*/
|
protected int $timeoutConnect = 15;
|
||||||
protected $url;
|
protected int $timeoutResponse = 30;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var resource
|
|
||||||
*/
|
|
||||||
protected $curlHandle;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
protected $timeoutConnect = 15;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
protected $timeoutResponse = 30;
|
|
||||||
|
|
||||||
public function __construct(string $url, int $timeoutConnect = 15, int $timeoutResponse = 30)
|
public function __construct(string $url, int $timeoutConnect = 15, int $timeoutResponse = 30)
|
||||||
{
|
{
|
||||||
|
|
@ -34,9 +19,12 @@ class Connection
|
||||||
$this->timeoutResponse = $timeoutResponse;
|
$this->timeoutResponse = $timeoutResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function connect()
|
/**
|
||||||
|
* @throws CurlException When initializing cURL fails.
|
||||||
|
*/
|
||||||
|
private function connect(): void
|
||||||
{
|
{
|
||||||
$this->curlHandle = curl_init();
|
$this->curlHandle = curl_init() ?: throw new CurlException('Failed initializing cURL.');
|
||||||
|
|
||||||
curl_setopt($this->curlHandle, CURLOPT_SSL_VERIFYPEER, true);
|
curl_setopt($this->curlHandle, CURLOPT_SSL_VERIFYPEER, true);
|
||||||
curl_setopt($this->curlHandle, CURLOPT_SSL_VERIFYHOST, 2);
|
curl_setopt($this->curlHandle, CURLOPT_SSL_VERIFYHOST, 2);
|
||||||
|
|
@ -52,7 +40,7 @@ class Connection
|
||||||
curl_setopt($this->curlHandle, CURLOPT_HTTPHEADER, ['cache-control: no-cache', 'Content-Type: text/plain']);
|
curl_setopt($this->curlHandle, CURLOPT_HTTPHEADER, ['cache-control: no-cache', 'Content-Type: text/plain']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function disconnect()
|
public function disconnect(): void
|
||||||
{
|
{
|
||||||
if ($this->curlHandle !== null) {
|
if ($this->curlHandle !== null) {
|
||||||
curl_close($this->curlHandle);
|
curl_close($this->curlHandle);
|
||||||
|
|
@ -76,7 +64,7 @@ class Connection
|
||||||
|
|
||||||
if (false === $response) {
|
if (false === $response) {
|
||||||
throw new CurlException(
|
throw new CurlException(
|
||||||
'Failed connection to ' . $this->url . ': ' . curl_error($this->curlHandle),
|
'Failed sending to ' . $this->url . ': ' . curl_error($this->curlHandle),
|
||||||
null,
|
null,
|
||||||
curl_errno($this->curlHandle),
|
curl_errno($this->curlHandle),
|
||||||
curl_getinfo($this->curlHandle),
|
curl_getinfo($this->curlHandle),
|
||||||
|
|
|
||||||
0
vendor/nemiah/php-fints/lib/Fhp/CurlException.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/CurlException.php
vendored
Executable file → Normal file
261
vendor/nemiah/php-fints/lib/Fhp/FinTs.php
vendored
Executable file → Normal file
261
vendor/nemiah/php-fints/lib/Fhp/FinTs.php
vendored
Executable file → Normal file
|
|
@ -5,6 +5,10 @@ namespace Fhp;
|
||||||
use Fhp\Model\NoPsd2TanMode;
|
use Fhp\Model\NoPsd2TanMode;
|
||||||
use Fhp\Model\TanMedium;
|
use Fhp\Model\TanMedium;
|
||||||
use Fhp\Model\TanMode;
|
use Fhp\Model\TanMode;
|
||||||
|
use Fhp\Model\VopConfirmationRequest;
|
||||||
|
use Fhp\Model\VopConfirmationRequestImpl;
|
||||||
|
use Fhp\Model\VopPollingInfo;
|
||||||
|
use Fhp\Model\VopVerificationResult;
|
||||||
use Fhp\Options\Credentials;
|
use Fhp\Options\Credentials;
|
||||||
use Fhp\Options\FinTsOptions;
|
use Fhp\Options\FinTsOptions;
|
||||||
use Fhp\Options\SanitizingLogger;
|
use Fhp\Options\SanitizingLogger;
|
||||||
|
|
@ -26,6 +30,8 @@ use Fhp\Segment\TAN\HITAN;
|
||||||
use Fhp\Segment\TAN\HKTAN;
|
use Fhp\Segment\TAN\HKTAN;
|
||||||
use Fhp\Segment\TAN\HKTANFactory;
|
use Fhp\Segment\TAN\HKTANFactory;
|
||||||
use Fhp\Segment\TAN\HKTANv6;
|
use Fhp\Segment\TAN\HKTANv6;
|
||||||
|
use Fhp\Segment\VPP\HKVPPv1;
|
||||||
|
use Fhp\Segment\VPP\VopHelper;
|
||||||
use Fhp\Syntax\InvalidResponseException;
|
use Fhp\Syntax\InvalidResponseException;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Psr\Log\NullLogger;
|
use Psr\Log\NullLogger;
|
||||||
|
|
@ -159,6 +165,7 @@ class FinTs
|
||||||
* carefully (not written to log files, only to a database or other storage system that would normally be used
|
* carefully (not written to log files, only to a database or other storage system that would normally be used
|
||||||
* for user data). The returned string never contains highly sensitive information (not the user's password or
|
* for user data). The returned string never contains highly sensitive information (not the user's password or
|
||||||
* PIN), so it probably does not need to be encrypted. Treat it like a session cookie of the same bank.
|
* PIN), so it probably does not need to be encrypted. Treat it like a session cookie of the same bank.
|
||||||
|
* Note that this is not necessarily valid UTF-8, so you should store it as a BLOB column or raw bytes.
|
||||||
*/
|
*/
|
||||||
public function persist(bool $minimal = false): string
|
public function persist(bool $minimal = false): string
|
||||||
{
|
{
|
||||||
|
|
@ -201,7 +208,7 @@ class FinTs
|
||||||
*
|
*
|
||||||
* @throws \InvalidArgumentException
|
* @throws \InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
public function loadPersistedInstance(string $persistedInstance)
|
public function loadPersistedInstance(string $persistedInstance): void
|
||||||
{
|
{
|
||||||
$unserialized = unserialize($persistedInstance);
|
$unserialized = unserialize($persistedInstance);
|
||||||
if (!is_array($unserialized) || count($unserialized) === 0) {
|
if (!is_array($unserialized) || count($unserialized) === 0) {
|
||||||
|
|
@ -216,7 +223,7 @@ class FinTs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function loadPersistedInstanceVersion2(array $data)
|
private function loadPersistedInstanceVersion2(array $data): void
|
||||||
{
|
{
|
||||||
list( // This should match persist().
|
list( // This should match persist().
|
||||||
$this->bpd,
|
$this->bpd,
|
||||||
|
|
@ -226,7 +233,7 @@ class FinTs
|
||||||
$this->selectedTanMedium,
|
$this->selectedTanMedium,
|
||||||
$this->kundensystemId,
|
$this->kundensystemId,
|
||||||
$this->dialogId,
|
$this->dialogId,
|
||||||
$this->messageNumber
|
$this->messageNumber,
|
||||||
) = $data;
|
) = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -254,7 +261,7 @@ class FinTs
|
||||||
* @param int $responseTimeout The number of seconds to wait before aborting a request to the bank server.
|
* @param int $responseTimeout The number of seconds to wait before aborting a request to the bank server.
|
||||||
* @noinspection PhpUnused
|
* @noinspection PhpUnused
|
||||||
*/
|
*/
|
||||||
public function setTimeouts(int $connectTimeout, int $responseTimeout)
|
public function setTimeouts(int $connectTimeout, int $responseTimeout): void
|
||||||
{
|
{
|
||||||
$this->options->timeoutConnect = $connectTimeout;
|
$this->options->timeoutConnect = $connectTimeout;
|
||||||
$this->options->timeoutResponse = $responseTimeout;
|
$this->options->timeoutResponse = $responseTimeout;
|
||||||
|
|
@ -285,7 +292,7 @@ class FinTs
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes an action. Be sure to {@link login()} first. See the `\Fhp\Action` package for actions that can be
|
* Executes an action. Be sure to {@link login()} first. See the `\Fhp\Action` package for actions that can be
|
||||||
* executed with this function. Note that, after this function returns, the action can be in two possible states:
|
* executed with this function. Note that, after this function returns, the action can be in the following states:
|
||||||
* 1. If {@link BaseAction::needsTan()} returns true, the action isn't completed yet because needs a TAN or other
|
* 1. If {@link BaseAction::needsTan()} returns true, the action isn't completed yet because needs a TAN or other
|
||||||
* kind of two-factor authentication (2FA). In this case, use {@link BaseAction::getTanRequest()} to get more
|
* kind of two-factor authentication (2FA). In this case, use {@link BaseAction::getTanRequest()} to get more
|
||||||
* information about the TAN/2FA that is needed. Your application then needs to interact with the user to obtain
|
* information about the TAN/2FA that is needed. Your application then needs to interact with the user to obtain
|
||||||
|
|
@ -293,9 +300,30 @@ class FinTs
|
||||||
* be verified with {@link checkDecoupledSubmission()}). Both of those functions require passing the same
|
* be verified with {@link checkDecoupledSubmission()}). Both of those functions require passing the same
|
||||||
* {@link BaseAction} argument as an argument, and once they succeed, the action will be in the same completed
|
* {@link BaseAction} argument as an argument, and once they succeed, the action will be in the same completed
|
||||||
* state as if it had been completed right away.
|
* state as if it had been completed right away.
|
||||||
* 2. If {@link BaseAction::needsTan()} returns false, the action was completed right away. Use the respective
|
* 2. If {@link BaseAction::needsPollingWait()} returns true, the action isn't completed yet because the server is
|
||||||
* getters on the action instance to retrieve the result. In case the action fails, the corresponding exception
|
* still running some slow operation. Importantly, the server has not necessarily accepted the action yet, so it
|
||||||
* will be thrown from this function.
|
* is absolutely required that the client keeps polling if they don't want the action to be abandoned.
|
||||||
|
* In this case, use {@link BaseAction::getPollingInfo()} to get more information on how frequently to poll, and
|
||||||
|
* do the polling through {@link pollAction()}.
|
||||||
|
* 3. If {@link BaseAction::needsVopConfirmation()} returns true, the action isn't completed yet because the payee
|
||||||
|
* information couldn't be matched automatically, so an explicit confirmation from the user is required.
|
||||||
|
* In this case, use {@link BaseAction::getVopConfirmationRequest()} to get more information to display to the
|
||||||
|
* user, ask the user to confirm that they want to proceed with the action, and then call {@link confirmVop()}.
|
||||||
|
* 4. If none of the above return true, the action was completed right away.
|
||||||
|
* Use the respective getters on the action instance to retrieve the result. In case the action fails, the
|
||||||
|
* corresponding exception will be thrown from this function.
|
||||||
|
*
|
||||||
|
* Tip: In practice, polling (2.) and confirmation (3.) are needed only for Verification of Payee. So if your
|
||||||
|
* application only ever executes read-only actions like account statement fetching, but never executes any
|
||||||
|
* transfers, instead of handling these cases you could simply assert that {@link BaseAction::needsPollingWait()}
|
||||||
|
* and {@link BaseAction::needsVopConfirmation()} both return false.
|
||||||
|
*
|
||||||
|
* Note that all conditions above that leave the action in an incomplete state require some action from the client
|
||||||
|
* application. These actions then change the state of the action again, but they don't necessarily complete it.
|
||||||
|
* In practice, the typical sequence is: Maybe polling, maybe VOP confirmation, maybe TAN, done. That said, you
|
||||||
|
* should ideally implement your application to deal with any sequence of states. Just execute the action, check
|
||||||
|
* what's state it's in, resolve that state as appropriate, and then check again (using the same code as before). Do
|
||||||
|
* this repeatedly until none of the special conditions above happen anymore, at which point the action is done.
|
||||||
*
|
*
|
||||||
* @param BaseAction $action The action to be executed. Its {@link BaseAction::isDone()} status will be updated when
|
* @param BaseAction $action The action to be executed. Its {@link BaseAction::isDone()} status will be updated when
|
||||||
* this function returns successfully.
|
* this function returns successfully.
|
||||||
|
|
@ -304,27 +332,36 @@ class FinTs
|
||||||
* @throws ServerException When the server responds with a (FinTS-encoded) error message, which includes most things
|
* @throws ServerException When the server responds with a (FinTS-encoded) error message, which includes most things
|
||||||
* that can go wrong with the action itself, like wrong credentials, invalid IBANs, locked accounts, etc.
|
* that can go wrong with the action itself, like wrong credentials, invalid IBANs, locked accounts, etc.
|
||||||
*/
|
*/
|
||||||
public function execute(BaseAction $action)
|
public function execute(BaseAction $action): void
|
||||||
{
|
{
|
||||||
if ($this->dialogId === null && !($action instanceof DialogInitialization)) {
|
if ($this->dialogId === null && !($action instanceof DialogInitialization)) {
|
||||||
throw new \RuntimeException('Need to login (DialogInitialization) before executing other actions');
|
throw new \RuntimeException('Need to login (DialogInitialization) before executing other actions');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add the action's main request segments.
|
||||||
$requestSegments = $action->getNextRequest($this->bpd, $this->upd);
|
$requestSegments = $action->getNextRequest($this->bpd, $this->upd);
|
||||||
|
|
||||||
if (count($requestSegments) === 0) {
|
if (count($requestSegments) === 0) {
|
||||||
return; // No request needed.
|
return; // No request needed.
|
||||||
}
|
}
|
||||||
|
$message = MessageBuilder::create()->add($requestSegments);
|
||||||
|
|
||||||
// Construct the full request message.
|
// Add HKTAN for authentication if necessary.
|
||||||
$message = MessageBuilder::create()->add($requestSegments); // This fills in the segment numbers.
|
|
||||||
if (!($this->getSelectedTanMode() instanceof NoPsd2TanMode)) {
|
if (!($this->getSelectedTanMode() instanceof NoPsd2TanMode)) {
|
||||||
if (($needTanForSegment = $action->getNeedTanForSegment()) !== null) {
|
if (($needTanForSegment = $action->getNeedTanForSegment()) !== null) {
|
||||||
$message->add(HKTANFactory::createProzessvariante2Step1(
|
$message->add(HKTANFactory::createProzessvariante2Step1(
|
||||||
$this->requireTanMode(), $this->selectedTanMedium, $needTanForSegment));
|
$this->requireTanMode(), $this->selectedTanMedium, $needTanForSegment));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$request = $this->buildMessage($message, $this->getSelectedTanMode());
|
|
||||||
|
// Add HKVPP for VOP verification if necessary.
|
||||||
|
$hkvpp = null;
|
||||||
|
if ($this->bpd?->vopRequiredForRequest($requestSegments) !== null) {
|
||||||
|
$hkvpp = VopHelper::createHKVPPForInitialRequest($this->bpd);
|
||||||
|
$message->add($hkvpp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the request message and tell the action about the segment numbers that were assigned.
|
||||||
|
$request = $this->buildMessage($message, $this->getSelectedTanMode()); // This fills in the segment numbers.
|
||||||
$action->setRequestSegmentNumbers(array_map(function ($segment) {
|
$action->setRequestSegmentNumbers(array_map(function ($segment) {
|
||||||
/* @var BaseSegment $segment */
|
/* @var BaseSegment $segment */
|
||||||
return $segment->getSegmentNumber();
|
return $segment->getSegmentNumber();
|
||||||
|
|
@ -332,11 +369,28 @@ class FinTs
|
||||||
|
|
||||||
// Execute the request.
|
// Execute the request.
|
||||||
$response = $this->sendMessage($request);
|
$response = $this->sendMessage($request);
|
||||||
|
$this->processServerResponse($action, $response, $hkvpp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the state of this FinTs instance and of the `$action` based on the server's response.
|
||||||
|
* See {@link execute()} for more documentation on the possible outcomes.
|
||||||
|
* @param BaseAction $action The action for which the request was sent.
|
||||||
|
* @param Message $response The response we just got from the server.
|
||||||
|
* @param HKVPPv1|null $hkvpp The HKVPP segment, if any was present in the request.
|
||||||
|
* @throws CurlException When the connection fails in a layer below the FinTS protocol.
|
||||||
|
* @throws UnexpectedResponseException When the server responds with a valid but unexpected message.
|
||||||
|
* @throws ServerException When the server responds with a (FinTS-encoded) error message, which includes most things
|
||||||
|
* that can go wrong with the action itself, like wrong credentials, invalid IBANs, locked accounts, etc.
|
||||||
|
*/
|
||||||
|
private function processServerResponse(BaseAction $action, Message $response, ?HKVPPv1 $hkvpp = null): void
|
||||||
|
{
|
||||||
$this->readBPD($response);
|
$this->readBPD($response);
|
||||||
|
|
||||||
// Detect if the bank wants a TAN.
|
// Detect if the bank wants a TAN.
|
||||||
/** @var HITAN $hitan */
|
/** @var HITAN $hitan */
|
||||||
$hitan = $response->findSegment(HITAN::class);
|
$hitan = $response->findSegment(HITAN::class);
|
||||||
|
// Note: Instead of DUMMY_REFERENCE, it's officially the 3076 Rueckmeldungscode that tells we don't need a TAN.
|
||||||
if ($hitan !== null && $hitan->getAuftragsreferenz() !== HITAN::DUMMY_REFERENCE) {
|
if ($hitan !== null && $hitan->getAuftragsreferenz() !== HITAN::DUMMY_REFERENCE) {
|
||||||
if ($hitan->tanProzess !== HKTAN::TAN_PROZESS_4) {
|
if ($hitan->tanProzess !== HKTAN::TAN_PROZESS_4) {
|
||||||
throw new UnexpectedResponseException("Unsupported TAN request type $hitan->tanProzess");
|
throw new UnexpectedResponseException("Unsupported TAN request type $hitan->tanProzess");
|
||||||
|
|
@ -350,14 +404,51 @@ class FinTs
|
||||||
$action->setDialogId($response->header->dialogId);
|
$action->setDialogId($response->header->dialogId);
|
||||||
$action->setMessageNumber($this->messageNumber);
|
$action->setMessageNumber($this->messageNumber);
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no TAN is needed, process the response normally, and maybe keep going for more pages.
|
// Detect if the bank needs us to do something for Verification of Payee.
|
||||||
|
if ($hkvpp != null) {
|
||||||
|
if ($pollingInfo = VopHelper::checkPollingRequired($response, $hkvpp->getSegmentNumber())) {
|
||||||
|
$action->setPollingInfo($pollingInfo);
|
||||||
|
if ($action->needsTan()) {
|
||||||
|
throw new UnexpectedResponseException('Unexpected polling and TAN request in the same response.');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ($confirmationRequest = VopHelper::checkVopConfirmationRequired($response, $hkvpp->getSegmentNumber())) {
|
||||||
|
$action->setVopConfirmationRequest($confirmationRequest);
|
||||||
|
if ($action->needsTan()) {
|
||||||
|
if ($confirmationRequest->getVerificationResult() === VopVerificationResult::CompletedFullMatch) {
|
||||||
|
// If someone hits this branch in practice, we can implement it.
|
||||||
|
throw new UnsupportedException('Combined VOP match confirmation and TAN request');
|
||||||
|
} else {
|
||||||
|
throw new UnexpectedResponseException(
|
||||||
|
'Unexpected TAN request on VOP result: ' . $confirmationRequest->getVerificationResult()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($action->needsVopConfirmation() || $action->needsTan()) {
|
||||||
|
return; // The action isn't complete yet.
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no TAN or VOP is needed, process the response normally, and maybe keep going for more pages.
|
||||||
$this->processActionResponse($action, $response->filterByReferenceSegments($action->getRequestSegmentNumbers()));
|
$this->processActionResponse($action, $response->filterByReferenceSegments($action->getRequestSegmentNumbers()));
|
||||||
if ($action instanceof PaginateableAction && $action->hasMorePages()) {
|
if ($action instanceof PaginateableAction && $action->hasMorePages()) {
|
||||||
$this->execute($action);
|
$this->execute($action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check whether the server requested a Kundensystem-ID refresh.
|
||||||
|
if ($response->findRueckmeldung(Rueckmeldungscode::NEUE_KUNDENSYSTEM_ID_HOLEN) !== null) {
|
||||||
|
// TODO Properly implement the refresh here, see https://github.com/nemiah/phpFinTS/issues/458.
|
||||||
|
$this->logger->warning(
|
||||||
|
'The server asked us to refresh the Kundensystem-ID in response to a ' . gettype($action) .
|
||||||
|
' action, but that is not implemented yet. This could result in authentication errors or extraneous ' .
|
||||||
|
' re-authentication prompts from the bank.'
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -365,9 +456,9 @@ class FinTs
|
||||||
* `false`, this function sends the given $tan to the server to complete the action. By using {@link persist()},
|
* `false`, this function sends the given $tan to the server to complete the action. By using {@link persist()},
|
||||||
* this can be done asynchronously, i.e., not in the same PHP process as the original {@link execute()} call.
|
* this can be done asynchronously, i.e., not in the same PHP process as the original {@link execute()} call.
|
||||||
*
|
*
|
||||||
* After this function returns, the `$action` is completed. That is, its result is available through its getters
|
* After this function returns, the `$action` is in any of the same states as after {@link execute()}, see there.
|
||||||
* just as if it had been completed by the original call to {@link execute()} right away. In case the action fails,
|
* In practice, the action is fully completed after completing the decoupled submission.
|
||||||
* the corresponding exception will be thrown from this function.
|
* In case the action fails, the corresponding exception will be thrown from this function.
|
||||||
*
|
*
|
||||||
* @link https://www.hbci-zka.de/dokumente/spezifikation_deutsch/fintsv3/FinTS_3.0_Security_Sicherheitsverfahren_PINTAN_2020-07-10_final_version.pdf
|
* @link https://www.hbci-zka.de/dokumente/spezifikation_deutsch/fintsv3/FinTS_3.0_Security_Sicherheitsverfahren_PINTAN_2020-07-10_final_version.pdf
|
||||||
* Section B.4.2.1.1
|
* Section B.4.2.1.1
|
||||||
|
|
@ -379,7 +470,7 @@ class FinTs
|
||||||
* @throws ServerException When the server responds with a (FinTS-encoded) error message, which includes most things
|
* @throws ServerException When the server responds with a (FinTS-encoded) error message, which includes most things
|
||||||
* that can go wrong with the action itself, like wrong credentials, invalid IBANs, locked accounts, etc.
|
* that can go wrong with the action itself, like wrong credentials, invalid IBANs, locked accounts, etc.
|
||||||
*/
|
*/
|
||||||
public function submitTan(BaseAction $action, string $tan)
|
public function submitTan(BaseAction $action, string $tan): void
|
||||||
{
|
{
|
||||||
// Check the action's state.
|
// Check the action's state.
|
||||||
$tanRequest = $action->getTanRequest();
|
$tanRequest = $action->getTanRequest();
|
||||||
|
|
@ -433,7 +524,9 @@ class FinTs
|
||||||
* For an action where {@link BaseAction::needsTan()} returns `true` and {@link TanMode::isDecoupled()} returns
|
* For an action where {@link BaseAction::needsTan()} returns `true` and {@link TanMode::isDecoupled()} returns
|
||||||
* `true`, this function checks with the server whether the second factor authentication has been completed yet on
|
* `true`, this function checks with the server whether the second factor authentication has been completed yet on
|
||||||
* the secondary device of the user.
|
* the secondary device of the user.
|
||||||
* - If so, this completes the given action and returns `true`.
|
* - If so, this function returns `true` and the `$action` is then in any of the same states as after
|
||||||
|
* {@link execute()} (except {@link BaseAction::needsTan()} won't happen again). See there for documentation.
|
||||||
|
* In practice, the action is fully completed after completing the decoupled submission.
|
||||||
* - In case the action fails, the corresponding exception will be thrown from this function.
|
* - In case the action fails, the corresponding exception will be thrown from this function.
|
||||||
* - If the authentication has not been completed yet, this returns `false` and the action remains in its
|
* - If the authentication has not been completed yet, this returns `false` and the action remains in its
|
||||||
* previous, uncompleted state.
|
* previous, uncompleted state.
|
||||||
|
|
@ -449,9 +542,10 @@ class FinTs
|
||||||
* Section B.4.2.2
|
* Section B.4.2.2
|
||||||
*
|
*
|
||||||
* @param BaseAction $action The action to be completed.
|
* @param BaseAction $action The action to be completed.
|
||||||
* @return bool True if the decoupled authentication is done and the $action was completed. If false, the
|
* @return bool True if the decoupled authentication is done and the $action was completed or entered one of the
|
||||||
* {@link TanRequest} inside the action has been updated, which *may* provide new/more instructions to the user,
|
* other states documented on {@link execute()}.
|
||||||
* though probably it rarely does in practice.
|
* If false, the {@link TanRequest} inside the action has been updated, which *may* provide new/more
|
||||||
|
* instructions to the user, though probably it rarely does in practice.
|
||||||
* @throws CurlException When the connection fails in a layer below the FinTS protocol.
|
* @throws CurlException When the connection fails in a layer below the FinTS protocol.
|
||||||
* @throws UnexpectedResponseException When the server responds with a valid but unexpected message.
|
* @throws UnexpectedResponseException When the server responds with a valid but unexpected message.
|
||||||
* @throws ServerException When the server responds with a (FinTS-encoded) error message, which includes most things
|
* @throws ServerException When the server responds with a (FinTS-encoded) error message, which includes most things
|
||||||
|
|
@ -530,6 +624,99 @@ class FinTs
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For an action where {@link BaseAction::needsPollingWait()} returns `true`, this function polls the server.
|
||||||
|
* By using {@link persist()}, this can be done asynchronously, i.e., not in the same PHP process as the original
|
||||||
|
* {@link execute()} call or the previous {@link pollAction()} call.
|
||||||
|
*
|
||||||
|
* After this function returns, the `$action` is in any of the same states as after {@link execute()}, see there. In
|
||||||
|
* particular, it's possible that the long-running operation on the server has not completed yet and thus
|
||||||
|
* {@link BaseAction::needsPollingWait()} still returns `true`. In practice, actions often require VOP confirmation
|
||||||
|
* or a TAN after the polling is over, though they can also complete right away.
|
||||||
|
* In case the action fails, the corresponding exception will be thrown from this function.
|
||||||
|
*
|
||||||
|
* @param BaseAction $action The action to be completed.
|
||||||
|
* @throws CurlException When the connection fails in a layer below the FinTS protocol.
|
||||||
|
* @throws UnexpectedResponseException When the server responds with a valid but unexpected message.
|
||||||
|
* @throws ServerException When the server responds with a (FinTS-encoded) error message, which includes most things
|
||||||
|
* that can go wrong with the action itself, like wrong credentials, invalid IBANs, locked accounts, etc.
|
||||||
|
* @link FinTS_3.0_Messages_Geschaeftsvorfaelle_VOP_1.01_2025_06_27_FV.pdf
|
||||||
|
* Section C.10.7.1.1 a)
|
||||||
|
*/
|
||||||
|
public function pollAction(BaseAction $action): void
|
||||||
|
{
|
||||||
|
$pollingInfo = $action->getPollingInfo();
|
||||||
|
if ($pollingInfo === null) {
|
||||||
|
throw new \InvalidArgumentException('This action is not awaiting polling for a long-running operation');
|
||||||
|
} elseif ($pollingInfo instanceof VopPollingInfo) {
|
||||||
|
// Only send a new HKVPP.
|
||||||
|
$hkvpp = VopHelper::createHKVPPForPollingRequest($this->bpd, $pollingInfo);
|
||||||
|
$message = MessageBuilder::create()->add($hkvpp);
|
||||||
|
|
||||||
|
// Execute the request and process the response.
|
||||||
|
$response = $this->sendMessage($this->buildMessage($message, $this->getSelectedTanMode()));
|
||||||
|
$action->setPollingInfo(null);
|
||||||
|
$this->processServerResponse($action, $response, $hkvpp);
|
||||||
|
} else {
|
||||||
|
throw new \InvalidArgumentException('Unexpected PollingInfo type: ' . gettype($pollingInfo));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For an action where {@link BaseAction::needsVopConfirmation()} returns `true`, this function re-submits the
|
||||||
|
* action with the additional confirmation from the user that they want to execute the transfer(s) after having
|
||||||
|
* reviewed the information from the {@link VopConfirmationRequest}.
|
||||||
|
* By using {@link persist()}, this can be done asynchronously, i.e., not in the same PHP process as the original
|
||||||
|
* {@link execute()} call.
|
||||||
|
*
|
||||||
|
* After this function returns, the `$action` is in any of the same states as after {@link execute()}, see there. In
|
||||||
|
* practice, actions often require a TAN after VOP is confirmed, though they can also complete right away.
|
||||||
|
* In case the action fails, the corresponding exception will be thrown from this function.
|
||||||
|
*
|
||||||
|
* @param BaseAction $action The action to be completed.
|
||||||
|
* @throws CurlException When the connection fails in a layer below the FinTS protocol.
|
||||||
|
* @throws UnexpectedResponseException When the server responds with a valid but unexpected message.
|
||||||
|
* @throws ServerException When the server responds with a (FinTS-encoded) error message, which includes most things
|
||||||
|
* that can go wrong with the action itself, like wrong credentials, invalid IBANs, locked accounts, etc.
|
||||||
|
* @link FinTS_3.0_Messages_Geschaeftsvorfaelle_VOP_1.01_2025_06_27_FV.pdf
|
||||||
|
* Section C.10.7.1.2 a)
|
||||||
|
*/
|
||||||
|
public function confirmVop(BaseAction $action): void
|
||||||
|
{
|
||||||
|
$vopConfirmationRequest = $action->getVopConfirmationRequest();
|
||||||
|
if (!($vopConfirmationRequest instanceof VopConfirmationRequestImpl)) {
|
||||||
|
throw new \InvalidArgumentException('Unexpected type: ' . gettype($vopConfirmationRequest));
|
||||||
|
}
|
||||||
|
// We need to send the original request again, plus HKVPA as the confirmation.
|
||||||
|
$requestSegments = $action->getNextRequest($this->bpd, $this->upd);
|
||||||
|
if (count($requestSegments) === 0) {
|
||||||
|
throw new \AssertionError('Request unexpectedly became empty upon VOP confirmation');
|
||||||
|
}
|
||||||
|
$message = MessageBuilder::create()
|
||||||
|
->add($requestSegments)
|
||||||
|
->add(VopHelper::createHKVPAForConfirmation($vopConfirmationRequest));
|
||||||
|
|
||||||
|
// Add HKTAN for authentication if necessary.
|
||||||
|
if (!($this->getSelectedTanMode() instanceof NoPsd2TanMode)) {
|
||||||
|
if (($needTanForSegment = $action->getNeedTanForSegment()) !== null) {
|
||||||
|
$message->add(HKTANFactory::createProzessvariante2Step1(
|
||||||
|
$this->requireTanMode(), $this->selectedTanMedium, $needTanForSegment));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the request message and tell the action about the segment numbers that were assigned.
|
||||||
|
$request = $this->buildMessage($message, $this->getSelectedTanMode()); // This fills in the segment numbers.
|
||||||
|
$action->setRequestSegmentNumbers(array_map(function ($segment) {
|
||||||
|
/* @var BaseSegment $segment */
|
||||||
|
return $segment->getSegmentNumber();
|
||||||
|
}, $requestSegments));
|
||||||
|
|
||||||
|
// Execute the request and process the response.
|
||||||
|
$response = $this->sendMessage($this->buildMessage($message, $this->getSelectedTanMode()));
|
||||||
|
$action->setVopConfirmationRequest(null);
|
||||||
|
$this->processServerResponse($action, $response);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes the session/dialog/connection, if open. This is equivalent to logging out. You should call this function
|
* Closes the session/dialog/connection, if open. This is equivalent to logging out. You should call this function
|
||||||
* when you're done with all the actions, but NOT when you're persisting the instance to fulfill the TAN request of
|
* when you're done with all the actions, but NOT when you're persisting the instance to fulfill the TAN request of
|
||||||
|
|
@ -538,7 +725,7 @@ class FinTs
|
||||||
* from cached BPD/UPD upon the next {@link login()}, for instance.
|
* from cached BPD/UPD upon the next {@link login()}, for instance.
|
||||||
* @throws ServerException When closing the dialog fails.
|
* @throws ServerException When closing the dialog fails.
|
||||||
*/
|
*/
|
||||||
public function close()
|
public function close(): void
|
||||||
{
|
{
|
||||||
if ($this->dialogId !== null) {
|
if ($this->dialogId !== null) {
|
||||||
$this->endDialog();
|
$this->endDialog();
|
||||||
|
|
@ -552,7 +739,7 @@ class FinTs
|
||||||
* This can be called by the application using this library when it just restored this FinTs instance from the
|
* This can be called by the application using this library when it just restored this FinTs instance from the
|
||||||
* persisted format after a long time, during which the session/dialog has most likely expired on the server side.
|
* persisted format after a long time, during which the session/dialog has most likely expired on the server side.
|
||||||
*/
|
*/
|
||||||
public function forgetDialog()
|
public function forgetDialog(): void
|
||||||
{
|
{
|
||||||
$this->dialogId = null;
|
$this->dialogId = null;
|
||||||
}
|
}
|
||||||
|
|
@ -571,9 +758,11 @@ class FinTs
|
||||||
public function getTanModes(): array
|
public function getTanModes(): array
|
||||||
{
|
{
|
||||||
$this->ensureTanModesAvailable();
|
$this->ensureTanModesAvailable();
|
||||||
$result = array();
|
$result = [];
|
||||||
foreach ($this->allowedTanModes as $tanModeId) {
|
foreach ($this->allowedTanModes as $tanModeId) {
|
||||||
if (!array_key_exists($tanModeId, $this->bpd->allTanModes)) continue;
|
if (!array_key_exists($tanModeId, $this->bpd->allTanModes)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
$result[$tanModeId] = $this->bpd->allTanModes[$tanModeId];
|
$result[$tanModeId] = $this->bpd->allTanModes[$tanModeId];
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
|
|
@ -624,7 +813,7 @@ class FinTs
|
||||||
* must be the value returned from {@link TanMedium::getName()} for one of the TAN media supported with that TAN
|
* must be the value returned from {@link TanMedium::getName()} for one of the TAN media supported with that TAN
|
||||||
* mode. Use {@link getTanMedia()} to obtain a list of possible TAN media options.
|
* mode. Use {@link getTanMedia()} to obtain a list of possible TAN media options.
|
||||||
*/
|
*/
|
||||||
public function selectTanMode($tanMode, $tanMedium = null)
|
public function selectTanMode($tanMode, $tanMedium = null): void
|
||||||
{
|
{
|
||||||
if (!is_int($tanMode) && !($tanMode instanceof TanMode)) {
|
if (!is_int($tanMode) && !($tanMode instanceof TanMode)) {
|
||||||
throw new \InvalidArgumentException('tanMode must be an int or a TanMode');
|
throw new \InvalidArgumentException('tanMode must be an int or a TanMode');
|
||||||
|
|
@ -664,7 +853,7 @@ class FinTs
|
||||||
* @throws UnexpectedResponseException When the server does not send the BPD or close the dialog properly.
|
* @throws UnexpectedResponseException When the server does not send the BPD or close the dialog properly.
|
||||||
* @throws ServerException When the server resopnds with an error.
|
* @throws ServerException When the server resopnds with an error.
|
||||||
*/
|
*/
|
||||||
private function ensureBpdAvailable()
|
private function ensureBpdAvailable(): void
|
||||||
{
|
{
|
||||||
if ($this->bpd !== null) {
|
if ($this->bpd !== null) {
|
||||||
return; // Nothing to do.
|
return; // Nothing to do.
|
||||||
|
|
@ -711,7 +900,7 @@ class FinTs
|
||||||
* like it should according to the protocol, or when the dialog is not closed properly.
|
* like it should according to the protocol, or when the dialog is not closed properly.
|
||||||
* @throws ServerException When the server responds with an error.
|
* @throws ServerException When the server responds with an error.
|
||||||
*/
|
*/
|
||||||
private function ensureTanModesAvailable()
|
private function ensureTanModesAvailable(): void
|
||||||
{
|
{
|
||||||
if ($this->allowedTanModes === null) {
|
if ($this->allowedTanModes === null) {
|
||||||
$this->ensureBpdAvailable();
|
$this->ensureBpdAvailable();
|
||||||
|
|
@ -730,7 +919,7 @@ class FinTs
|
||||||
* dialog is not closed properly.
|
* dialog is not closed properly.
|
||||||
* @throws ServerException When the server responds with an error.
|
* @throws ServerException When the server responds with an error.
|
||||||
*/
|
*/
|
||||||
private function ensureSynchronized()
|
private function ensureSynchronized(): void
|
||||||
{
|
{
|
||||||
if ($this->kundensystemId === null) {
|
if ($this->kundensystemId === null) {
|
||||||
$this->ensureBpdAvailable();
|
$this->ensureBpdAvailable();
|
||||||
|
|
@ -820,7 +1009,7 @@ class FinTs
|
||||||
/**
|
/**
|
||||||
* Closes the physical connection, if necessary.
|
* Closes the physical connection, if necessary.
|
||||||
*/
|
*/
|
||||||
private function disconnect()
|
private function disconnect(): void
|
||||||
{
|
{
|
||||||
if ($this->connection !== null) {
|
if ($this->connection !== null) {
|
||||||
$this->connection->disconnect();
|
$this->connection->disconnect();
|
||||||
|
|
@ -834,7 +1023,7 @@ class FinTs
|
||||||
* @param Message $fakeResponseMessage A messsage that contains the response segments for this action.
|
* @param Message $fakeResponseMessage A messsage that contains the response segments for this action.
|
||||||
* @throws UnexpectedResponseException When the server responded with a valid but unexpected message.
|
* @throws UnexpectedResponseException When the server responded with a valid but unexpected message.
|
||||||
*/
|
*/
|
||||||
private function processActionResponse(BaseAction $action, Message $fakeResponseMessage)
|
private function processActionResponse(BaseAction $action, Message $fakeResponseMessage): void
|
||||||
{
|
{
|
||||||
$action->processResponse($fakeResponseMessage);
|
$action->processResponse($fakeResponseMessage);
|
||||||
if ($action instanceof DialogInitialization) {
|
if ($action instanceof DialogInitialization) {
|
||||||
|
|
@ -864,7 +1053,7 @@ class FinTs
|
||||||
* properly.
|
* properly.
|
||||||
* @throws ServerException When the server responds with an error.
|
* @throws ServerException When the server responds with an error.
|
||||||
*/
|
*/
|
||||||
private function executeWeakDialogInitialization(?string $hktanRef)
|
private function executeWeakDialogInitialization(?string $hktanRef): void
|
||||||
{
|
{
|
||||||
if ($this->dialogId !== null) {
|
if ($this->dialogId !== null) {
|
||||||
throw new \RuntimeException('Cannot init another dialog.');
|
throw new \RuntimeException('Cannot init another dialog.');
|
||||||
|
|
@ -905,7 +1094,7 @@ class FinTs
|
||||||
* @throws ServerException When the server responds with an error instead of closing the dialog. This means that
|
* @throws ServerException When the server responds with an error instead of closing the dialog. This means that
|
||||||
* the connection is tainted and can probably not be used for another dialog.
|
* the connection is tainted and can probably not be used for another dialog.
|
||||||
*/
|
*/
|
||||||
protected function endDialog(bool $isAnonymous = false)
|
protected function endDialog(bool $isAnonymous = false): void
|
||||||
{
|
{
|
||||||
if ($this->connection === null) {
|
if ($this->connection === null) {
|
||||||
$this->dialogId = null;
|
$this->dialogId = null;
|
||||||
|
|
@ -943,7 +1132,7 @@ class FinTs
|
||||||
* @param MessageBuilder $message The message to be built.
|
* @param MessageBuilder $message The message to be built.
|
||||||
* @param TanMode|null $tanMode Optionally a TAN mode that will be used when sending this message, defaults to 999
|
* @param TanMode|null $tanMode Optionally a TAN mode that will be used when sending this message, defaults to 999
|
||||||
* (single step).
|
* (single step).
|
||||||
* @param string|null Optionally a TAN to sign this message with.
|
* @param string|null $tan Optionally a TAN to sign this message with.
|
||||||
* @return Message The built message.
|
* @return Message The built message.
|
||||||
*/
|
*/
|
||||||
private function buildMessage(MessageBuilder $message, ?TanMode $tanMode = null, ?string $tan = null): Message
|
private function buildMessage(MessageBuilder $message, ?TanMode $tanMode = null, ?string $tan = null): Message
|
||||||
|
|
|
||||||
0
vendor/nemiah/php-fints/lib/Fhp/MT535/MT535.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/MT535/MT535.php
vendored
Executable file → Normal file
1
vendor/nemiah/php-fints/lib/Fhp/MT940/Dialect/PostbankMT940.php
vendored
Executable file → Normal file
1
vendor/nemiah/php-fints/lib/Fhp/MT940/Dialect/PostbankMT940.php
vendored
Executable file → Normal file
|
|
@ -8,7 +8,6 @@ class PostbankMT940 extends MT940
|
||||||
{
|
{
|
||||||
public const DIALECT_ID = 'https://hbci.postbank.de/banking/hbci.do';
|
public const DIALECT_ID = 'https://hbci.postbank.de/banking/hbci.do';
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function extractStructuredDataFromRemittanceLines($descriptionLines, string &$gvc, array &$rawLines, array $transaction): array
|
public function extractStructuredDataFromRemittanceLines($descriptionLines, string &$gvc, array &$rawLines, array $transaction): array
|
||||||
{
|
{
|
||||||
// z.B bei Zinsen o.ä. ist alles leer
|
// z.B bei Zinsen o.ä. ist alles leer
|
||||||
|
|
|
||||||
1
vendor/nemiah/php-fints/lib/Fhp/MT940/Dialect/SpardaMT940.php
vendored
Executable file → Normal file
1
vendor/nemiah/php-fints/lib/Fhp/MT940/Dialect/SpardaMT940.php
vendored
Executable file → Normal file
|
|
@ -8,7 +8,6 @@ class SpardaMT940 extends MT940
|
||||||
{
|
{
|
||||||
public const DIALECT_ID = 'https://fints.bankingonline.de/fints/FinTs30PinTanHttpGate';
|
public const DIALECT_ID = 'https://fints.bankingonline.de/fints/FinTs30PinTanHttpGate';
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function extractStructuredDataFromRemittanceLines($descriptionLines, string &$gvc, array &$rawLines, array $transaction): array
|
public function extractStructuredDataFromRemittanceLines($descriptionLines, string &$gvc, array &$rawLines, array $transaction): array
|
||||||
{
|
{
|
||||||
$otherInfo = [];
|
$otherInfo = [];
|
||||||
|
|
|
||||||
2
vendor/nemiah/php-fints/lib/Fhp/MT940/MT940.php
vendored
Executable file → Normal file
2
vendor/nemiah/php-fints/lib/Fhp/MT940/MT940.php
vendored
Executable file → Normal file
|
|
@ -142,7 +142,7 @@ class MT940
|
||||||
$soaDate = $this->getDate(substr($day[$i], 1, 6));
|
$soaDate = $this->getDate(substr($day[$i], 1, 6));
|
||||||
|
|
||||||
if (isset($result[$soaDate])) {
|
if (isset($result[$soaDate])) {
|
||||||
#$result[$soaDate] = ['end_balance' => []];
|
// $result[$soaDate] = ['end_balance' => []];
|
||||||
|
|
||||||
$amount = str_replace(',', '.', substr($day[$i], 10, -1));
|
$amount = str_replace(',', '.', substr($day[$i], 10, -1));
|
||||||
$cdMark = substr($day[$i], 0, 1);
|
$cdMark = substr($day[$i], 0, 1);
|
||||||
|
|
|
||||||
0
vendor/nemiah/php-fints/lib/Fhp/MT940/MT940Exception.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/MT940/MT940Exception.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/Account.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/Account.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/DataElement.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/DataElement.php
vendored
Executable file → Normal file
9
vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/StartCode.php
vendored
Executable file → Normal file
9
vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/StartCode.php
vendored
Executable file → Normal file
|
|
@ -68,17 +68,11 @@ class StartCode extends DataElement
|
||||||
$this->headerHighBit = '1';
|
$this->headerHighBit = '1';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public function toHex(): string
|
public function toHex(): string
|
||||||
{
|
{
|
||||||
return $this->getHeaderHex() . implode('', $this->controlBytes) . $this->getDataHex();
|
return $this->getHeaderHex() . implode('', $this->controlBytes) . $this->getDataHex();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public function getLuhnChecksum(): int
|
public function getLuhnChecksum(): int
|
||||||
{
|
{
|
||||||
$luhn = 0;
|
$luhn = 0;
|
||||||
|
|
@ -89,9 +83,6 @@ class StartCode extends DataElement
|
||||||
return $luhn;
|
return $luhn;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public function __debugInfo(): ?array
|
public function __debugInfo(): ?array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|
|
||||||
0
vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/SvgRenderer.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/SvgRenderer.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/TanRequestChallengeFlicker.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/TanRequestChallengeFlicker.php
vendored
Executable file → Normal file
17
vendor/nemiah/php-fints/lib/Fhp/Model/NoPsd2TanMode.php
vendored
Executable file → Normal file
17
vendor/nemiah/php-fints/lib/Fhp/Model/NoPsd2TanMode.php
vendored
Executable file → Normal file
|
|
@ -16,13 +16,11 @@ final class NoPsd2TanMode implements TanMode
|
||||||
{
|
{
|
||||||
public const ID = -1;
|
public const ID = -1;
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function getId(): int
|
public function getId(): int
|
||||||
{
|
{
|
||||||
return self::ID;
|
return self::ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function getName(): string
|
public function getName(): string
|
||||||
{
|
{
|
||||||
return 'No PSD2/TANs supported';
|
return 'No PSD2/TANs supported';
|
||||||
|
|
@ -33,91 +31,76 @@ final class NoPsd2TanMode implements TanMode
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function isDecoupled(): bool
|
public function isDecoupled(): bool
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function getChallengeLabel(): string
|
public function getChallengeLabel(): string
|
||||||
{
|
{
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function getMaxChallengeLength(): int
|
public function getMaxChallengeLength(): int
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function getMaxTanLength(): int
|
public function getMaxTanLength(): int
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function getTanFormat(): int
|
public function getTanFormat(): int
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function needsTanMedium(): bool
|
public function needsTanMedium(): bool
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function getSmsAbbuchungskontoErforderlich(): bool
|
public function getSmsAbbuchungskontoErforderlich(): bool
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function getAuftraggeberkontoErforderlich(): bool
|
public function getAuftraggeberkontoErforderlich(): bool
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function getChallengeKlasseErforderlich(): bool
|
public function getChallengeKlasseErforderlich(): bool
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function getAntwortHhdUcErforderlich(): bool
|
public function getAntwortHhdUcErforderlich(): bool
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function getMaxDecoupledChecks(): int
|
public function getMaxDecoupledChecks(): int
|
||||||
{
|
{
|
||||||
throw new \RuntimeException('Only allowed for decoupled TAN modes');
|
throw new \RuntimeException('Only allowed for decoupled TAN modes');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function getFirstDecoupledCheckDelaySeconds(): int
|
public function getFirstDecoupledCheckDelaySeconds(): int
|
||||||
{
|
{
|
||||||
throw new \RuntimeException('Only allowed for decoupled TAN modes');
|
throw new \RuntimeException('Only allowed for decoupled TAN modes');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function getPeriodicDecoupledCheckDelaySeconds(): int
|
public function getPeriodicDecoupledCheckDelaySeconds(): int
|
||||||
{
|
{
|
||||||
throw new \RuntimeException('Only allowed for decoupled TAN modes');
|
throw new \RuntimeException('Only allowed for decoupled TAN modes');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function allowsManualConfirmation(): bool
|
public function allowsManualConfirmation(): bool
|
||||||
{
|
{
|
||||||
throw new \RuntimeException('Only allowed for decoupled TAN modes');
|
throw new \RuntimeException('Only allowed for decoupled TAN modes');
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function allowsAutomatedPolling(): bool
|
public function allowsAutomatedPolling(): bool
|
||||||
{
|
{
|
||||||
throw new \RuntimeException('Only allowed for decoupled TAN modes');
|
throw new \RuntimeException('Only allowed for decoupled TAN modes');
|
||||||
|
|
|
||||||
23
vendor/nemiah/php-fints/lib/Fhp/Model/PollingInfo.php
vendored
Normal file
23
vendor/nemiah/php-fints/lib/Fhp/Model/PollingInfo.php
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Fhp\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides information that the client application should use to poll for the completion of a long-running operation on
|
||||||
|
* the server.
|
||||||
|
*/
|
||||||
|
interface PollingInfo
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @return ?int The number of seconds (measured from the time when the client received this {@link PollingInfo})
|
||||||
|
* after which the client is allowed to contact the server again regarding this action. If this returns null,
|
||||||
|
* there is no restriction.
|
||||||
|
*/
|
||||||
|
public function getNextAttemptInSeconds(): ?int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return ?string An HTML-formatted text (either in the bank's language or in English!) that the application may
|
||||||
|
* display to the user to inform them (on a very high level) about why they have to wait.
|
||||||
|
*/
|
||||||
|
public function getInformationForUser(): ?string;
|
||||||
|
}
|
||||||
0
vendor/nemiah/php-fints/lib/Fhp/Model/SEPAAccount.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/SEPAAccount.php
vendored
Executable file → Normal file
30
vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfAccount/Statement.php
vendored
Executable file → Normal file
30
vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfAccount/Statement.php
vendored
Executable file → Normal file
|
|
@ -7,30 +7,12 @@ class Statement
|
||||||
public const CD_CREDIT = 'credit';
|
public const CD_CREDIT = 'credit';
|
||||||
public const CD_DEBIT = 'debit';
|
public const CD_DEBIT = 'debit';
|
||||||
|
|
||||||
/**
|
/** @var Transaction[] */
|
||||||
* @var array of Transaction
|
protected array $transactions = [];
|
||||||
*/
|
protected float $startBalance = 0.0;
|
||||||
protected $transactions = [];
|
protected ?float $endBalance = null;
|
||||||
|
protected ?string $creditDebit = null;
|
||||||
/**
|
protected ?\DateTime $date = null;
|
||||||
* @var float
|
|
||||||
*/
|
|
||||||
protected $startBalance = 0.0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var float|null
|
|
||||||
*/
|
|
||||||
protected $endBalance = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string|null
|
|
||||||
*/
|
|
||||||
protected $creditDebit = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var \DateTime|null
|
|
||||||
*/
|
|
||||||
protected $date;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get transactions
|
* Get transactions
|
||||||
|
|
|
||||||
8
vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfAccount/StatementOfAccount.php
vendored
Executable file → Normal file
8
vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfAccount/StatementOfAccount.php
vendored
Executable file → Normal file
|
|
@ -6,10 +6,8 @@ use Fhp\MT940\MT940;
|
||||||
|
|
||||||
class StatementOfAccount
|
class StatementOfAccount
|
||||||
{
|
{
|
||||||
/**
|
/** @var Statement[] */
|
||||||
* @var Statement[]
|
protected array $statements = [];
|
||||||
*/
|
|
||||||
protected $statements = [];
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get statements
|
* Get statements
|
||||||
|
|
@ -77,7 +75,7 @@ class StatementOfAccount
|
||||||
$statementModel->setStartBalance((float) $statement['start_balance']['amount']);
|
$statementModel->setStartBalance((float) $statement['start_balance']['amount']);
|
||||||
}
|
}
|
||||||
if (isset($statement['end_balance'])) {
|
if (isset($statement['end_balance'])) {
|
||||||
$statementModel->setEndBalance((float) $statement['end_balance']['amount'] * ($statement["end_balance"]['credit_debit'] == MT940::CD_CREDIT ? 1 : -1));
|
$statementModel->setEndBalance((float) $statement['end_balance']['amount'] * ($statement['end_balance']['credit_debit'] == MT940::CD_CREDIT ? 1 : -1));
|
||||||
}
|
}
|
||||||
if (isset($statement['start_balance']['credit_debit'])) {
|
if (isset($statement['start_balance']['credit_debit'])) {
|
||||||
$statementModel->setCreditDebit($statement['start_balance']['credit_debit']);
|
$statementModel->setCreditDebit($statement['start_balance']['credit_debit']);
|
||||||
|
|
|
||||||
152
vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfAccount/Transaction.php
vendored
Executable file → Normal file
152
vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfAccount/Transaction.php
vendored
Executable file → Normal file
|
|
@ -8,86 +8,28 @@ class Transaction
|
||||||
public const CD_CREDIT = 'credit';
|
public const CD_CREDIT = 'credit';
|
||||||
public const CD_DEBIT = 'debit';
|
public const CD_DEBIT = 'debit';
|
||||||
|
|
||||||
/**
|
protected ?\DateTime $bookingDate = null;
|
||||||
* @var \DateTime|null
|
protected ?\DateTime $valutaDate = null;
|
||||||
*/
|
protected float $amount;
|
||||||
protected $bookingDate;
|
protected string $creditDebit;
|
||||||
|
protected bool $isStorno;
|
||||||
/**
|
protected string $bookingCode;
|
||||||
* @var \DateTime|null
|
protected string $bookingText;
|
||||||
*/
|
protected string $description1;
|
||||||
protected $valutaDate;
|
protected string $description2;
|
||||||
|
|
||||||
/**
|
|
||||||
* @var float
|
|
||||||
*/
|
|
||||||
protected $amount;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $creditDebit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
protected $isStorno;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $bookingCode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $bookingText;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $description2;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Array keys are identifiers like "SVWZ" for the main description.
|
* Array keys are identifiers like "SVWZ" for the main description.
|
||||||
* @var string[]
|
* @var string[]
|
||||||
*/
|
*/
|
||||||
protected $structuredDescription;
|
protected array $structuredDescription;
|
||||||
|
|
||||||
/**
|
protected string $bankCode;
|
||||||
* @var string
|
protected string $accountNumber;
|
||||||
*/
|
protected string $name;
|
||||||
protected $bankCode;
|
protected bool $booked;
|
||||||
|
protected int $pn;
|
||||||
/**
|
protected int $textKeyAddition;
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $accountNumber;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
protected $booked;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
protected $pn;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
protected $textKeyAddition;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get booking date.
|
* Get booking date.
|
||||||
|
|
@ -121,10 +63,9 @@ class Transaction
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setBookingDate(?\DateTime $date = null)
|
public function setBookingDate(?\DateTime $date = null): static
|
||||||
{
|
{
|
||||||
$this->bookingDate = $date;
|
$this->bookingDate = $date;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,10 +74,9 @@ class Transaction
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setValutaDate(?\DateTime $date = null)
|
public function setValutaDate(?\DateTime $date = null): static
|
||||||
{
|
{
|
||||||
$this->valutaDate = $date;
|
$this->valutaDate = $date;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -153,10 +93,9 @@ class Transaction
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setBooked(bool $booked)
|
public function setBooked(bool $booked): static
|
||||||
{
|
{
|
||||||
$this->booked = $booked;
|
$this->booked = $booked;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,10 +104,9 @@ class Transaction
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setAmount(float $amount)
|
public function setAmount(float $amount): static
|
||||||
{
|
{
|
||||||
$this->amount = (float) $amount;
|
$this->amount = $amount;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -185,10 +123,9 @@ class Transaction
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setCreditDebit(string $creditDebit)
|
public function setCreditDebit(string $creditDebit): static
|
||||||
{
|
{
|
||||||
$this->creditDebit = $creditDebit;
|
$this->creditDebit = $creditDebit;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,10 +142,9 @@ class Transaction
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setIsStorno(bool $isStorno)
|
public function setIsStorno(bool $isStorno): static
|
||||||
{
|
{
|
||||||
$this->isStorno = $isStorno;
|
$this->isStorno = $isStorno;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,10 +161,9 @@ class Transaction
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setBookingCode(string $bookingCode)
|
public function setBookingCode(string $bookingCode): static
|
||||||
{
|
{
|
||||||
$this->bookingCode = (string) $bookingCode;
|
$this->bookingCode = $bookingCode;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -245,10 +180,9 @@ class Transaction
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setBookingText(string $bookingText)
|
public function setBookingText(string $bookingText): static
|
||||||
{
|
{
|
||||||
$this->bookingText = (string) $bookingText;
|
$this->bookingText = $bookingText;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,10 +199,9 @@ class Transaction
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setDescription1(string $description1)
|
public function setDescription1(string $description1): static
|
||||||
{
|
{
|
||||||
$this->description1 = (string) $description1;
|
$this->description1 = $description1;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -285,10 +218,9 @@ class Transaction
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setDescription2(string $description2)
|
public function setDescription2(string $description2): static
|
||||||
{
|
{
|
||||||
$this->description2 = (string) $description2;
|
$this->description2 = $description2;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,10 +238,9 @@ class Transaction
|
||||||
* Set structuredDescription
|
* Set structuredDescription
|
||||||
*
|
*
|
||||||
* @param string[] $structuredDescription
|
* @param string[] $structuredDescription
|
||||||
*
|
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setStructuredDescription(array $structuredDescription)
|
public function setStructuredDescription(array $structuredDescription): static
|
||||||
{
|
{
|
||||||
$this->structuredDescription = $structuredDescription;
|
$this->structuredDescription = $structuredDescription;
|
||||||
|
|
||||||
|
|
@ -353,10 +284,9 @@ class Transaction
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setBankCode(string $bankCode)
|
public function setBankCode(string $bankCode): static
|
||||||
{
|
{
|
||||||
$this->bankCode = (string) $bankCode;
|
$this->bankCode = $bankCode;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -373,10 +303,9 @@ class Transaction
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setAccountNumber(string $accountNumber)
|
public function setAccountNumber(string $accountNumber): static
|
||||||
{
|
{
|
||||||
$this->accountNumber = (string) $accountNumber;
|
$this->accountNumber = $accountNumber;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -401,10 +330,9 @@ class Transaction
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setName(string $name)
|
public function setName(string $name): static
|
||||||
{
|
{
|
||||||
$this->name = (string) $name;
|
$this->name = $name;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,7 +350,7 @@ class Transaction
|
||||||
* @param int|mixed $nr Will be parsed to an int.
|
* @param int|mixed $nr Will be parsed to an int.
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setPN($nr)
|
public function setPN($nr): static
|
||||||
{
|
{
|
||||||
$this->pn = intval($nr);
|
$this->pn = intval($nr);
|
||||||
return $this;
|
return $this;
|
||||||
|
|
@ -442,7 +370,7 @@ class Transaction
|
||||||
* @param int|mixed $textKeyAddition Will be parsed to an int.
|
* @param int|mixed $textKeyAddition Will be parsed to an int.
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setTextKeyAddition($textKeyAddition)
|
public function setTextKeyAddition($textKeyAddition): static
|
||||||
{
|
{
|
||||||
$this->textKeyAddition = intval($textKeyAddition);
|
$this->textKeyAddition = intval($textKeyAddition);
|
||||||
return $this;
|
return $this;
|
||||||
|
|
|
||||||
0
vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfHoldings/Holding.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfHoldings/Holding.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfHoldings/StatementOfHoldings.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfHoldings/StatementOfHoldings.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/TanMedium.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/TanMedium.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/TanMode.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/TanMode.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/TanRequest.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/TanRequest.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/TanRequestChallengeImage.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Model/TanRequestChallengeImage.php
vendored
Executable file → Normal file
25
vendor/nemiah/php-fints/lib/Fhp/Model/VopConfirmationRequest.php
vendored
Normal file
25
vendor/nemiah/php-fints/lib/Fhp/Model/VopConfirmationRequest.php
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Fhp\Model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides information (about the payee) that the client application should present to the user and then ask for their
|
||||||
|
* confirmation that the transfer (to this payee) should be executed.
|
||||||
|
*/
|
||||||
|
interface VopConfirmationRequest
|
||||||
|
{
|
||||||
|
/** An HTML-formatted text that (if present) the application must show to the user when asking for confirmation. */
|
||||||
|
public function getInformationForUser(): ?string;
|
||||||
|
|
||||||
|
/** If this returns a non-null value, the confirmation request is only valid up to that time. */
|
||||||
|
public function getExpiration(): ?\DateTime;
|
||||||
|
|
||||||
|
/** The main outcome of the payee verification. See {@link VopVerificationResult} for possible values. */
|
||||||
|
public function getVerificationResult(): ?string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If {@link getVerificationResult()} returns {@link VopVerificationResult::NotApplicable}, then this function MAY
|
||||||
|
* return an additional explanation (in the user's language or in English), but it may also return null.
|
||||||
|
*/
|
||||||
|
public function getVerificationNotApplicableReason(): ?string;
|
||||||
|
}
|
||||||
54
vendor/nemiah/php-fints/lib/Fhp/Model/VopConfirmationRequestImpl.php
vendored
Normal file
54
vendor/nemiah/php-fints/lib/Fhp/Model/VopConfirmationRequestImpl.php
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Fhp\Model;
|
||||||
|
|
||||||
|
use Fhp\Syntax\Bin;
|
||||||
|
|
||||||
|
/** Application code should not interact directly with this type, see {@link VopConfirmationRequest instead}. */
|
||||||
|
class VopConfirmationRequestImpl implements VopConfirmationRequest
|
||||||
|
{
|
||||||
|
private Bin $vopId;
|
||||||
|
private ?\DateTime $expiration;
|
||||||
|
private ?string $informationForUser;
|
||||||
|
private ?string $verificationResult;
|
||||||
|
private ?string $verificationNotApplicableReason;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
Bin $vopId,
|
||||||
|
?\DateTime $expiration,
|
||||||
|
?string $informationForUser,
|
||||||
|
?string $verificationResult,
|
||||||
|
?string $verificationNotApplicableReason,
|
||||||
|
) {
|
||||||
|
$this->vopId = $vopId;
|
||||||
|
$this->expiration = $expiration;
|
||||||
|
$this->informationForUser = $informationForUser;
|
||||||
|
$this->verificationResult = $verificationResult;
|
||||||
|
$this->verificationNotApplicableReason = $verificationNotApplicableReason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVopId(): Bin
|
||||||
|
{
|
||||||
|
return $this->vopId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExpiration(): ?\DateTime
|
||||||
|
{
|
||||||
|
return $this->expiration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInformationForUser(): ?string
|
||||||
|
{
|
||||||
|
return $this->informationForUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVerificationResult(): ?string
|
||||||
|
{
|
||||||
|
return $this->verificationResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVerificationNotApplicableReason(): ?string
|
||||||
|
{
|
||||||
|
return $this->verificationNotApplicableReason;
|
||||||
|
}
|
||||||
|
}
|
||||||
50
vendor/nemiah/php-fints/lib/Fhp/Model/VopPollingInfo.php
vendored
Normal file
50
vendor/nemiah/php-fints/lib/Fhp/Model/VopPollingInfo.php
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Fhp\Model;
|
||||||
|
|
||||||
|
use Fhp\Syntax\Bin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Application code should not interact directly with this type, see {@link PollingInfo instead}.
|
||||||
|
*
|
||||||
|
* When we send a request to the bank that requires a Verification of Payee, this means that the bank server has to
|
||||||
|
* contact another bank's server and compare payee names. Especially for larger requests (e.g. bulk transfers), this can
|
||||||
|
* take some time. During this time, the server asks the client to poll regularly in order to find out when the process
|
||||||
|
* is done. This class contains the state that the client needs to do this polling.
|
||||||
|
*/
|
||||||
|
class VopPollingInfo implements PollingInfo
|
||||||
|
{
|
||||||
|
// Both of these are effectively opaque tokens that only the server understands. Our job is to relay them back to
|
||||||
|
// the server when polling. And for some reason there's two of them.
|
||||||
|
private string $aufsetzpunkt;
|
||||||
|
private ?Bin $pollingId;
|
||||||
|
|
||||||
|
private ?int $nextAttemptInSeconds = null;
|
||||||
|
|
||||||
|
public function __construct(string $aufsetzpunkt, ?Bin $pollingId, ?int $nextAttemptInSeconds)
|
||||||
|
{
|
||||||
|
$this->aufsetzpunkt = $aufsetzpunkt;
|
||||||
|
$this->pollingId = $pollingId;
|
||||||
|
$this->nextAttemptInSeconds = $nextAttemptInSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAufsetzpunkt(): string
|
||||||
|
{
|
||||||
|
return $this->aufsetzpunkt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPollingId(): ?Bin
|
||||||
|
{
|
||||||
|
return $this->pollingId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNextAttemptInSeconds(): ?int
|
||||||
|
{
|
||||||
|
return $this->nextAttemptInSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInformationForUser(): string
|
||||||
|
{
|
||||||
|
return 'The bank is verifying payee information...';
|
||||||
|
}
|
||||||
|
}
|
||||||
51
vendor/nemiah/php-fints/lib/Fhp/Model/VopVerificationResult.php
vendored
Normal file
51
vendor/nemiah/php-fints/lib/Fhp/Model/VopVerificationResult.php
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Fhp\Model;
|
||||||
|
|
||||||
|
use Fhp\Protocol\UnexpectedResponseException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible outcomes of the Verification of Payee check that the bank did on a transfer we want to execute.
|
||||||
|
* TODO Once we have PHP8.1, turn this into an enum. That's why we use UpperCamelCase below (Symfony style for enums).
|
||||||
|
* @see FinTS_3.0_Messages_Geschaeftsvorfaelle_VOP_1.01_2025_06_27_FV.pdf (chapter D under "VOP-Prüfergebnis")
|
||||||
|
* @see https://febelfin.be/media/pages/publicaties/2023/febelfin-standaarden-voor-online-bankieren/971728b297-1746523070/febelfin-standard-payment-status-report-xml-2025-v1.0-en_final.pdf
|
||||||
|
*/
|
||||||
|
class VopVerificationResult
|
||||||
|
{
|
||||||
|
/** The verification completed and successfully matched the payee information. */
|
||||||
|
public const CompletedFullMatch = 'CompletedFullMatch';
|
||||||
|
/** The verification completed and only partially matched the payee information. */
|
||||||
|
public const CompletedCloseMatch = 'CompletedCloseMatch';
|
||||||
|
/** The verification completed but could not match the payee information. */
|
||||||
|
public const CompletedNoMatch = 'CompletedNoMatch';
|
||||||
|
/** The verification completed but not all included transfers were successfully matched. */
|
||||||
|
public const CompletedPartialMatch = 'CompletedPartialMatch';
|
||||||
|
/**
|
||||||
|
* The verification was attempted but could not be completed. More information MAY be available from
|
||||||
|
* {@link VopConfirmationRequest::getVerificationNotApplicableReason()}.
|
||||||
|
*/
|
||||||
|
public const NotApplicable = 'NotApplicable';
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
// Disallow instantiation, because we'll turn this into an enum.
|
||||||
|
throw new \AssertionError('There should be no instances of VopVerificationResult');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ?string $codeFromBank The verification status code received from the bank.
|
||||||
|
* @return ?string One of the constants defined above, or null if the code could not be recognized.
|
||||||
|
*/
|
||||||
|
public static function parse(?string $codeFromBank): ?string
|
||||||
|
{
|
||||||
|
return match ($codeFromBank) {
|
||||||
|
null => null,
|
||||||
|
'RCVC' => self::CompletedFullMatch,
|
||||||
|
'RVMC' => self::CompletedCloseMatch,
|
||||||
|
'RVNM' => self::CompletedNoMatch,
|
||||||
|
'RVCM' => self::CompletedPartialMatch,
|
||||||
|
'RVNA' => self::NotApplicable,
|
||||||
|
default => throw new UnexpectedResponseException("Unexpected VOP result code: $codeFromBank"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
0
vendor/nemiah/php-fints/lib/Fhp/Options/Credentials.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Options/Credentials.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Options/FinTsOptions.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Options/FinTsOptions.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Options/SanitizingLogger.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Options/SanitizingLogger.php
vendored
Executable file → Normal file
16
vendor/nemiah/php-fints/lib/Fhp/PaginateableAction.php
vendored
Executable file → Normal file
16
vendor/nemiah/php-fints/lib/Fhp/PaginateableAction.php
vendored
Executable file → Normal file
|
|
@ -6,7 +6,6 @@ use Fhp\Protocol\BPD;
|
||||||
use Fhp\Protocol\Message;
|
use Fhp\Protocol\Message;
|
||||||
use Fhp\Protocol\UnexpectedResponseException;
|
use Fhp\Protocol\UnexpectedResponseException;
|
||||||
use Fhp\Protocol\UPD;
|
use Fhp\Protocol\UPD;
|
||||||
use Fhp\Segment\BaseSegment;
|
|
||||||
use Fhp\Segment\HIRMS\Rueckmeldungscode;
|
use Fhp\Segment\HIRMS\Rueckmeldungscode;
|
||||||
use Fhp\Segment\Paginateable;
|
use Fhp\Segment\Paginateable;
|
||||||
|
|
||||||
|
|
@ -19,23 +18,20 @@ use Fhp\Segment\Paginateable;
|
||||||
abstract class PaginateableAction extends BaseAction
|
abstract class PaginateableAction extends BaseAction
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var BaseSegment[] Stores the request created by BaseAction::getNextRequest to be reused in case the bank wants
|
* Stores the request created by BaseAction::getNextRequest to be reused in case the bank wants
|
||||||
* to split the result over multiple pages e.g. request/response pairs. This avoids the need for {@link BPD} to be
|
* to split the result over multiple pages e.g. request/response pairs. This avoids the need for {@link BPD} to be
|
||||||
* available for paginated requests.
|
* available for paginated requests.
|
||||||
*/
|
*/
|
||||||
protected $requestSegments;
|
protected ?array $requestSegments = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If set, the last response from the server regarding this action indicated that there are more results to be
|
* If set, the last response from the server regarding this action indicated that there are more results to be
|
||||||
* fetched using this pagination token. This is called "Aufsetzpunkt" in the specification.
|
* fetched using this pagination token. This is called "Aufsetzpunkt" in the specification.
|
||||||
* @var string|null
|
|
||||||
*/
|
*/
|
||||||
protected $paginationToken;
|
protected ?string $paginationToken = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Beginning from PHP7.4 __unserialize is used for new generated strings, then this method is only used for previously generated strings - remove after May 2023
|
* @deprecated Beginning from PHP7.4 __unserialize is used for new generated strings, then this method is only used for previously generated strings - remove after May 2023
|
||||||
*
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
*/
|
||||||
public function serialize(): string
|
public function serialize(): string
|
||||||
{
|
{
|
||||||
|
|
@ -53,8 +49,6 @@ abstract class PaginateableAction extends BaseAction
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Beginning from PHP7.4 __unserialize is used for new generated strings, then this method is only used for previously generated strings - remove after May 2023
|
* @deprecated Beginning from PHP7.4 __unserialize is used for new generated strings, then this method is only used for previously generated strings - remove after May 2023
|
||||||
*
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
*/
|
||||||
public function unserialize($serialized)
|
public function unserialize($serialized)
|
||||||
{
|
{
|
||||||
|
|
@ -82,10 +76,9 @@ abstract class PaginateableAction extends BaseAction
|
||||||
return !$this->isDone() && $this->paginationToken !== null;
|
return !$this->isDone() && $this->paginationToken !== null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function processResponse(Message $response)
|
public function processResponse(Message $response)
|
||||||
{
|
{
|
||||||
if (($pagination = $response->findRueckmeldung(Rueckmeldungscode::PAGINATION)) !== null) {
|
if (($pagination = $response->findRueckmeldung(Rueckmeldungscode::AUFSETZPUNKT)) !== null) {
|
||||||
if (count($pagination->rueckmeldungsparameter) !== 1) {
|
if (count($pagination->rueckmeldungsparameter) !== 1) {
|
||||||
throw new UnexpectedResponseException("Unexpected pagination request: $pagination");
|
throw new UnexpectedResponseException("Unexpected pagination request: $pagination");
|
||||||
}
|
}
|
||||||
|
|
@ -97,7 +90,6 @@ abstract class PaginateableAction extends BaseAction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function getNextRequest(?BPD $bpd, ?UPD $upd)
|
public function getNextRequest(?BPD $bpd, ?UPD $upd)
|
||||||
{
|
{
|
||||||
if ($this->requestSegments === null) {
|
if ($this->requestSegments === null) {
|
||||||
|
|
|
||||||
0
vendor/nemiah/php-fints/lib/Fhp/Protocol/ActionIncompleteException.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Protocol/ActionIncompleteException.php
vendored
Executable file → Normal file
26
vendor/nemiah/php-fints/lib/Fhp/Protocol/ActionPendingException.php
vendored
Normal file
26
vendor/nemiah/php-fints/lib/Fhp/Protocol/ActionPendingException.php
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
/** @noinspection PhpUnused */
|
||||||
|
|
||||||
|
namespace Fhp\Protocol;
|
||||||
|
|
||||||
|
use Fhp\Model\PollingInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when an action result is read, but the action is still pending a long-running operation on the server and
|
||||||
|
* requires polling to find out when it's completed.
|
||||||
|
*/
|
||||||
|
class ActionPendingException extends \RuntimeException
|
||||||
|
{
|
||||||
|
private PollingInfo $pollingInfo;
|
||||||
|
|
||||||
|
public function __construct(PollingInfo $pollingInfo)
|
||||||
|
{
|
||||||
|
parent::__construct('This action needs polling to await finishing a server-side operation.');
|
||||||
|
$this->pollingInfo = $pollingInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPollingInfo(): PollingInfo
|
||||||
|
{
|
||||||
|
return $this->pollingInfo;
|
||||||
|
}
|
||||||
|
}
|
||||||
23
vendor/nemiah/php-fints/lib/Fhp/Protocol/BPD.php
vendored
Executable file → Normal file
23
vendor/nemiah/php-fints/lib/Fhp/Protocol/BPD.php
vendored
Executable file → Normal file
|
|
@ -10,6 +10,7 @@ use Fhp\Segment\HIBPA\HIBPAv3;
|
||||||
use Fhp\Segment\HIPINS\HIPINSv1;
|
use Fhp\Segment\HIPINS\HIPINSv1;
|
||||||
use Fhp\Segment\SegmentInterface;
|
use Fhp\Segment\SegmentInterface;
|
||||||
use Fhp\Segment\TAN\HITANS;
|
use Fhp\Segment\TAN\HITANS;
|
||||||
|
use Fhp\Segment\VPP\HIVPPSv1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Segmentfolge: Bankparameterdaten (Version 3)
|
* Segmentfolge: Bankparameterdaten (Version 3)
|
||||||
|
|
@ -152,6 +153,28 @@ class BPD
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param SegmentInterface[] $requestSegments The segments that shall be sent to the bank.
|
||||||
|
* @return string|null Identifier of the (first) segment that requires Verification of Payee according to HIPINS, or
|
||||||
|
* null if none of the segments require verification.
|
||||||
|
*/
|
||||||
|
public function vopRequiredForRequest(array $requestSegments): ?string
|
||||||
|
{
|
||||||
|
/** @var HIVPPSv1 $hivpps */
|
||||||
|
$hivpps = $this->getLatestSupportedParameters('HIVPPS');
|
||||||
|
$vopRequiredTypes = $hivpps?->parameter?->vopPflichtigerZahlungsverkehrsauftrag;
|
||||||
|
if ($vopRequiredTypes === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($requestSegments as $segment) {
|
||||||
|
if (in_array($segment->getName(), $vopRequiredTypes)) {
|
||||||
|
return $segment->getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return bool Whether the BPD indicates that the bank supports PSD2.
|
* @return bool Whether the BPD indicates that the bank supports PSD2.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
3
vendor/nemiah/php-fints/lib/Fhp/Protocol/DialogInitialization.php
vendored
Executable file → Normal file
3
vendor/nemiah/php-fints/lib/Fhp/Protocol/DialogInitialization.php
vendored
Executable file → Normal file
|
|
@ -143,7 +143,7 @@ class DialogInitialization extends BaseAction
|
||||||
$this->hktanRef,
|
$this->hktanRef,
|
||||||
$this->kundensystemId,
|
$this->kundensystemId,
|
||||||
$this->messageNumber,
|
$this->messageNumber,
|
||||||
$this->dialogId
|
$this->dialogId,
|
||||||
) = $serialized;
|
) = $serialized;
|
||||||
|
|
||||||
is_array($parentSerialized) ?
|
is_array($parentSerialized) ?
|
||||||
|
|
@ -151,7 +151,6 @@ class DialogInitialization extends BaseAction
|
||||||
parent::unserialize($parentSerialized);
|
parent::unserialize($parentSerialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||||
{
|
{
|
||||||
throw new \AssertionError('DialogInitialization::createRequest should not be used.');
|
throw new \AssertionError('DialogInitialization::createRequest should not be used.');
|
||||||
|
|
|
||||||
2
vendor/nemiah/php-fints/lib/Fhp/Protocol/GetTanMedia.php
vendored
Executable file → Normal file
2
vendor/nemiah/php-fints/lib/Fhp/Protocol/GetTanMedia.php
vendored
Executable file → Normal file
|
|
@ -17,7 +17,6 @@ class GetTanMedia extends BaseAction
|
||||||
/** @var TanMediumListe[]|null */
|
/** @var TanMediumListe[]|null */
|
||||||
private $tanMedia;
|
private $tanMedia;
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||||
{
|
{
|
||||||
// Prepare the HKTAB request.
|
// Prepare the HKTAB request.
|
||||||
|
|
@ -32,7 +31,6 @@ class GetTanMedia extends BaseAction
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritdoc} */
|
|
||||||
public function processResponse(Message $response)
|
public function processResponse(Message $response)
|
||||||
{
|
{
|
||||||
parent::processResponse($response);
|
parent::processResponse($response);
|
||||||
|
|
|
||||||
48
vendor/nemiah/php-fints/lib/Fhp/Protocol/Message.php
vendored
Executable file → Normal file
48
vendor/nemiah/php-fints/lib/Fhp/Protocol/Message.php
vendored
Executable file → Normal file
|
|
@ -190,12 +190,17 @@ class Message
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $code The response code to search for.
|
* @param int $code The response code to search for.
|
||||||
|
* @param ?int $requestSegmentNumber If set, only consider Rueckmeldungen that pertain to this request segment.
|
||||||
* @return Rueckmeldung|null The corresponding Rueckmeldung instance, or null if not found.
|
* @return Rueckmeldung|null The corresponding Rueckmeldung instance, or null if not found.
|
||||||
*/
|
*/
|
||||||
public function findRueckmeldung(int $code): ?Rueckmeldung
|
public function findRueckmeldung(int $code, ?int $requestSegmentNumber = null): ?Rueckmeldung
|
||||||
{
|
{
|
||||||
foreach ($this->plainSegments as $segment) {
|
foreach ($this->plainSegments as $segment) {
|
||||||
if ($segment instanceof RueckmeldungContainer) {
|
if (
|
||||||
|
$segment instanceof RueckmeldungContainer && (
|
||||||
|
$requestSegmentNumber === null || $segment->segmentkopf->bezugselement === $requestSegmentNumber
|
||||||
|
)
|
||||||
|
) {
|
||||||
$rueckmeldung = $segment->findRueckmeldung($code);
|
$rueckmeldung = $segment->findRueckmeldung($code);
|
||||||
if ($rueckmeldung !== null) {
|
if ($rueckmeldung !== null) {
|
||||||
return $rueckmeldung;
|
return $rueckmeldung;
|
||||||
|
|
@ -217,16 +222,29 @@ class Message
|
||||||
return $rueckmeldungen;
|
return $rueckmeldungen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $requestSegmentNumber Only consider Rueckmeldungen that pertain to this request segment.
|
||||||
|
* @return int[] The codes of all the Rueckmeldung instances matching the request segment.
|
||||||
|
*/
|
||||||
|
public function findRueckmeldungscodesForReferenceSegment(int $requestSegmentNumber): array
|
||||||
|
{
|
||||||
|
$codes = [];
|
||||||
|
foreach ($this->plainSegments as $segment) {
|
||||||
|
if ($segment instanceof RueckmeldungContainer && $segment->segmentkopf->bezugselement === $requestSegmentNumber) {
|
||||||
|
foreach ($segment->getAllRueckmeldungen() as $rueckmeldung) {
|
||||||
|
$codes[] = $rueckmeldung->rueckmeldungscode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $codes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string The HBCI/FinTS wire format for this message, ISO-8859-1 encoded.
|
* @return string The HBCI/FinTS wire format for this message, ISO-8859-1 encoded.
|
||||||
*/
|
*/
|
||||||
public function serialize(): string
|
public function serialize(): string
|
||||||
{
|
{
|
||||||
$result = '';
|
return Serializer::serializeSegments($this->wrapperSegments);
|
||||||
foreach ($this->wrapperSegments as $segment) {
|
|
||||||
$result .= Serializer::serializeSegment($segment);
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -300,14 +318,16 @@ class Message
|
||||||
$segments = Parser::parseSegments($rawMessage);
|
$segments = Parser::parseSegments($rawMessage);
|
||||||
|
|
||||||
// Message header and footer must always be there, or something went badly wrong.
|
// Message header and footer must always be there, or something went badly wrong.
|
||||||
if (!($segments[0] instanceof HNHBKv3)) {
|
|
||||||
throw new \InvalidArgumentException("Expected first segment to be HNHBK: $rawMessage");
|
|
||||||
}
|
|
||||||
if (!($segments[count($segments) - 1] instanceof HNHBSv1)) {
|
|
||||||
throw new \InvalidArgumentException("Expected last segment to be HNHBS: $rawMessage");
|
|
||||||
}
|
|
||||||
$result->header = $segments[0];
|
$result->header = $segments[0];
|
||||||
$result->footer = $segments[count($segments) - 1];
|
$result->footer = $segments[count($segments) - 1];
|
||||||
|
if (!($result->header instanceof HNHBKv3)) {
|
||||||
|
$actual = $result->header->getName();
|
||||||
|
throw new \InvalidArgumentException("Expected first segment to be HNHBK, but got $actual: $rawMessage");
|
||||||
|
}
|
||||||
|
if (!($result->footer instanceof HNHBSv1)) {
|
||||||
|
$actual = $result->footer->getName();
|
||||||
|
throw new \InvalidArgumentException("Expected last segment to be HNHBS, but got $actual: $rawMessage");
|
||||||
|
}
|
||||||
|
|
||||||
// Check if there's an encryption header and "encrypted" data.
|
// Check if there's an encryption header and "encrypted" data.
|
||||||
// Section B.8 specifies that there are exactly 4 segments: HNHBK, HNVSK, HNVSD, HNHBS.
|
// Section B.8 specifies that there are exactly 4 segments: HNHBK, HNVSK, HNVSD, HNHBS.
|
||||||
|
|
@ -351,7 +371,7 @@ class Message
|
||||||
* @param int $segmentNumber The number for the *first* segment, subsequent segment get the subsequent integers.
|
* @param int $segmentNumber The number for the *first* segment, subsequent segment get the subsequent integers.
|
||||||
* @return BaseSegment[] The same array, for chaining.
|
* @return BaseSegment[] The same array, for chaining.
|
||||||
*/
|
*/
|
||||||
private static function setSegmentNumbers(array $segments, int $segmentNumber): array
|
public static function setSegmentNumbers(array $segments, int $segmentNumber): array
|
||||||
{
|
{
|
||||||
foreach ($segments as $segment) {
|
foreach ($segments as $segment) {
|
||||||
$segment->segmentkopf->segmentnummer = $segmentNumber;
|
$segment->segmentkopf->segmentnummer = $segmentNumber;
|
||||||
|
|
|
||||||
0
vendor/nemiah/php-fints/lib/Fhp/Protocol/MessageBuilder.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Protocol/MessageBuilder.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Protocol/ServerException.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Protocol/ServerException.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Protocol/TanRequiredException.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Protocol/TanRequiredException.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Protocol/UPD.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Protocol/UPD.php
vendored
Executable file → Normal file
2
vendor/nemiah/php-fints/lib/Fhp/Protocol/UnexpectedResponseException.php
vendored
Executable file → Normal file
2
vendor/nemiah/php-fints/lib/Fhp/Protocol/UnexpectedResponseException.php
vendored
Executable file → Normal file
|
|
@ -8,7 +8,7 @@ namespace Fhp\Protocol;
|
||||||
*/
|
*/
|
||||||
class UnexpectedResponseException extends \RuntimeException
|
class UnexpectedResponseException extends \RuntimeException
|
||||||
{
|
{
|
||||||
public function __construct(string $message, int $code = 0, \Exception $previous = null)
|
public function __construct(string $message, int $code = 0, ?\Exception $previous = null)
|
||||||
{
|
{
|
||||||
parent::__construct($message, $code, $previous);
|
parent::__construct($message, $code, $previous);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
26
vendor/nemiah/php-fints/lib/Fhp/Protocol/VopConfirmationRequiredException.php
vendored
Normal file
26
vendor/nemiah/php-fints/lib/Fhp/Protocol/VopConfirmationRequiredException.php
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
/** @noinspection PhpUnused */
|
||||||
|
|
||||||
|
namespace Fhp\Protocol;
|
||||||
|
|
||||||
|
use Fhp\Model\VopConfirmationRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when an action result is read, but the action is still pending the user's confirmation of the Verification of
|
||||||
|
* Payee result.
|
||||||
|
*/
|
||||||
|
class VopConfirmationRequiredException extends \RuntimeException
|
||||||
|
{
|
||||||
|
private VopConfirmationRequest $vopConfirmationRequest;
|
||||||
|
|
||||||
|
public function __construct(VopConfirmationRequest $vopConfirmationRequest)
|
||||||
|
{
|
||||||
|
parent::__construct('This action needs VOP confirmation before it will be executed.');
|
||||||
|
$this->vopConfirmationRequest = $vopConfirmationRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVopConfirmationRequest(): VopConfirmationRequest
|
||||||
|
{
|
||||||
|
return $this->vopConfirmationRequest;
|
||||||
|
}
|
||||||
|
}
|
||||||
0
vendor/nemiah/php-fints/lib/Fhp/Segment/AUB/HIAUBSv9.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/AUB/HIAUBSv9.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/AUB/HKAUBv9.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/AUB/HKAUBv9.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/AUB/ParameterAuslandsueberweisungV2.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/AUB/ParameterAuslandsueberweisungV2.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/AnonymousSegment.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/AnonymousSegment.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/BME/HIBMESv1.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/BME/HIBMESv1.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/BME/HIBMESv2.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/BME/HIBMESv2.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/BME/HKBMEv1.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/BME/HKBMEv1.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/BME/HKBMEv2.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/BME/HKBMEv2.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/BME/ParameterTerminierteSEPAFirmenSammellastschriftEinreichenV1.php
vendored
Executable file → Normal file
0
vendor/nemiah/php-fints/lib/Fhp/Segment/BME/ParameterTerminierteSEPAFirmenSammellastschriftEinreichenV1.php
vendored
Executable file → Normal file
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue