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
|
||||
|
||||
### Hinzugefügt
|
||||
- **PDF-Kontoauszüge per FinTS (HKEKP)**: Elektronische Kontoauszüge direkt von der Bank abrufen
|
||||
- Neue Segmente für php-fints: HKEKPv2, HIEKPv2, HIEKPSv2, ParameterKontoauszugPdf
|
||||
- Neue Action-Klasse: GetStatementPDF für PDF-Abruf
|
||||
- **PDF-Kontoauszüge per FinTS**: Elektronische Kontoauszüge direkt von der Bank abrufen
|
||||
- **HKEKP**: Direkt-Abruf (für Banken die dies unterstützen)
|
||||
- **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
|
||||
- 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`
|
||||
- Aktivierbar über Konstante `BANKIMPORT_PDF_AUTO_ENABLED`
|
||||
- Ruft automatisch neue PDF-Kontoauszüge ab und speichert sie
|
||||
|
||||
### Geändert
|
||||
- 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
|
||||
- Erweiterung der php-fints Bibliothek um HKEKP-Unterstützung (Segment/EKP/*)
|
||||
- Neue Action-Klasse mit Pagination-Support für große PDF-Auszüge
|
||||
- Erweiterung der php-fints Bibliothek:
|
||||
- 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
|
||||
|
||||
|
|
|
|||
57
CLAUDE.md
57
CLAUDE.md
|
|
@ -17,35 +17,54 @@
|
|||
| `cron/bankimport.cron.php` | Cronjob für automatischen Import |
|
||||
| `admin/cronmonitor.php` | Cron-Monitoring und Pause/Resume |
|
||||
| `pdfstatements.php` | PDF-Kontoauszüge hochladen und per FinTS abrufen |
|
||||
| `vendor/.../Segment/EKP/*` | HKEKP-Segmente für PDF-Abruf |
|
||||
| `vendor/.../Action/GetStatementPDF.php` | Action-Klasse für PDF-Abruf |
|
||||
| `vendor/.../Segment/EKP/*` | HKEKP-Segmente für PDF-Abruf (direkt) |
|
||||
| `vendor/.../Segment/KAA/*` | HKKAA-Segmente für PDF-Abruf (Archiv) |
|
||||
| `vendor/.../Action/GetStatementPDF.php` | Action-Klasse für HKEKP |
|
||||
| `vendor/.../Action/GetStatementFromArchive.php` | Action-Klasse für HKKAA |
|
||||
|
||||
## PDF-Kontoauszüge per FinTS (HKEKP)
|
||||
## PDF-Kontoauszüge per FinTS
|
||||
|
||||
### Ü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
|
||||
```
|
||||
vendor/nemiah/php-fints/lib/Fhp/
|
||||
├── Action/GetStatementPDF.php # Haupt-Action-Klasse
|
||||
└── Segment/EKP/
|
||||
├── HKEKPv2.php # Request-Segment
|
||||
├── HIEKPv2.php # Response-Segment
|
||||
├── HIEKP.php # Response-Interface
|
||||
├── HIEKPSv2.php # Parameter-Segment
|
||||
├── HIEKPS.php # Parameter-Interface
|
||||
└── ParameterKontoauszugPdf.php # Parameter-Model
|
||||
├── Action/
|
||||
│ ├── GetStatementPDF.php # HKEKP Action
|
||||
│ └── GetStatementFromArchive.php # HKKAA Action
|
||||
└── Segment/
|
||||
├── EKP/ # HKEKP Segmente
|
||||
│ ├── HKEKPv2.php
|
||||
│ ├── HIEKPv2.php
|
||||
│ └── ...
|
||||
└── KAA/ # HKKAA Segmente
|
||||
├── HKKAAv2.php
|
||||
├── HIKAAv2.php
|
||||
├── HIKAASv1.php
|
||||
└── ParameterKontoauszugArchiv.php
|
||||
```
|
||||
|
||||
### Verwendung
|
||||
### Verwendung (empfohlen: Auto-Modus)
|
||||
```php
|
||||
$fints = new BankImportFinTS();
|
||||
if ($fints->supportsPdfStatements()) {
|
||||
$result = $fints->getStatementPDF(0); // Account-Index, optional Nr+Jahr
|
||||
if ($result['success']) {
|
||||
$pdfData = $result['data']['pdf'];
|
||||
$info = $result['data']['info']; // statementNumber, statementYear, etc.
|
||||
$fints = new BankImportFinTS($db);
|
||||
$fints->login();
|
||||
|
||||
// Automatische Methodenwahl
|
||||
$method = $fints->getPdfStatementMethod(); // 'HKEKP', 'HKKAA' oder false
|
||||
if ($method) {
|
||||
$result = $fints->getStatementPDFAuto(0);
|
||||
if (is_array($result) && !empty($result['pdfData'])) {
|
||||
$pdfData = $result['pdfData'];
|
||||
$info = $result['info'];
|
||||
$usedMethod = $result['method']; // 'HKEKP' oder 'HKKAA'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ use Fhp\Action\GetSEPAAccounts;
|
|||
use Fhp\Action\GetStatementOfAccount;
|
||||
use Fhp\Action\GetStatementOfAccountXML;
|
||||
use Fhp\Action\GetStatementPDF;
|
||||
use Fhp\Action\GetStatementFromArchive;
|
||||
use Fhp\Model\StatementOfAccount\Statement;
|
||||
use Fhp\Model\StatementOfAccount\Transaction;
|
||||
|
||||
|
|
@ -1139,4 +1140,180 @@ class BankImportFinTS
|
|||
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",
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"nemiah/php-fints": "^3.2"
|
||||
"nemiah/php-fints": "^4.0"
|
||||
},
|
||||
"replace": {
|
||||
"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",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "cfc07b7e6c4a3dcfdcd6e754983b1a9b",
|
||||
"content-hash": "32eb1d84f3157a4dee83ef5a81763257",
|
||||
"packages": [
|
||||
{
|
||||
"name": "nemiah/php-fints",
|
||||
"version": "3.7.0",
|
||||
"version": "4.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nemiah/phpFinTS.git",
|
||||
"reference": "08257e10229db2d4ca8c54ed7fec0f390b332519"
|
||||
"reference": "b37e6df7efd39b4e757537e782241d5abb6b2bb5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nemiah/phpFinTS/zipball/08257e10229db2d4ca8c54ed7fec0f390b332519",
|
||||
"reference": "08257e10229db2d4ca8c54ed7fec0f390b332519",
|
||||
"url": "https://api.github.com/repos/nemiah/phpFinTS/zipball/b37e6df7efd39b4e757537e782241d5abb6b2bb5",
|
||||
"reference": "b37e6df7efd39b4e757537e782241d5abb6b2bb5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-mbstring": "*",
|
||||
"php": ">=8.0",
|
||||
"php": ">=8.3",
|
||||
"psr/log": "^1|^2|^3"
|
||||
},
|
||||
"require-dev": {
|
||||
|
|
@ -51,9 +51,9 @@
|
|||
"homepage": "https://github.com/nemiah/phpFinTS",
|
||||
"support": {
|
||||
"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": [],
|
||||
|
|
|
|||
|
|
@ -101,13 +101,16 @@ if ($action == 'fetchpdf' || $action == 'fetchpdf_single') {
|
|||
setEventMessages($langs->trans("TANRequired").($fints->tanChallenge ? ': '.$fints->tanChallenge : ''), null, 'warnings');
|
||||
$fints->close();
|
||||
} else {
|
||||
// Check if bank supports HKEKP
|
||||
if (!$fints->supportsPdfStatements()) {
|
||||
// Check if bank supports any PDF statement method (HKEKP or HKKAA)
|
||||
$pdfMethod = $fints->getPdfStatementMethod();
|
||||
if ($pdfMethod === false) {
|
||||
setEventMessages($langs->trans("ErrorBankDoesNotSupportPdfStatements"), null, 'errors');
|
||||
$fints->close();
|
||||
} else {
|
||||
// Fetch PDF
|
||||
$pdfResult = $fints->getStatementPDF(0, $fetchNumber, $fetchYear);
|
||||
dol_syslog("BankImport: Using PDF method: ".$pdfMethod, LOG_DEBUG);
|
||||
|
||||
// Fetch PDF using auto method (tries HKEKP first, falls back to HKKAA)
|
||||
$pdfResult = $fints->getStatementPDFAuto(0, $fetchNumber, $fetchYear);
|
||||
|
||||
if ($pdfResult === 0) {
|
||||
// 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": [
|
||||
{
|
||||
"name": "nemiah/php-fints",
|
||||
"version": "3.7.0",
|
||||
"version_normalized": "3.7.0.0",
|
||||
"version": "4.0.0",
|
||||
"version_normalized": "4.0.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nemiah/phpFinTS.git",
|
||||
"reference": "08257e10229db2d4ca8c54ed7fec0f390b332519"
|
||||
"reference": "b37e6df7efd39b4e757537e782241d5abb6b2bb5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nemiah/phpFinTS/zipball/08257e10229db2d4ca8c54ed7fec0f390b332519",
|
||||
"reference": "08257e10229db2d4ca8c54ed7fec0f390b332519",
|
||||
"url": "https://api.github.com/repos/nemiah/phpFinTS/zipball/b37e6df7efd39b4e757537e782241d5abb6b2bb5",
|
||||
"reference": "b37e6df7efd39b4e757537e782241d5abb6b2bb5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-mbstring": "*",
|
||||
"php": ">=8.0",
|
||||
"php": ">=8.3",
|
||||
"psr/log": "^1|^2|^3"
|
||||
},
|
||||
"require-dev": {
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
"monolog/monolog": "Allow sending log messages to a variety of different handlers",
|
||||
"nemiah/php-sepa-xml": "dev-master"
|
||||
},
|
||||
"time": "2025-10-14T15:05:56+00:00",
|
||||
"time": "2026-01-16T07:56:30+00:00",
|
||||
"type": "library",
|
||||
"installation-source": "dist",
|
||||
"autoload": {
|
||||
|
|
@ -48,7 +48,7 @@
|
|||
"homepage": "https://github.com/nemiah/phpFinTS",
|
||||
"support": {
|
||||
"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"
|
||||
}
|
||||
|
|
|
|||
18
vendor/composer/installed.php
vendored
18
vendor/composer/installed.php
vendored
|
|
@ -1,9 +1,9 @@
|
|||
<?php return array(
|
||||
'root' => array(
|
||||
'name' => 'dolibarr/bankimport',
|
||||
'pretty_version' => '1.0.0+no-version-set',
|
||||
'version' => '1.0.0.0',
|
||||
'reference' => null,
|
||||
'pretty_version' => 'dev-main',
|
||||
'version' => 'dev-main',
|
||||
'reference' => 'fc380892f035d3a48038c3c0cedef76fd0fec404',
|
||||
'type' => 'dolibarr-module',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
|
|
@ -11,18 +11,18 @@
|
|||
),
|
||||
'versions' => array(
|
||||
'dolibarr/bankimport' => array(
|
||||
'pretty_version' => '1.0.0+no-version-set',
|
||||
'version' => '1.0.0.0',
|
||||
'reference' => null,
|
||||
'pretty_version' => 'dev-main',
|
||||
'version' => 'dev-main',
|
||||
'reference' => 'fc380892f035d3a48038c3c0cedef76fd0fec404',
|
||||
'type' => 'dolibarr-module',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'nemiah/php-fints' => array(
|
||||
'pretty_version' => '3.7.0',
|
||||
'version' => '3.7.0.0',
|
||||
'reference' => '08257e10229db2d4ca8c54ed7fec0f390b332519',
|
||||
'pretty_version' => '4.0.0',
|
||||
'version' => '4.0.0.0',
|
||||
'reference' => 'b37e6df7efd39b4e757537e782241d5abb6b2bb5',
|
||||
'type' => 'library',
|
||||
'install_path' => __DIR__ . '/../nemiah/php-fints',
|
||||
'aliases' => array(),
|
||||
|
|
|
|||
4
vendor/composer/platform_check.php
vendored
4
vendor/composer/platform_check.php
vendored
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
$issues = array();
|
||||
|
||||
if (!(PHP_VERSION_ID >= 80000)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.0.0". You are running ' . PHP_VERSION . '.';
|
||||
if (!(PHP_VERSION_ID >= 80300)) {
|
||||
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.3.0". You are running ' . PHP_VERSION . '.';
|
||||
}
|
||||
|
||||
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:
|
||||
// Logic
|
||||
'yoda_style' => FALSE, // Allow both Yoda-style and regular comparisons.
|
||||
'yoda_style' => false, // Allow both Yoda-style and regular comparisons.
|
||||
|
||||
// Whitespace
|
||||
'blank_line_before_statement' => FALSE, // Don't put blank lines before `return` statements.
|
||||
'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.
|
||||
'single_line_throw' => FALSE, // Allow `throw` statements to span multiple lines.
|
||||
'blank_line_before_statement' => false, // Don't put blank lines before `return` statements.
|
||||
'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.
|
||||
'single_line_throw' => false, // Allow `throw` statements to span multiple lines.
|
||||
|
||||
// phpDoc
|
||||
'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_no_alias_tag' => FALSE, // Allow @link in addition to @see.
|
||||
'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_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_no_alias_tag' => false, // Allow @link in addition to @see.
|
||||
'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.
|
||||
])
|
||||
->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
|
||||
|
||||
[](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:
|
||||
|
||||
|
|
|
|||
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);
|
||||
$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'));
|
||||
$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 */
|
||||
$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->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());
|
||||
$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",
|
||||
"description": "PHP Library for the protocols fints and hbci",
|
||||
"homepage": "https://github.com/nemiah/phpFinTS",
|
||||
"version": "3.7.0",
|
||||
"version": "4.0.0",
|
||||
"license": "MIT",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
}
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"php": ">=8.3",
|
||||
"psr/log": "^1|^2|^3",
|
||||
"ext-curl": "*",
|
||||
"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
|
||||
{
|
||||
// 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 */
|
||||
private $account;
|
||||
/** @var bool */
|
||||
|
|
@ -79,7 +79,7 @@ class GetBalance extends PaginateableAction
|
|||
{
|
||||
list(
|
||||
$parentSerialized,
|
||||
$this->account, $this->allAccounts
|
||||
$this->account, $this->allAccounts,
|
||||
) = $serialized;
|
||||
|
||||
is_array($parentSerialized) ?
|
||||
|
|
@ -96,7 +96,6 @@ class GetBalance extends PaginateableAction
|
|||
return $this->response;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||
{
|
||||
/** @var BaseSegment $hisals */
|
||||
|
|
@ -115,7 +114,6 @@ class GetBalance extends PaginateableAction
|
|||
}
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function processResponse(Message $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
|
||||
{
|
||||
// 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 */
|
||||
private $account;
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ class GetDepotAufstellung extends PaginateableAction
|
|||
{
|
||||
list(
|
||||
$parentSerialized,
|
||||
$this->account
|
||||
$this->account,
|
||||
) = $serialized;
|
||||
|
||||
is_array($parentSerialized) ?
|
||||
|
|
@ -111,7 +111,6 @@ class GetDepotAufstellung extends PaginateableAction
|
|||
return $this->depotWert;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||
{
|
||||
/** @var HIWPDS $hiwpds */
|
||||
|
|
@ -125,7 +124,6 @@ class GetDepotAufstellung extends PaginateableAction
|
|||
}
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function processResponse(Message $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;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||
{
|
||||
/** @var BaseSegment $hispas */
|
||||
|
|
@ -64,7 +63,6 @@ class GetSEPAAccounts extends PaginateableAction
|
|||
}
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function processResponse(Message $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 DIRECT_DEBIT_TYPES = ['CORE', 'COR1', 'B2B'];
|
||||
|
||||
// Request (if you add a field here, update __serialize() and __unserialize() as well).
|
||||
/** @var string */
|
||||
private $directDebitType;
|
||||
|
||||
/** @var string */
|
||||
private $seqType;
|
||||
|
||||
/** @var bool */
|
||||
private $singleDirectDebit;
|
||||
|
||||
|
|
@ -43,6 +42,45 @@ class GetSEPADirectDebitParameters extends BaseAction
|
|||
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
|
||||
{
|
||||
switch ($directDebitType) {
|
||||
|
|
@ -56,7 +94,6 @@ class GetSEPADirectDebitParameters extends BaseAction
|
|||
}
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||
{
|
||||
$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
|
||||
{
|
||||
// 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 */
|
||||
private $account;
|
||||
/** @var \DateTime */
|
||||
|
|
@ -93,7 +93,7 @@ class GetStatementOfAccount extends PaginateableAction
|
|||
{
|
||||
return [
|
||||
parent::__serialize(),
|
||||
$this->account, $this->from, $this->to, $this->allAccounts,
|
||||
$this->account, $this->from, $this->to, $this->allAccounts, $this->includeUnbooked,
|
||||
$this->bankName,
|
||||
];
|
||||
}
|
||||
|
|
@ -113,8 +113,8 @@ class GetStatementOfAccount extends PaginateableAction
|
|||
{
|
||||
list(
|
||||
$parentSerialized,
|
||||
$this->account, $this->from, $this->to, $this->allAccounts,
|
||||
$this->bankName
|
||||
$this->account, $this->from, $this->to, $this->allAccounts, $this->includeUnbooked,
|
||||
$this->bankName,
|
||||
) = $serialized;
|
||||
|
||||
is_array($parentSerialized) ?
|
||||
|
|
@ -147,7 +147,6 @@ class GetStatementOfAccount extends PaginateableAction
|
|||
return $this->statement;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||
{
|
||||
$this->bankName = $bpd->getBankName();
|
||||
|
|
@ -171,7 +170,6 @@ class GetStatementOfAccount extends PaginateableAction
|
|||
}
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function processResponse(Message $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
|
||||
{
|
||||
// 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 */
|
||||
private $account;
|
||||
/** @var \DateTime */
|
||||
|
|
@ -98,7 +98,7 @@ class GetStatementOfAccountXML extends PaginateableAction
|
|||
{
|
||||
list(
|
||||
$parentSerialized,
|
||||
$this->account, $this->camtURN, $this->from, $this->to, $this->allAccounts
|
||||
$this->account, $this->camtURN, $this->from, $this->to, $this->allAccounts,
|
||||
) = $serialized;
|
||||
|
||||
is_array($parentSerialized) ?
|
||||
|
|
@ -115,7 +115,6 @@ class GetStatementOfAccountXML extends PaginateableAction
|
|||
return $this->xml;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||
{
|
||||
if ($upd === null) {
|
||||
|
|
@ -149,7 +148,6 @@ class GetStatementOfAccountXML extends PaginateableAction
|
|||
}
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function processResponse(Message $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
|
||||
{
|
||||
// Request (if you add a field here, update __serialize() and __unserialize() as well).
|
||||
/** @var SEPAAccount */
|
||||
protected $account;
|
||||
|
||||
/** @var string */
|
||||
protected $dtavzData;
|
||||
|
||||
/** @var string|null */
|
||||
protected $dtavzVersion;
|
||||
|
||||
|
|
@ -36,6 +35,45 @@ class SendInternationalCreditTransfer extends BaseAction
|
|||
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)
|
||||
{
|
||||
/** @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\DME\HIDMESv1;
|
||||
use Fhp\Segment\DME\HIDMESv2;
|
||||
use Fhp\Segment\DME\HKDMEv2;
|
||||
use Fhp\Segment\DSE\HIDSESv2;
|
||||
use Fhp\Segment\DSE\HIDXES;
|
||||
use Fhp\Segment\DSE\HKDSEv2;
|
||||
use Fhp\Segment\SPA\HISPAS;
|
||||
use Fhp\Syntax\Bin;
|
||||
use Fhp\UnsupportedException;
|
||||
|
|
@ -22,27 +24,24 @@ use Fhp\UnsupportedException;
|
|||
*/
|
||||
class SendSEPADirectDebit extends BaseAction
|
||||
{
|
||||
// Request (if you add a field here, update __serialize() and __unserialize() as well).
|
||||
/** @var SEPAAccount */
|
||||
protected $account;
|
||||
|
||||
/** @var string */
|
||||
protected $painMessage;
|
||||
|
||||
/** @var string */
|
||||
protected $painNamespace;
|
||||
|
||||
/** @var float */
|
||||
protected $ctrlSum;
|
||||
|
||||
/** @var bool */
|
||||
protected $singleDirectDebit = false;
|
||||
|
||||
/** @var bool */
|
||||
protected $tryToUseControlSumForSingleTransactions = false;
|
||||
|
||||
/** @var string */
|
||||
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
|
||||
{
|
||||
if (preg_match('/xmlns="(?<namespace>[^"]+)"/s', $painMessage, $matches) === 1) {
|
||||
|
|
@ -114,7 +113,7 @@ class SendSEPADirectDebit extends BaseAction
|
|||
{
|
||||
list(
|
||||
$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;
|
||||
|
||||
is_array($parentSerialized) ?
|
||||
|
|
@ -151,7 +150,7 @@ class SendSEPADirectDebit extends BaseAction
|
|||
// Sometimes the Bank reports supported schemas with a "_GBIC_X" postfix.
|
||||
// GIBC_X stands for German Banking Industry Committee and a version counter.
|
||||
$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
|
||||
// urn:iso:std:iso:20022:tech:xsd:pain.008.001.08_GBIC_4
|
||||
return str_starts_with($value, $xmlSchema);
|
||||
|
|
@ -162,7 +161,7 @@ class SendSEPADirectDebit extends BaseAction
|
|||
. implode(', ', $supportedPainNamespaces));
|
||||
}
|
||||
|
||||
/** @var mixed $hkdxe */ // TODO Put a new interface type here.
|
||||
/** @var HKDMEv2|HKDSEv2|HIDXES $hkdxe */
|
||||
$hkdxe = $hidxes->createRequestSegment();
|
||||
$hkdxe->kontoverbindungInternational = Kti::fromAccount($this->account);
|
||||
$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
|
||||
{
|
||||
// Request (if you add a field here, update __serialize() and __unserialize() as well).
|
||||
/** @var SEPAAccount */
|
||||
private $account;
|
||||
/** @var string */
|
||||
private $painMessage;
|
||||
/** @var string */
|
||||
private $xmlSchema;
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
/** {@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)
|
||||
{
|
||||
/** @var HIIPZSv1|HIIPZSv2 $hiipzs */
|
||||
|
|
@ -70,7 +110,7 @@ class SendSEPARealtimeTransfer extends BaseAction
|
|||
// Sometimes the Bank reports supported schemas with a "_GBIC_X" postfix.
|
||||
// GIBC_X stands for German Banking Industry Committee and a version counter.
|
||||
$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
|
||||
// urn:iso:std:iso:20022:tech:xsd:pain.001.001.09_GBIC_4
|
||||
return str_starts_with($value, $xmlSchema);
|
||||
|
|
@ -92,7 +132,6 @@ class SendSEPARealtimeTransfer extends BaseAction
|
|||
return $hkipz;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function processResponse(Message $response)
|
||||
{
|
||||
parent::processResponse($response);
|
||||
|
|
@ -106,8 +145,8 @@ class SendSEPARealtimeTransfer extends BaseAction
|
|||
return;
|
||||
}
|
||||
|
||||
if ($response->findRueckmeldung(Rueckmeldungscode::ENTGEGENGENOMMEN) === null &&
|
||||
$response->findRueckmeldung(Rueckmeldungscode::AUSGEFUEHRT) === null) {
|
||||
if ($response->findRueckmeldung(Rueckmeldungscode::ENTGEGENGENOMMEN) === null
|
||||
&& $response->findRueckmeldung(Rueckmeldungscode::AUSGEFUEHRT) === null) {
|
||||
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
|
||||
{
|
||||
// Request (if you add a field here, update __serialize() and __unserialize() as well).
|
||||
/** @var SEPAAccount */
|
||||
private $account;
|
||||
/** @var string */
|
||||
private $painMessage;
|
||||
/** @var string */
|
||||
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.
|
||||
|
|
@ -44,11 +49,62 @@ class SendSEPATransfer extends BaseAction
|
|||
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)
|
||||
{
|
||||
//ANALYSE XML FOR RECEIPTS AND PAYMENT DATE
|
||||
$xmlAsObject = simplexml_load_string($this->painMessage, "SimpleXMLElement", LIBXML_NOCDATA);
|
||||
// ANALYSE XML FOR RECEIPTS AND PAYMENT DATE
|
||||
$xmlAsObject = simplexml_load_string($this->painMessage, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||
$numberOfTransactions = $xmlAsObject->CstmrCdtTrfInitn->GrpHdr->NbOfTxs;
|
||||
$hasReqdExDates = false;
|
||||
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) {
|
||||
|
||||
// Terminierte SEPA-Sammelüberweisung (Segment HKCME / Kennung HICMES)
|
||||
$segmentID = 'HICMES';
|
||||
$segment = \Fhp\Segment\CME\HKCMEv1::createEmpty();
|
||||
} elseif ($numberOfTransactions == 1 && $hasReqdExDates) {
|
||||
|
||||
// Terminierte SEPA-Überweisung (Segment HKCSE / Kennung HICSES)
|
||||
$segmentID = 'HICSES';
|
||||
$segment = \Fhp\Segment\CSE\HKCSEv1::createEmpty();
|
||||
} elseif ($numberOfTransactions > 1 && !$hasReqdExDates) {
|
||||
|
||||
// SEPA-Sammelüberweisungen (Segment HKCCM / Kennung HICSES)
|
||||
$segmentID = 'HICSES';
|
||||
$segment = \Fhp\Segment\CCM\HKCCMv1::createEmpty();
|
||||
} else {
|
||||
|
||||
//SEPA Einzelüberweisung (Segment HKCCS / Kennung HICCSS).
|
||||
// SEPA Einzelüberweisung (Segment HKCCS / Kennung HICCSS).
|
||||
$segmentID = 'HICCSS';
|
||||
$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.
|
||||
// GIBC_X stands for German Banking Industry Committee and a version counter.
|
||||
$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
|
||||
// urn:iso:std:iso:20022:tech:xsd:pain.001.001.09_GBIC_4
|
||||
return str_starts_with($value, $xmlSchema);
|
||||
|
|
@ -107,10 +159,19 @@ class SendSEPATransfer extends BaseAction
|
|||
$segment->kontoverbindungInternational = Kti::fromAccount($this->account);
|
||||
$segment->sepaDescriptor = $this->xmlSchema;
|
||||
$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;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function processResponse(Message $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;
|
||||
|
||||
use Fhp\Model\PollingInfo;
|
||||
use Fhp\Model\TanRequest;
|
||||
use Fhp\Model\VopConfirmationRequest;
|
||||
use Fhp\Protocol\ActionIncompleteException;
|
||||
use Fhp\Protocol\ActionPendingException;
|
||||
use Fhp\Protocol\BPD;
|
||||
use Fhp\Protocol\Message;
|
||||
use Fhp\Protocol\TanRequiredException;
|
||||
use Fhp\Protocol\UnexpectedResponseException;
|
||||
use Fhp\Protocol\UPD;
|
||||
use Fhp\Protocol\VopConfirmationRequiredException;
|
||||
use Fhp\Segment\BaseSegment;
|
||||
use Fhp\Segment\HIRMS\Rueckmeldung;
|
||||
use Fhp\Segment\HIRMS\Rueckmeldungscode;
|
||||
|
|
@ -37,37 +41,37 @@ use Fhp\Segment\HIRMS\Rueckmeldungscode;
|
|||
abstract class BaseAction implements \Serializable
|
||||
{
|
||||
/** @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.
|
||||
*/
|
||||
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.
|
||||
* @var TanRequest|null
|
||||
*/
|
||||
protected $tanRequest;
|
||||
/** If set, the last response from the server regarding this action asked for a TAN from the user. */
|
||||
protected ?TanRequest $tanRequest = null;
|
||||
|
||||
/** @var bool */
|
||||
protected $isDone = false;
|
||||
/** If set, this action is currently waiting for a long-running operation on the server to complete. */
|
||||
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
|
||||
* 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
|
||||
*
|
||||
* 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
|
||||
* present yet.
|
||||
* An action can only be serialized before it was completed.
|
||||
* 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.
|
||||
*/
|
||||
|
|
@ -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
|
||||
* present yet.
|
||||
* An action can only be serialized before it was completed.
|
||||
* 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.
|
||||
* 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
|
||||
{
|
||||
if (!$this->needsTan()) {
|
||||
throw new \RuntimeException('Cannot serialize this action, because it is not waiting for a TAN.');
|
||||
if ($this->isDone()) {
|
||||
throw new \RuntimeException('Completed actions cannot be serialized.');
|
||||
}
|
||||
return [
|
||||
$this->requestSegmentNumbers,
|
||||
$this->tanRequest,
|
||||
$this->needTanForSegment,
|
||||
$this->pollingInfo,
|
||||
$this->vopConfirmationRequest,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -111,8 +117,10 @@ abstract class BaseAction implements \Serializable
|
|||
list(
|
||||
$this->requestSegmentNumbers,
|
||||
$this->tanRequest,
|
||||
$this->needTanForSegment
|
||||
) = $serialized;
|
||||
$this->needTanForSegment,
|
||||
$this->pollingInfo,
|
||||
$this->vopConfirmationRequest,
|
||||
) = array_pad($serialized, 5, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -144,25 +152,54 @@ abstract class BaseAction implements \Serializable
|
|||
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:
|
||||
* - the action has not been {@link FinTs::execute()}-d at all or the {@link FinTs::execute()} call for it threw an
|
||||
* 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
|
||||
* 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
|
||||
* {@link FinTs::execute()} and (2) you checked {@link needsTan()} and, if it returned true, supplied a TAN by
|
||||
* calling {@ink FinTs::submitTan()}. Note that both exception types thrown from this method are sub-classes of
|
||||
* {@link \RuntimeException}, so you shouldn't need a try-catch block at the call site for this.
|
||||
* {@link FinTs::execute()} and (2) you checked and resolved all other special outcome states documented there.
|
||||
* Note that both exception types thrown from this method are sub-classes of {@link \RuntimeException}, so you
|
||||
* shouldn't need a try-catch block at the call site for this.
|
||||
* @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.
|
||||
*/
|
||||
public function ensureDone()
|
||||
public function ensureDone(): void
|
||||
{
|
||||
if ($this->tanRequest !== null) {
|
||||
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()) {
|
||||
throw new ActionIncompleteException();
|
||||
}
|
||||
|
|
@ -231,7 +268,7 @@ abstract class BaseAction implements \Serializable
|
|||
/** @return int[] */
|
||||
public function getRequestSegmentNumbers(): array
|
||||
{
|
||||
return $this->requestSegmentNumbers;
|
||||
return $this->requestSegmentNumbers ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -248,11 +285,21 @@ abstract class BaseAction implements \Serializable
|
|||
$this->requestSegmentNumbers = $requestSegmentNumbers;
|
||||
}
|
||||
|
||||
/**
|
||||
* To be called only by the FinTs instance that executes this action.
|
||||
*/
|
||||
final public function setTanRequest(?TanRequest $tanRequest)
|
||||
/** To be called only by the FinTs instance that executes this action. */
|
||||
final public function setTanRequest(?TanRequest $tanRequest): void
|
||||
{
|
||||
$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
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $url;
|
||||
|
||||
/**
|
||||
* @var resource
|
||||
*/
|
||||
protected $curlHandle;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $timeoutConnect = 15;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $timeoutResponse = 30;
|
||||
protected string $url;
|
||||
protected ?\CurlHandle $curlHandle = null;
|
||||
protected int $timeoutConnect = 15;
|
||||
protected int $timeoutResponse = 30;
|
||||
|
||||
public function __construct(string $url, int $timeoutConnect = 15, int $timeoutResponse = 30)
|
||||
{
|
||||
|
|
@ -34,9 +19,12 @@ class Connection
|
|||
$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_VERIFYHOST, 2);
|
||||
|
|
@ -52,7 +40,7 @@ class Connection
|
|||
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) {
|
||||
curl_close($this->curlHandle);
|
||||
|
|
@ -76,7 +64,7 @@ class Connection
|
|||
|
||||
if (false === $response) {
|
||||
throw new CurlException(
|
||||
'Failed connection to ' . $this->url . ': ' . curl_error($this->curlHandle),
|
||||
'Failed sending to ' . $this->url . ': ' . curl_error($this->curlHandle),
|
||||
null,
|
||||
curl_errno($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\TanMedium;
|
||||
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\FinTsOptions;
|
||||
use Fhp\Options\SanitizingLogger;
|
||||
|
|
@ -26,6 +30,8 @@ use Fhp\Segment\TAN\HITAN;
|
|||
use Fhp\Segment\TAN\HKTAN;
|
||||
use Fhp\Segment\TAN\HKTANFactory;
|
||||
use Fhp\Segment\TAN\HKTANv6;
|
||||
use Fhp\Segment\VPP\HKVPPv1;
|
||||
use Fhp\Segment\VPP\VopHelper;
|
||||
use Fhp\Syntax\InvalidResponseException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
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
|
||||
* 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.
|
||||
* 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
|
||||
{
|
||||
|
|
@ -201,7 +208,7 @@ class FinTs
|
|||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function loadPersistedInstance(string $persistedInstance)
|
||||
public function loadPersistedInstance(string $persistedInstance): void
|
||||
{
|
||||
$unserialized = unserialize($persistedInstance);
|
||||
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().
|
||||
$this->bpd,
|
||||
|
|
@ -226,7 +233,7 @@ class FinTs
|
|||
$this->selectedTanMedium,
|
||||
$this->kundensystemId,
|
||||
$this->dialogId,
|
||||
$this->messageNumber
|
||||
$this->messageNumber,
|
||||
) = $data;
|
||||
}
|
||||
|
||||
|
|
@ -254,7 +261,7 @@ class FinTs
|
|||
* @param int $responseTimeout The number of seconds to wait before aborting a request to the bank server.
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function setTimeouts(int $connectTimeout, int $responseTimeout)
|
||||
public function setTimeouts(int $connectTimeout, int $responseTimeout): void
|
||||
{
|
||||
$this->options->timeoutConnect = $connectTimeout;
|
||||
$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
|
||||
* 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
|
||||
* 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
|
||||
|
|
@ -293,9 +300,30 @@ class FinTs
|
|||
* 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
|
||||
* 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
|
||||
* getters on the action instance to retrieve the result. In case the action fails, the corresponding exception
|
||||
* will be thrown from this function.
|
||||
* 2. If {@link BaseAction::needsPollingWait()} returns true, the action isn't completed yet because the server is
|
||||
* still running some slow operation. Importantly, the server has not necessarily accepted the action yet, so it
|
||||
* 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
|
||||
* 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
|
||||
* 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)) {
|
||||
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);
|
||||
|
||||
if (count($requestSegments) === 0) {
|
||||
return; // No request needed.
|
||||
}
|
||||
$message = MessageBuilder::create()->add($requestSegments);
|
||||
|
||||
// Construct the full request message.
|
||||
$message = MessageBuilder::create()->add($requestSegments); // This fills in the segment numbers.
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
$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) {
|
||||
/* @var BaseSegment $segment */
|
||||
return $segment->getSegmentNumber();
|
||||
|
|
@ -332,11 +369,28 @@ class FinTs
|
|||
|
||||
// Execute the 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);
|
||||
|
||||
// Detect if the bank wants a TAN.
|
||||
/** @var HITAN $hitan */
|
||||
$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->tanProzess !== HKTAN::TAN_PROZESS_4) {
|
||||
throw new UnexpectedResponseException("Unsupported TAN request type $hitan->tanProzess");
|
||||
|
|
@ -350,14 +404,51 @@ class FinTs
|
|||
$action->setDialogId($response->header->dialogId);
|
||||
$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()));
|
||||
if ($action instanceof PaginateableAction && $action->hasMorePages()) {
|
||||
$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()},
|
||||
* 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
|
||||
* just as if it had been completed by the original call to {@link execute()} right away. In case the action fails,
|
||||
* the corresponding exception will be thrown from this function.
|
||||
* After this function returns, the `$action` is in any of the same states as after {@link execute()}, see there.
|
||||
* 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.
|
||||
*
|
||||
* @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
|
||||
|
|
@ -379,7 +470,7 @@ class FinTs
|
|||
* @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.
|
||||
*/
|
||||
public function submitTan(BaseAction $action, string $tan)
|
||||
public function submitTan(BaseAction $action, string $tan): void
|
||||
{
|
||||
// Check the action's state.
|
||||
$tanRequest = $action->getTanRequest();
|
||||
|
|
@ -433,7 +524,9 @@ class FinTs
|
|||
* 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
|
||||
* 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.
|
||||
* - If the authentication has not been completed yet, this returns `false` and the action remains in its
|
||||
* previous, uncompleted state.
|
||||
|
|
@ -449,9 +542,10 @@ class FinTs
|
|||
* Section B.4.2.2
|
||||
*
|
||||
* @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
|
||||
* {@link TanRequest} inside the action has been updated, which *may* provide new/more instructions to the user,
|
||||
* though probably it rarely does in practice.
|
||||
* @return bool True if the decoupled authentication is done and the $action was completed or entered one of the
|
||||
* other states documented on {@link execute()}.
|
||||
* 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 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
|
||||
|
|
@ -530,6 +624,99 @@ class FinTs
|
|||
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
|
||||
* 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.
|
||||
* @throws ServerException When closing the dialog fails.
|
||||
*/
|
||||
public function close()
|
||||
public function close(): void
|
||||
{
|
||||
if ($this->dialogId !== null) {
|
||||
$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
|
||||
* 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;
|
||||
}
|
||||
|
|
@ -571,9 +758,11 @@ class FinTs
|
|||
public function getTanModes(): array
|
||||
{
|
||||
$this->ensureTanModesAvailable();
|
||||
$result = array();
|
||||
$result = [];
|
||||
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];
|
||||
}
|
||||
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
|
||||
* 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)) {
|
||||
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 ServerException When the server resopnds with an error.
|
||||
*/
|
||||
private function ensureBpdAvailable()
|
||||
private function ensureBpdAvailable(): void
|
||||
{
|
||||
if ($this->bpd !== null) {
|
||||
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.
|
||||
* @throws ServerException When the server responds with an error.
|
||||
*/
|
||||
private function ensureTanModesAvailable()
|
||||
private function ensureTanModesAvailable(): void
|
||||
{
|
||||
if ($this->allowedTanModes === null) {
|
||||
$this->ensureBpdAvailable();
|
||||
|
|
@ -730,7 +919,7 @@ class FinTs
|
|||
* dialog is not closed properly.
|
||||
* @throws ServerException When the server responds with an error.
|
||||
*/
|
||||
private function ensureSynchronized()
|
||||
private function ensureSynchronized(): void
|
||||
{
|
||||
if ($this->kundensystemId === null) {
|
||||
$this->ensureBpdAvailable();
|
||||
|
|
@ -820,7 +1009,7 @@ class FinTs
|
|||
/**
|
||||
* Closes the physical connection, if necessary.
|
||||
*/
|
||||
private function disconnect()
|
||||
private function disconnect(): void
|
||||
{
|
||||
if ($this->connection !== null) {
|
||||
$this->connection->disconnect();
|
||||
|
|
@ -834,7 +1023,7 @@ class FinTs
|
|||
* @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.
|
||||
*/
|
||||
private function processActionResponse(BaseAction $action, Message $fakeResponseMessage)
|
||||
private function processActionResponse(BaseAction $action, Message $fakeResponseMessage): void
|
||||
{
|
||||
$action->processResponse($fakeResponseMessage);
|
||||
if ($action instanceof DialogInitialization) {
|
||||
|
|
@ -864,7 +1053,7 @@ class FinTs
|
|||
* properly.
|
||||
* @throws ServerException When the server responds with an error.
|
||||
*/
|
||||
private function executeWeakDialogInitialization(?string $hktanRef)
|
||||
private function executeWeakDialogInitialization(?string $hktanRef): void
|
||||
{
|
||||
if ($this->dialogId !== null) {
|
||||
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
|
||||
* 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) {
|
||||
$this->dialogId = null;
|
||||
|
|
@ -943,7 +1132,7 @@ class FinTs
|
|||
* @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
|
||||
* (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.
|
||||
*/
|
||||
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';
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function extractStructuredDataFromRemittanceLines($descriptionLines, string &$gvc, array &$rawLines, array $transaction): array
|
||||
{
|
||||
// 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';
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function extractStructuredDataFromRemittanceLines($descriptionLines, string &$gvc, array &$rawLines, array $transaction): array
|
||||
{
|
||||
$otherInfo = [];
|
||||
|
|
|
|||
4
vendor/nemiah/php-fints/lib/Fhp/MT940/MT940.php
vendored
Executable file → Normal file
4
vendor/nemiah/php-fints/lib/Fhp/MT940/MT940.php
vendored
Executable file → Normal file
|
|
@ -142,8 +142,8 @@ class MT940
|
|||
$soaDate = $this->getDate(substr($day[$i], 1, 6));
|
||||
|
||||
if (isset($result[$soaDate])) {
|
||||
#$result[$soaDate] = ['end_balance' => []];
|
||||
|
||||
// $result[$soaDate] = ['end_balance' => []];
|
||||
|
||||
$amount = str_replace(',', '.', substr($day[$i], 10, -1));
|
||||
$cdMark = substr($day[$i], 0, 1);
|
||||
if ($cdMark == 'C') {
|
||||
|
|
|
|||
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';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function toHex(): string
|
||||
{
|
||||
return $this->getHeaderHex() . implode('', $this->controlBytes) . $this->getDataHex();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function getLuhnChecksum(): int
|
||||
{
|
||||
$luhn = 0;
|
||||
|
|
@ -89,9 +83,6 @@ class StartCode extends DataElement
|
|||
return $luhn;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __debugInfo(): ?array
|
||||
{
|
||||
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;
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function getId(): int
|
||||
{
|
||||
return self::ID;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function getName(): string
|
||||
{
|
||||
return 'No PSD2/TANs supported';
|
||||
|
|
@ -33,91 +31,76 @@ final class NoPsd2TanMode implements TanMode
|
|||
return false;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function isDecoupled(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function getChallengeLabel(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function getMaxChallengeLength(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function getMaxTanLength(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function getTanFormat(): int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function needsTanMedium(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function getSmsAbbuchungskontoErforderlich(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function getAuftraggeberkontoErforderlich(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function getChallengeKlasseErforderlich(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function getAntwortHhdUcErforderlich(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function getMaxDecoupledChecks(): int
|
||||
{
|
||||
throw new \RuntimeException('Only allowed for decoupled TAN modes');
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function getFirstDecoupledCheckDelaySeconds(): int
|
||||
{
|
||||
throw new \RuntimeException('Only allowed for decoupled TAN modes');
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function getPeriodicDecoupledCheckDelaySeconds(): int
|
||||
{
|
||||
throw new \RuntimeException('Only allowed for decoupled TAN modes');
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function allowsManualConfirmation(): bool
|
||||
{
|
||||
throw new \RuntimeException('Only allowed for decoupled TAN modes');
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function allowsAutomatedPolling(): bool
|
||||
{
|
||||
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_DEBIT = 'debit';
|
||||
|
||||
/**
|
||||
* @var array of Transaction
|
||||
*/
|
||||
protected $transactions = [];
|
||||
|
||||
/**
|
||||
* @var float
|
||||
*/
|
||||
protected $startBalance = 0.0;
|
||||
|
||||
/**
|
||||
* @var float|null
|
||||
*/
|
||||
protected $endBalance = null;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $creditDebit = null;
|
||||
|
||||
/**
|
||||
* @var \DateTime|null
|
||||
*/
|
||||
protected $date;
|
||||
/** @var Transaction[] */
|
||||
protected array $transactions = [];
|
||||
protected float $startBalance = 0.0;
|
||||
protected ?float $endBalance = null;
|
||||
protected ?string $creditDebit = null;
|
||||
protected ?\DateTime $date = null;
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
* @var Statement[]
|
||||
*/
|
||||
protected $statements = [];
|
||||
/** @var Statement[] */
|
||||
protected array $statements = [];
|
||||
|
||||
/**
|
||||
* Get statements
|
||||
|
|
@ -77,7 +75,7 @@ class StatementOfAccount
|
|||
$statementModel->setStartBalance((float) $statement['start_balance']['amount']);
|
||||
}
|
||||
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'])) {
|
||||
$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_DEBIT = 'debit';
|
||||
|
||||
/**
|
||||
* @var \DateTime|null
|
||||
*/
|
||||
protected $bookingDate;
|
||||
|
||||
/**
|
||||
* @var \DateTime|null
|
||||
*/
|
||||
protected $valutaDate;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
protected ?\DateTime $bookingDate = null;
|
||||
protected ?\DateTime $valutaDate = null;
|
||||
protected float $amount;
|
||||
protected string $creditDebit;
|
||||
protected bool $isStorno;
|
||||
protected string $bookingCode;
|
||||
protected string $bookingText;
|
||||
protected string $description1;
|
||||
protected string $description2;
|
||||
|
||||
/**
|
||||
* Array keys are identifiers like "SVWZ" for the main description.
|
||||
* @var string[]
|
||||
*/
|
||||
protected $structuredDescription;
|
||||
protected array $structuredDescription;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $bankCode;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $accountNumber;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $booked;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $pn;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $textKeyAddition;
|
||||
protected string $bankCode;
|
||||
protected string $accountNumber;
|
||||
protected string $name;
|
||||
protected bool $booked;
|
||||
protected int $pn;
|
||||
protected int $textKeyAddition;
|
||||
|
||||
/**
|
||||
* Get booking date.
|
||||
|
|
@ -121,10 +63,9 @@ class Transaction
|
|||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBookingDate(?\DateTime $date = null)
|
||||
public function setBookingDate(?\DateTime $date = null): static
|
||||
{
|
||||
$this->bookingDate = $date;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -133,10 +74,9 @@ class Transaction
|
|||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setValutaDate(?\DateTime $date = null)
|
||||
public function setValutaDate(?\DateTime $date = null): static
|
||||
{
|
||||
$this->valutaDate = $date;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -153,10 +93,9 @@ class Transaction
|
|||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBooked(bool $booked)
|
||||
public function setBooked(bool $booked): static
|
||||
{
|
||||
$this->booked = $booked;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -165,10 +104,9 @@ class Transaction
|
|||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAmount(float $amount)
|
||||
public function setAmount(float $amount): static
|
||||
{
|
||||
$this->amount = (float) $amount;
|
||||
|
||||
$this->amount = $amount;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -185,10 +123,9 @@ class Transaction
|
|||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setCreditDebit(string $creditDebit)
|
||||
public function setCreditDebit(string $creditDebit): static
|
||||
{
|
||||
$this->creditDebit = $creditDebit;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -205,10 +142,9 @@ class Transaction
|
|||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setIsStorno(bool $isStorno)
|
||||
public function setIsStorno(bool $isStorno): static
|
||||
{
|
||||
$this->isStorno = $isStorno;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -225,10 +161,9 @@ class Transaction
|
|||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBookingCode(string $bookingCode)
|
||||
public function setBookingCode(string $bookingCode): static
|
||||
{
|
||||
$this->bookingCode = (string) $bookingCode;
|
||||
|
||||
$this->bookingCode = $bookingCode;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -245,10 +180,9 @@ class Transaction
|
|||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBookingText(string $bookingText)
|
||||
public function setBookingText(string $bookingText): static
|
||||
{
|
||||
$this->bookingText = (string) $bookingText;
|
||||
|
||||
$this->bookingText = $bookingText;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -265,10 +199,9 @@ class Transaction
|
|||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDescription1(string $description1)
|
||||
public function setDescription1(string $description1): static
|
||||
{
|
||||
$this->description1 = (string) $description1;
|
||||
|
||||
$this->description1 = $description1;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -285,10 +218,9 @@ class Transaction
|
|||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setDescription2(string $description2)
|
||||
public function setDescription2(string $description2): static
|
||||
{
|
||||
$this->description2 = (string) $description2;
|
||||
|
||||
$this->description2 = $description2;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -306,10 +238,9 @@ class Transaction
|
|||
* Set structuredDescription
|
||||
*
|
||||
* @param string[] $structuredDescription
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setStructuredDescription(array $structuredDescription)
|
||||
public function setStructuredDescription(array $structuredDescription): static
|
||||
{
|
||||
$this->structuredDescription = $structuredDescription;
|
||||
|
||||
|
|
@ -353,10 +284,9 @@ class Transaction
|
|||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setBankCode(string $bankCode)
|
||||
public function setBankCode(string $bankCode): static
|
||||
{
|
||||
$this->bankCode = (string) $bankCode;
|
||||
|
||||
$this->bankCode = $bankCode;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -373,10 +303,9 @@ class Transaction
|
|||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAccountNumber(string $accountNumber)
|
||||
public function setAccountNumber(string $accountNumber): static
|
||||
{
|
||||
$this->accountNumber = (string) $accountNumber;
|
||||
|
||||
$this->accountNumber = $accountNumber;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -401,10 +330,9 @@ class Transaction
|
|||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setName(string $name)
|
||||
public function setName(string $name): static
|
||||
{
|
||||
$this->name = (string) $name;
|
||||
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
|
@ -422,7 +350,7 @@ class Transaction
|
|||
* @param int|mixed $nr Will be parsed to an int.
|
||||
* @return $this
|
||||
*/
|
||||
public function setPN($nr)
|
||||
public function setPN($nr): static
|
||||
{
|
||||
$this->pn = intval($nr);
|
||||
return $this;
|
||||
|
|
@ -442,7 +370,7 @@ class Transaction
|
|||
* @param int|mixed $textKeyAddition Will be parsed to an int.
|
||||
* @return $this
|
||||
*/
|
||||
public function setTextKeyAddition($textKeyAddition)
|
||||
public function setTextKeyAddition($textKeyAddition): static
|
||||
{
|
||||
$this->textKeyAddition = intval($textKeyAddition);
|
||||
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\UnexpectedResponseException;
|
||||
use Fhp\Protocol\UPD;
|
||||
use Fhp\Segment\BaseSegment;
|
||||
use Fhp\Segment\HIRMS\Rueckmeldungscode;
|
||||
use Fhp\Segment\Paginateable;
|
||||
|
||||
|
|
@ -19,23 +18,20 @@ use Fhp\Segment\Paginateable;
|
|||
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
|
||||
* 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
|
||||
* 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
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
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
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
|
|
@ -82,10 +76,9 @@ abstract class PaginateableAction extends BaseAction
|
|||
return !$this->isDone() && $this->paginationToken !== null;
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function processResponse(Message $response)
|
||||
{
|
||||
if (($pagination = $response->findRueckmeldung(Rueckmeldungscode::PAGINATION)) !== null) {
|
||||
if (($pagination = $response->findRueckmeldung(Rueckmeldungscode::AUFSETZPUNKT)) !== null) {
|
||||
if (count($pagination->rueckmeldungsparameter) !== 1) {
|
||||
throw new UnexpectedResponseException("Unexpected pagination request: $pagination");
|
||||
}
|
||||
|
|
@ -97,7 +90,6 @@ abstract class PaginateableAction extends BaseAction
|
|||
}
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function getNextRequest(?BPD $bpd, ?UPD $upd)
|
||||
{
|
||||
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\SegmentInterface;
|
||||
use Fhp\Segment\TAN\HITANS;
|
||||
use Fhp\Segment\VPP\HIVPPSv1;
|
||||
|
||||
/**
|
||||
* Segmentfolge: Bankparameterdaten (Version 3)
|
||||
|
|
@ -152,6 +153,28 @@ class BPD
|
|||
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.
|
||||
*/
|
||||
|
|
|
|||
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->kundensystemId,
|
||||
$this->messageNumber,
|
||||
$this->dialogId
|
||||
$this->dialogId,
|
||||
) = $serialized;
|
||||
|
||||
is_array($parentSerialized) ?
|
||||
|
|
@ -151,7 +151,6 @@ class DialogInitialization extends BaseAction
|
|||
parent::unserialize($parentSerialized);
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||
{
|
||||
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 */
|
||||
private $tanMedia;
|
||||
|
||||
/** {@inheritdoc} */
|
||||
protected function createRequest(BPD $bpd, ?UPD $upd)
|
||||
{
|
||||
// Prepare the HKTAB request.
|
||||
|
|
@ -32,7 +31,6 @@ class GetTanMedia extends BaseAction
|
|||
}
|
||||
}
|
||||
|
||||
/** {@inheritdoc} */
|
||||
public function processResponse(Message $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 $requestSegmentNumber If set, only consider Rueckmeldungen that pertain to this request segment.
|
||||
* @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) {
|
||||
if ($segment instanceof RueckmeldungContainer) {
|
||||
if (
|
||||
$segment instanceof RueckmeldungContainer && (
|
||||
$requestSegmentNumber === null || $segment->segmentkopf->bezugselement === $requestSegmentNumber
|
||||
)
|
||||
) {
|
||||
$rueckmeldung = $segment->findRueckmeldung($code);
|
||||
if ($rueckmeldung !== null) {
|
||||
return $rueckmeldung;
|
||||
|
|
@ -217,16 +222,29 @@ class Message
|
|||
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.
|
||||
*/
|
||||
public function serialize(): string
|
||||
{
|
||||
$result = '';
|
||||
foreach ($this->wrapperSegments as $segment) {
|
||||
$result .= Serializer::serializeSegment($segment);
|
||||
}
|
||||
return $result;
|
||||
return Serializer::serializeSegments($this->wrapperSegments);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -300,14 +318,16 @@ class Message
|
|||
$segments = Parser::parseSegments($rawMessage);
|
||||
|
||||
// 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->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.
|
||||
// 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.
|
||||
* @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) {
|
||||
$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
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
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