diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dd45a0..92ff42e 100755 --- a/CHANGELOG.md +++ b/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 diff --git a/CLAUDE.md b/CLAUDE.md index aa43855..48a50e4 100755 --- a/CLAUDE.md +++ b/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' } } ``` diff --git a/class/fints.class.php b/class/fints.class.php index 6d3822b..b6a89c8 100755 --- a/class/fints.class.php +++ b/class/fints.class.php @@ -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; + } } diff --git a/composer.json b/composer.json index d77bfa8..85f0bb9 100755 --- a/composer.json +++ b/composer.json @@ -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": "*" diff --git a/composer.lock b/composer.lock index 4f0aff3..ca4143e 100755 --- a/composer.lock +++ b/composer.lock @@ -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": [], diff --git a/pdfstatements.php b/pdfstatements.php index 4a5084c..b7c7c30 100755 --- a/pdfstatements.php +++ b/pdfstatements.php @@ -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 diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index 88c07eb..7970181 100755 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -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" } diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index 31e768d..1055767 100755 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -1,9 +1,9 @@ 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(), diff --git a/vendor/composer/platform_check.php b/vendor/composer/platform_check.php index a70ba47..af033b9 100755 --- a/vendor/composer/platform_check.php +++ b/vendor/composer/platform_check.php @@ -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) { diff --git a/vendor/nemiah/php-fints/.github/workflows/tests.yml b/vendor/nemiah/php-fints/.github/workflows/tests.yml new file mode 100644 index 0000000..228d6d5 --- /dev/null +++ b/vendor/nemiah/php-fints/.github/workflows/tests.yml @@ -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 diff --git a/vendor/nemiah/php-fints/.gitignore b/vendor/nemiah/php-fints/.gitignore new file mode 100644 index 0000000..ebd1a7a --- /dev/null +++ b/vendor/nemiah/php-fints/.gitignore @@ -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 \ No newline at end of file diff --git a/vendor/nemiah/php-fints/.php-cs-fixer.php b/vendor/nemiah/php-fints/.php-cs-fixer.php old mode 100755 new mode 100644 index 9eb8056..9171a9a --- a/vendor/nemiah/php-fints/.php-cs-fixer.php +++ b/vendor/nemiah/php-fints/.php-cs-fixer.php @@ -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 ` 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 ` 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); diff --git a/vendor/nemiah/php-fints/.travis.yml b/vendor/nemiah/php-fints/.travis.yml deleted file mode 100755 index 1db343e..0000000 --- a/vendor/nemiah/php-fints/.travis.yml +++ /dev/null @@ -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' diff --git a/vendor/nemiah/php-fints/DEVELOPER-GUIDE.md b/vendor/nemiah/php-fints/DEVELOPER-GUIDE.md old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/LICENSE b/vendor/nemiah/php-fints/LICENSE old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/README.md b/vendor/nemiah/php-fints/README.md old mode 100755 new mode 100644 index c14ea9d..84c3e1d --- a/vendor/nemiah/php-fints/README.md +++ b/vendor/nemiah/php-fints/README.md @@ -1,6 +1,6 @@ # PHP FinTS/HBCI library -[![Build Status](https://travis-ci.org/nemiah/phpFinTS.svg?branch=master)](https://travis-ci.org/nemiah/phpFinTS) +[![CI status](https://github.com/nemiah/phpFinTS/actions/workflows/tests.yml/badge.svg)](https://github.com/nemiah/phpFinTS/actions/workflows/tests.yml) A PHP library implementing the following functions of the FinTS/HBCI protocol: diff --git a/vendor/nemiah/php-fints/Samples/accounts.php b/vendor/nemiah/php-fints/Samples/accounts.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/Samples/balance.php b/vendor/nemiah/php-fints/Samples/balance.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/Samples/bpd.php b/vendor/nemiah/php-fints/Samples/bpd.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/Samples/browser.php b/vendor/nemiah/php-fints/Samples/browser.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/Samples/directDebit_Sephpa.php b/vendor/nemiah/php-fints/Samples/directDebit_Sephpa.php old mode 100755 new mode 100644 index a3c076d..171d0fc --- a/vendor/nemiah/php-fints/Samples/directDebit_Sephpa.php +++ b/vendor/nemiah/php-fints/Samples/directDebit_Sephpa.php @@ -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(); diff --git a/vendor/nemiah/php-fints/Samples/directDebit_phpSepaXml.php b/vendor/nemiah/php-fints/Samples/directDebit_phpSepaXml.php old mode 100755 new mode 100644 index 2748592..aaa41bc --- a/vendor/nemiah/php-fints/Samples/directDebit_phpSepaXml.php +++ b/vendor/nemiah/php-fints/Samples/directDebit_phpSepaXml.php @@ -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(); diff --git a/vendor/nemiah/php-fints/Samples/init.php b/vendor/nemiah/php-fints/Samples/init.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/Samples/login.php b/vendor/nemiah/php-fints/Samples/login.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/Samples/statementOfAccount.php b/vendor/nemiah/php-fints/Samples/statementOfAccount.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/Samples/statementOfHoldings.php b/vendor/nemiah/php-fints/Samples/statementOfHoldings.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/Samples/tanModesAndMedia.php b/vendor/nemiah/php-fints/Samples/tanModesAndMedia.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/Samples/transfer.php b/vendor/nemiah/php-fints/Samples/transfer.php old mode 100755 new mode 100644 index 083d8e6..6aae181 --- a/vendor/nemiah/php-fints/Samples/transfer.php +++ b/vendor/nemiah/php-fints/Samples/transfer.php @@ -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(); diff --git a/vendor/nemiah/php-fints/Samples/vop.php b/vendor/nemiah/php-fints/Samples/vop.php new file mode 100644 index 0000000..2864e5c --- /dev/null +++ b/vendor/nemiah/php-fints/Samples/vop.php @@ -0,0 +1,138 @@ +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. +} diff --git a/vendor/nemiah/php-fints/composer.json b/vendor/nemiah/php-fints/composer.json old mode 100755 new mode 100644 index 0da3b32..a1863bd --- a/vendor/nemiah/php-fints/composer.json +++ b/vendor/nemiah/php-fints/composer.json @@ -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": "*" diff --git a/vendor/nemiah/php-fints/csfixer-check.sh b/vendor/nemiah/php-fints/csfixer-check.sh deleted file mode 100755 index 9c76ae3..0000000 --- a/vendor/nemiah/php-fints/csfixer-check.sh +++ /dev/null @@ -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) \ No newline at end of file diff --git a/vendor/nemiah/php-fints/disallowtabs.sh b/vendor/nemiah/php-fints/disallowtabs.sh deleted file mode 100755 index 3d91702..0000000 --- a/vendor/nemiah/php-fints/disallowtabs.sh +++ /dev/null @@ -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 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Action/GetBalance.php b/vendor/nemiah/php-fints/lib/Fhp/Action/GetBalance.php old mode 100755 new mode 100644 index 00c053f..00d8f81 --- a/vendor/nemiah/php-fints/lib/Fhp/Action/GetBalance.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Action/GetBalance.php @@ -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); diff --git a/vendor/nemiah/php-fints/lib/Fhp/Action/GetDepotAufstellung.php b/vendor/nemiah/php-fints/lib/Fhp/Action/GetDepotAufstellung.php old mode 100755 new mode 100644 index 3f32987..17e644e --- a/vendor/nemiah/php-fints/lib/Fhp/Action/GetDepotAufstellung.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Action/GetDepotAufstellung.php @@ -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); diff --git a/vendor/nemiah/php-fints/lib/Fhp/Action/GetElectronicStatement.php b/vendor/nemiah/php-fints/lib/Fhp/Action/GetElectronicStatement.php new file mode 100644 index 0000000..bdc6b44 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Action/GetElectronicStatement.php @@ -0,0 +1,178 @@ +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, + ]; + } + } + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Action/GetSEPAAccounts.php b/vendor/nemiah/php-fints/lib/Fhp/Action/GetSEPAAccounts.php old mode 100755 new mode 100644 index 92e876d..1101075 --- a/vendor/nemiah/php-fints/lib/Fhp/Action/GetSEPAAccounts.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Action/GetSEPAAccounts.php @@ -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); diff --git a/vendor/nemiah/php-fints/lib/Fhp/Action/GetSEPADirectDebitParameters.php b/vendor/nemiah/php-fints/lib/Fhp/Action/GetSEPADirectDebitParameters.php old mode 100755 new mode 100644 index 5530317..80b8767 --- a/vendor/nemiah/php-fints/lib/Fhp/Action/GetSEPADirectDebitParameters.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Action/GetSEPADirectDebitParameters.php @@ -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)); diff --git a/vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementFromArchive.php b/vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementFromArchive.php new file mode 100644 index 0000000..5f36078 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementFromArchive.php @@ -0,0 +1,194 @@ +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, + ]; + } + } + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementOfAccount.php b/vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementOfAccount.php old mode 100755 new mode 100644 index 8529ec5..8f623ec --- a/vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementOfAccount.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementOfAccount.php @@ -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); diff --git a/vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementOfAccountXML.php b/vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementOfAccountXML.php old mode 100755 new mode 100644 index 71d20cb..f4ee1a5 --- a/vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementOfAccountXML.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementOfAccountXML.php @@ -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); diff --git a/vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementPDF.php b/vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementPDF.php deleted file mode 100644 index 81427a2..0000000 --- a/vendor/nemiah/php-fints/lib/Fhp/Action/GetStatementPDF.php +++ /dev/null @@ -1,182 +0,0 @@ -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, - ]; - } - } - } -} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Action/SendInternationalCreditTransfer.php b/vendor/nemiah/php-fints/lib/Fhp/Action/SendInternationalCreditTransfer.php old mode 100755 new mode 100644 index 2634f24..73416fc --- a/vendor/nemiah/php-fints/lib/Fhp/Action/SendInternationalCreditTransfer.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Action/SendInternationalCreditTransfer.php @@ -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 */ diff --git a/vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPADirectDebit.php b/vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPADirectDebit.php old mode 100755 new mode 100644 index 1c9fe59..0976ed4 --- a/vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPADirectDebit.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPADirectDebit.php @@ -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="(?[^"]+)"/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; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPARealtimeTransfer.php b/vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPARealtimeTransfer.php old mode 100755 new mode 100644 index 22dfda3..c3bd960 --- a/vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPARealtimeTransfer.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPARealtimeTransfer.php @@ -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'); } } diff --git a/vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPATransfer.php b/vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPATransfer.php old mode 100755 new mode 100644 index 68de23b..a7ce104 --- a/vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPATransfer.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Action/SendSEPATransfer.php @@ -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); diff --git a/vendor/nemiah/php-fints/lib/Fhp/BaseAction.php b/vendor/nemiah/php-fints/lib/Fhp/BaseAction.php old mode 100755 new mode 100644 index d36dec6..735b390 --- a/vendor/nemiah/php-fints/lib/Fhp/BaseAction.php +++ b/vendor/nemiah/php-fints/lib/Fhp/BaseAction.php @@ -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; + } } diff --git a/vendor/nemiah/php-fints/lib/Fhp/Connection.php b/vendor/nemiah/php-fints/lib/Fhp/Connection.php old mode 100755 new mode 100644 index 5b2981d..c461473 --- a/vendor/nemiah/php-fints/lib/Fhp/Connection.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Connection.php @@ -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), diff --git a/vendor/nemiah/php-fints/lib/Fhp/CurlException.php b/vendor/nemiah/php-fints/lib/Fhp/CurlException.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/FinTs.php b/vendor/nemiah/php-fints/lib/Fhp/FinTs.php old mode 100755 new mode 100644 index a124c27..24f1b6b --- a/vendor/nemiah/php-fints/lib/Fhp/FinTs.php +++ b/vendor/nemiah/php-fints/lib/Fhp/FinTs.php @@ -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 diff --git a/vendor/nemiah/php-fints/lib/Fhp/MT535/MT535.php b/vendor/nemiah/php-fints/lib/Fhp/MT535/MT535.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/MT940/Dialect/PostbankMT940.php b/vendor/nemiah/php-fints/lib/Fhp/MT940/Dialect/PostbankMT940.php old mode 100755 new mode 100644 index b7d1e91..826c16f --- a/vendor/nemiah/php-fints/lib/Fhp/MT940/Dialect/PostbankMT940.php +++ b/vendor/nemiah/php-fints/lib/Fhp/MT940/Dialect/PostbankMT940.php @@ -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 diff --git a/vendor/nemiah/php-fints/lib/Fhp/MT940/Dialect/SpardaMT940.php b/vendor/nemiah/php-fints/lib/Fhp/MT940/Dialect/SpardaMT940.php old mode 100755 new mode 100644 index f1f70f4..24b873b --- a/vendor/nemiah/php-fints/lib/Fhp/MT940/Dialect/SpardaMT940.php +++ b/vendor/nemiah/php-fints/lib/Fhp/MT940/Dialect/SpardaMT940.php @@ -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 = []; diff --git a/vendor/nemiah/php-fints/lib/Fhp/MT940/MT940.php b/vendor/nemiah/php-fints/lib/Fhp/MT940/MT940.php old mode 100755 new mode 100644 index 32c4b03..9bf24f7 --- a/vendor/nemiah/php-fints/lib/Fhp/MT940/MT940.php +++ b/vendor/nemiah/php-fints/lib/Fhp/MT940/MT940.php @@ -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') { diff --git a/vendor/nemiah/php-fints/lib/Fhp/MT940/MT940Exception.php b/vendor/nemiah/php-fints/lib/Fhp/MT940/MT940Exception.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/Account.php b/vendor/nemiah/php-fints/lib/Fhp/Model/Account.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/DataElement.php b/vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/DataElement.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/StartCode.php b/vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/StartCode.php old mode 100755 new mode 100644 index faa0893..bcce438 --- a/vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/StartCode.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/StartCode.php @@ -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 [ diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/SvgRenderer.php b/vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/SvgRenderer.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/TanRequestChallengeFlicker.php b/vendor/nemiah/php-fints/lib/Fhp/Model/FlickerTan/TanRequestChallengeFlicker.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/NoPsd2TanMode.php b/vendor/nemiah/php-fints/lib/Fhp/Model/NoPsd2TanMode.php old mode 100755 new mode 100644 index 223722f..c6ab6f6 --- a/vendor/nemiah/php-fints/lib/Fhp/Model/NoPsd2TanMode.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Model/NoPsd2TanMode.php @@ -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'); diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/PollingInfo.php b/vendor/nemiah/php-fints/lib/Fhp/Model/PollingInfo.php new file mode 100644 index 0000000..68ff71f --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Model/PollingInfo.php @@ -0,0 +1,23 @@ +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']); diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfAccount/Transaction.php b/vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfAccount/Transaction.php old mode 100755 new mode 100644 index 1483a30..af3151f --- a/vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfAccount/Transaction.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfAccount/Transaction.php @@ -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; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfHoldings/Holding.php b/vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfHoldings/Holding.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfHoldings/StatementOfHoldings.php b/vendor/nemiah/php-fints/lib/Fhp/Model/StatementOfHoldings/StatementOfHoldings.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/TanMedium.php b/vendor/nemiah/php-fints/lib/Fhp/Model/TanMedium.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/TanMode.php b/vendor/nemiah/php-fints/lib/Fhp/Model/TanMode.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/TanRequest.php b/vendor/nemiah/php-fints/lib/Fhp/Model/TanRequest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/TanRequestChallengeImage.php b/vendor/nemiah/php-fints/lib/Fhp/Model/TanRequestChallengeImage.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/VopConfirmationRequest.php b/vendor/nemiah/php-fints/lib/Fhp/Model/VopConfirmationRequest.php new file mode 100644 index 0000000..af2e9ca --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Model/VopConfirmationRequest.php @@ -0,0 +1,25 @@ +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; + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/VopPollingInfo.php b/vendor/nemiah/php-fints/lib/Fhp/Model/VopPollingInfo.php new file mode 100644 index 0000000..903b345 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Model/VopPollingInfo.php @@ -0,0 +1,50 @@ +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...'; + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Model/VopVerificationResult.php b/vendor/nemiah/php-fints/lib/Fhp/Model/VopVerificationResult.php new file mode 100644 index 0000000..f29f569 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Model/VopVerificationResult.php @@ -0,0 +1,51 @@ + 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"), + }; + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Options/Credentials.php b/vendor/nemiah/php-fints/lib/Fhp/Options/Credentials.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Options/FinTsOptions.php b/vendor/nemiah/php-fints/lib/Fhp/Options/FinTsOptions.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Options/SanitizingLogger.php b/vendor/nemiah/php-fints/lib/Fhp/Options/SanitizingLogger.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/PaginateableAction.php b/vendor/nemiah/php-fints/lib/Fhp/PaginateableAction.php old mode 100755 new mode 100644 index b01d480..7144f30 --- a/vendor/nemiah/php-fints/lib/Fhp/PaginateableAction.php +++ b/vendor/nemiah/php-fints/lib/Fhp/PaginateableAction.php @@ -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) { diff --git a/vendor/nemiah/php-fints/lib/Fhp/Protocol/ActionIncompleteException.php b/vendor/nemiah/php-fints/lib/Fhp/Protocol/ActionIncompleteException.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Protocol/ActionPendingException.php b/vendor/nemiah/php-fints/lib/Fhp/Protocol/ActionPendingException.php new file mode 100644 index 0000000..9424dc1 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Protocol/ActionPendingException.php @@ -0,0 +1,26 @@ +pollingInfo = $pollingInfo; + } + + public function getPollingInfo(): PollingInfo + { + return $this->pollingInfo; + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Protocol/BPD.php b/vendor/nemiah/php-fints/lib/Fhp/Protocol/BPD.php old mode 100755 new mode 100644 index de8caf4..5241ab4 --- a/vendor/nemiah/php-fints/lib/Fhp/Protocol/BPD.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Protocol/BPD.php @@ -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. */ diff --git a/vendor/nemiah/php-fints/lib/Fhp/Protocol/DialogInitialization.php b/vendor/nemiah/php-fints/lib/Fhp/Protocol/DialogInitialization.php old mode 100755 new mode 100644 index 3e07aec..f31fdf9 --- a/vendor/nemiah/php-fints/lib/Fhp/Protocol/DialogInitialization.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Protocol/DialogInitialization.php @@ -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.'); diff --git a/vendor/nemiah/php-fints/lib/Fhp/Protocol/GetTanMedia.php b/vendor/nemiah/php-fints/lib/Fhp/Protocol/GetTanMedia.php old mode 100755 new mode 100644 index da0f32f..4bb2a75 --- a/vendor/nemiah/php-fints/lib/Fhp/Protocol/GetTanMedia.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Protocol/GetTanMedia.php @@ -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); diff --git a/vendor/nemiah/php-fints/lib/Fhp/Protocol/Message.php b/vendor/nemiah/php-fints/lib/Fhp/Protocol/Message.php old mode 100755 new mode 100644 index 6d18b75..b4babcf --- a/vendor/nemiah/php-fints/lib/Fhp/Protocol/Message.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Protocol/Message.php @@ -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; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Protocol/MessageBuilder.php b/vendor/nemiah/php-fints/lib/Fhp/Protocol/MessageBuilder.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Protocol/ServerException.php b/vendor/nemiah/php-fints/lib/Fhp/Protocol/ServerException.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Protocol/TanRequiredException.php b/vendor/nemiah/php-fints/lib/Fhp/Protocol/TanRequiredException.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Protocol/UPD.php b/vendor/nemiah/php-fints/lib/Fhp/Protocol/UPD.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Protocol/UnexpectedResponseException.php b/vendor/nemiah/php-fints/lib/Fhp/Protocol/UnexpectedResponseException.php old mode 100755 new mode 100644 index daea608..02b183c --- a/vendor/nemiah/php-fints/lib/Fhp/Protocol/UnexpectedResponseException.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Protocol/UnexpectedResponseException.php @@ -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); } diff --git a/vendor/nemiah/php-fints/lib/Fhp/Protocol/VopConfirmationRequiredException.php b/vendor/nemiah/php-fints/lib/Fhp/Protocol/VopConfirmationRequiredException.php new file mode 100644 index 0000000..03ec77b --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Protocol/VopConfirmationRequiredException.php @@ -0,0 +1,26 @@ +vopConfirmationRequest = $vopConfirmationRequest; + } + + public function getVopConfirmationRequest(): VopConfirmationRequest + { + return $this->vopConfirmationRequest; + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/AUB/HIAUBSv9.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/AUB/HIAUBSv9.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/AUB/HKAUBv9.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/AUB/HKAUBv9.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/AUB/ParameterAuslandsueberweisungV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/AUB/ParameterAuslandsueberweisungV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/AnonymousSegment.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/AnonymousSegment.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BME/HIBMESv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BME/HIBMESv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BME/HIBMESv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BME/HIBMESv2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BME/HKBMEv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BME/HKBMEv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BME/HKBMEv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BME/HKBMEv2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BME/ParameterTerminierteSEPAFirmenSammellastschriftEinreichenV1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BME/ParameterTerminierteSEPAFirmenSammellastschriftEinreichenV1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BME/ParameterTerminierteSEPAFirmenSammellastschriftEinreichenV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BME/ParameterTerminierteSEPAFirmenSammellastschriftEinreichenV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BSE/HIBSESv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BSE/HIBSESv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BSE/HIBSESv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BSE/HIBSESv2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BSE/HKBSEv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BSE/HKBSEv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BSE/HKBSEv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BSE/HKBSEv2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BSE/ParameterTerminierteSEPAFirmenEinzellastschriftEinreichenV1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BSE/ParameterTerminierteSEPAFirmenEinzellastschriftEinreichenV1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BSE/ParameterTerminierteSEPAFirmenEinzellastschriftEinreichenV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BSE/ParameterTerminierteSEPAFirmenEinzellastschriftEinreichenV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BaseDeg.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BaseDeg.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BaseDescriptor.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BaseDescriptor.php old mode 100755 new mode 100644 index 1234721..b7db851 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/BaseDescriptor.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/BaseDescriptor.php @@ -32,9 +32,11 @@ abstract class BaseDescriptor protected function __construct(\ReflectionClass $clazz) { // Use reflection to map PHP class fields to elements in the segment/Deg. - $implicitIndex = true; $nextIndex = 0; foreach (static::enumerateProperties($clazz) as $property) { + if ($nextIndex === null) { + throw new \InvalidArgumentException("Disallowed property $property after an @Unlimited field"); + } $docComment = $property->getDocComment() ?: ''; if (static::getBoolAnnotation('Ignore', $docComment)) { continue; // Skip @Ignore-d propeties. @@ -44,22 +46,35 @@ abstract class BaseDescriptor $descriptor = new ElementDescriptor(); $descriptor->field = $property->getName(); $maxCount = static::getIntAnnotation('Max', $docComment); + $unlimitedCount = static::getBoolAnnotation('Unlimited', $docComment); if ($type = static::getVarAnnotation($docComment)) { if (str_ends_with($type, '|null')) { // Nullable field $descriptor->optional = true; $type = substr($type, 0, -5); } if (str_ends_with($type, '[]')) { // Array/repeated field - if ($maxCount === null) { - throw new \InvalidArgumentException("Repeated property $property needs @Max() annotation"); - } - $descriptor->repeated = $maxCount; $type = substr($type, 0, -2); - // If a repeated field is followed by anything at all, there will be an empty entry for each possible - // repeated value (in extreme cases, there can be hundreds of consecutive `+`, for instance). - $nextIndex += $maxCount; + if ($unlimitedCount) { + $descriptor->repeated = PHP_INT_MAX; + // A repeated field of unlimited size cannot be followed by anything, because it would not be + // clear which of the following values still belong to the repeated field vs to the next field. + $nextIndex = null; + } elseif ($maxCount !== null) { + $descriptor->repeated = $maxCount; + // If there's another field value after this repeated field, then a serialized message will + // contain placeholders (i.e. empty field values separated by possibly hundreds of `+`) to fill + // up to the repeated field's maximum length, after which the next message continues at the next + // index. + $nextIndex += $maxCount; + } else { + throw new \InvalidArgumentException( + "Repeated property $property needs @Max(.) or (rarely) @Unlimited annotation" + ); + } } elseif ($maxCount !== null) { throw new \InvalidArgumentException("@Max() annotation not recognized on single $property"); + } elseif ($unlimitedCount) { + throw new \InvalidArgumentException("@Unlimited annotation not recognized on single $property"); } else { ++$nextIndex; // Singular field, so the index advances by 1. } @@ -90,7 +105,7 @@ abstract class BaseDescriptor throw new \InvalidArgumentException("No fields found in $clazz->name"); } ksort($this->elements); // Make sure elements are parsed in wire-format order. - $this->maxIndex = $nextIndex - 1; + $this->maxIndex = $nextIndex === null ? PHP_INT_MAX : $nextIndex - 1; } /** diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BaseGeschaeftsvorfallparameter.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BaseGeschaeftsvorfallparameter.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BaseGeschaeftsvorfallparameterOld.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BaseGeschaeftsvorfallparameterOld.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/BaseSegment.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/BaseSegment.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CAZ/GebuchteCamtUmsaetze.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CAZ/GebuchteCamtUmsaetze.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CAZ/HICAZSv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CAZ/HICAZSv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CAZ/HICAZv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CAZ/HICAZv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CAZ/HKCAZv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CAZ/HKCAZv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CAZ/ParameterKontoumsaetzeCamt.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CAZ/ParameterKontoumsaetzeCamt.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CAZ/UnterstuetzteCamtMessages.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CAZ/UnterstuetzteCamtMessages.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CCM/HICCMSv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CCM/HICCMSv1.php old mode 100755 new mode 100644 index f3d23be..3b2c460 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/CCM/HICCMSv1.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/CCM/HICCMSv1.php @@ -14,7 +14,7 @@ class HICCMSv1 extends BaseGeschaeftsvorfallparameter { public ParameterSEPASammelueberweisungV1 $parameter; - public function getParameter() + public function getParameter(): ParameterSEPASammelueberweisungV1 { return $this->parameter; } diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CCM/HKCCMv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CCM/HKCCMv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CCM/ParameterSEPASammelueberweisungV1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CCM/ParameterSEPASammelueberweisungV1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CCS/HICCSSv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CCS/HICCSSv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CCS/HKCCSv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CCS/HKCCSv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CME/HICMESv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CME/HICMESv1.php old mode 100755 new mode 100644 index 833d18b..582afd0 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/CME/HICMESv1.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/CME/HICMESv1.php @@ -13,4 +13,9 @@ use Fhp\Segment\BaseGeschaeftsvorfallparameter; class HICMESv1 extends BaseGeschaeftsvorfallparameter { public ParameterTerminierteSEPASammelueberweisungEinreichenV1 $parameter; + + public function getParameter(): ParameterTerminierteSEPASammelueberweisungEinreichenV1 + { + return $this->parameter; + } } diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CME/HICMEv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CME/HICMEv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CME/HKCMEv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CME/HKCMEv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CME/ParameterTerminierteSEPASammelueberweisungEinreichenV1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CME/ParameterTerminierteSEPASammelueberweisungEinreichenV1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CSE/HICSESv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CSE/HICSESv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CSE/HICSEv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CSE/HICSEv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CSE/HKCSEv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CSE/HKCSEv1.php old mode 100755 new mode 100644 index 5861cde..515e3a3 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/CSE/HKCSEv1.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/CSE/HKCSEv1.php @@ -17,7 +17,7 @@ class HKCSEv1 extends BaseSegment public \Fhp\Segment\Common\Kti $kontoverbindungInternational; /** Max length: 256 */ public string $sepaDescriptor; - /** + /** * The PAIN message in XML format. * HISPAS informs which XML schemas are allowed. * The field must be 1999-01-01. diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/CSE/ParameterTerminierteSEPAUeberweisungEinreichenV1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/CSE/ParameterTerminierteSEPAUeberweisungEinreichenV1.php old mode 100755 new mode 100644 index 905aff9..1058223 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/CSE/ParameterTerminierteSEPAUeberweisungEinreichenV1.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/CSE/ParameterTerminierteSEPAUeberweisungEinreichenV1.php @@ -9,5 +9,4 @@ class ParameterTerminierteSEPAUeberweisungEinreichenV1 extends BaseDeg /** Must be => 1 */ public int $minimaleVorlaufzeit; public int $maximaleVorlaufzeit; - } diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/AccountInfo.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/AccountInfo.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Btg.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Btg.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Kik.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Kik.php old mode 100755 new mode 100644 index 8b8f177..2caa640 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Kik.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Kik.php @@ -19,7 +19,6 @@ class Kik extends BaseDeg /** Max length: 30 (Mandatory/absent depending on the country) */ public ?string $kreditinstitutscode = null; - /** {@inheritdoc} */ public function validate() { parent::validate(); diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Kti.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Kti.php old mode 100755 new mode 100644 index 9c47a71..bd10de7 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Kti.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Kti.php @@ -26,7 +26,6 @@ class Kti extends BaseDeg implements AccountInfo public ?string $unterkontomerkmal = null; public ?Kik $kreditinstitutskennung = null; - /** {@inheritdoc} */ public function validate() { parent::validate(); @@ -58,13 +57,11 @@ class Kti extends BaseDeg implements AccountInfo return $result; } - /** {@inheritdoc} */ public function getAccountNumber(): string { return $this->iban ?? $this->kontonummer; } - /** {@inheritdoc} */ public function getBankIdentifier(): ?string { return $this->bic ?? $this->kreditinstitutskennung->kreditinstitutscode; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Kto.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Kto.php old mode 100755 new mode 100644 index 1671816..46436e3 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Kto.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Kto.php @@ -31,13 +31,11 @@ class Kto extends BaseDeg implements AccountInfo return static::create($account->getAccountNumber(), Kik::create($account->getBlz())); } - /** {@inheritdoc} */ public function getAccountNumber(): string { return $this->kontonummer; } - /** {@inheritdoc} */ public function getBankIdentifier(): ?string { return $this->kik->kreditinstitutscode; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/KtvV3.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/KtvV3.php old mode 100755 new mode 100644 index 194ad43..b6144ac --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/KtvV3.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/KtvV3.php @@ -37,13 +37,11 @@ class KtvV3 extends BaseDeg implements AccountInfo return static::create($account->getAccountNumber(), $account->getSubAccount(), Kik::create($account->getBlz())); } - /** {@inheritdoc} */ public function getAccountNumber(): string { return $this->kontonummer ?: ''; } - /** {@inheritdoc} */ public function getBankIdentifier(): ?string { return $this->kik->kreditinstitutscode; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Ktz.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Ktz.php old mode 100755 new mode 100644 index b5ee4d8..34b9592 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Ktz.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Ktz.php @@ -24,13 +24,11 @@ class Ktz extends BaseDeg implements AccountInfo public ?string $unterkontomerkmal = null; public Kik $kreditinstitutskennung; - /** {@inheritdoc} */ public function getAccountNumber(): string { return $this->iban ?? $this->kontonummer; } - /** {@inheritdoc} */ public function getBankIdentifier(): ?string { return $this->bic ?? $this->kreditinstitutskennung->kreditinstitutscode; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Kursqualitaet.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Kursqualitaet.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Sdo.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Sdo.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Tsp.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/Common/Tsp.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/DME/HIDMESv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/DME/HIDMESv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/DME/HIDMESv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/DME/HIDMESv2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/DME/HKDMEv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/DME/HKDMEv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/DME/HKDMEv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/DME/HKDMEv2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/DME/ParameterTerminierteSEPASammellastschriftEinreichenV1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/DME/ParameterTerminierteSEPASammellastschriftEinreichenV1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/DME/ParameterTerminierteSEPASammellastschriftEinreichenV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/DME/ParameterTerminierteSEPASammellastschriftEinreichenV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/HIDSESv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/HIDSESv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/HIDSESv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/HIDSESv2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/HIDXES.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/HIDXES.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/HKDSEv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/HKDSEv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/HKDSEv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/HKDSEv2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/MinimaleVorlaufzeitSEPALastschrift.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/MinimaleVorlaufzeitSEPALastschrift.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/ParameterTerminierteSEPAEinzellastschriftEinreichenV1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/ParameterTerminierteSEPAEinzellastschriftEinreichenV1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/ParameterTerminierteSEPAEinzellastschriftEinreichenV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/ParameterTerminierteSEPAEinzellastschriftEinreichenV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/SEPADirectDebitMinimalLeadTimeProvider.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/DSE/SEPADirectDebitMinimalLeadTimeProvider.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/DegDescriptor.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/DegDescriptor.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/EKA/HIEKA.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/EKA/HIEKA.php new file mode 100644 index 0000000..b3099f1 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/EKA/HIEKA.php @@ -0,0 +1,49 @@ +parameter; + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/EKA/HIEKAv5.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/EKA/HIEKAv5.php new file mode 100644 index 0000000..ea04536 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/EKA/HIEKAv5.php @@ -0,0 +1,90 @@ +kontoauszug ?? ''; + } + + /** {@inheritDoc} */ + public function getFormat(): ?int + { + return $this->format; + } + + /** {@inheritDoc} */ + public function getIban(): ?string + { + return $this->iban; + } + + /** {@inheritDoc} */ + public function getStatementNumber(): ?int + { + return $this->kontoauszugsnummer; + } + + /** {@inheritDoc} */ + public function getStatementYear(): ?int + { + return $this->kontoauszugsjahr; + } + + /** {@inheritDoc} */ + public function getCreationDate(): ?string + { + return $this->erstellungsdatum; + } + + /** {@inheritDoc} */ + public function needsReceipt(): bool + { + return !empty($this->quittungscode); + } + + /** {@inheritDoc} */ + public function getReceiptCode(): ?string + { + return $this->quittungscode; + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/EKA/HKEKAv5.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/EKA/HKEKAv5.php new file mode 100644 index 0000000..891abc4 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/EKA/HKEKAv5.php @@ -0,0 +1,71 @@ +kontoverbindungInternational = $kti; + $result->format = $format; + $result->vonDatum = $vonDatum; + $result->bisDatum = $bisDatum; + $result->aufsetzpunkt = $aufsetzpunkt; + return $result; + } + + public function setPaginationToken(string $paginationToken): void + { + $this->aufsetzpunkt = $paginationToken; + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/EKA/ParameterElektronischerKontoauszug.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/EKA/ParameterElektronischerKontoauszug.php new file mode 100644 index 0000000..8c4f609 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/EKA/ParameterElektronischerKontoauszug.php @@ -0,0 +1,75 @@ +unterstuetzteFormate)) { + return false; + } + return stripos($this->unterstuetzteFormate, 'PDF') !== false || + str_contains($this->unterstuetzteFormate, '2;'); + } + + /** + * Prüft ob MT940-Format unterstützt wird + */ + public function supportsMt940(): bool + { + if (empty($this->unterstuetzteFormate)) { + return false; + } + return stripos($this->unterstuetzteFormate, 'MT940') !== false || + str_contains($this->unterstuetzteFormate, '1;'); + } + + /** + * Prüft ob Zeitraum-Abruf möglich ist + */ + public function canFetchByDateRange(): bool + { + return $this->zeitraumAbrufMoeglich === 'J'; + } + + /** + * Prüft ob Quittierung erforderlich ist + */ + public function requiresReceipt(): bool + { + return $this->quittierungErforderlich === 'J'; + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/EKP/HIEKPS.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/EKP/HIEKPS.php deleted file mode 100644 index 6967bf2..0000000 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/EKP/HIEKPS.php +++ /dev/null @@ -1,11 +0,0 @@ -parameter; - } -} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/EKP/HKEKPv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/EKP/HKEKPv2.php deleted file mode 100644 index 9db96e6..0000000 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/EKP/HKEKPv2.php +++ /dev/null @@ -1,75 +0,0 @@ -kontoverbindungInternational = $kti; - $result->kontoauszugsnummer = $kontoauszugsnummer; - $result->kontoauszugsjahr = $kontoauszugsjahr; - $result->aufsetzpunkt = $aufsetzpunkt; - return $result; - } - - public function setPaginationToken(string $paginationToken): void - { - $this->aufsetzpunkt = $paginationToken; - } -} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/EKP/ParameterKontoauszugPdf.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/EKP/ParameterKontoauszugPdf.php deleted file mode 100644 index 8cdeae0..0000000 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/EKP/ParameterKontoauszugPdf.php +++ /dev/null @@ -1,48 +0,0 @@ -kontoauszugsnummerErlaubt; - } - - public function needsReceipt(): bool - { - return $this->quittierungBenoetigt; - } - - public function isBase64Encoded(): bool - { - return $this->base64Kodiert; - } -} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/ElementDescriptor.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/ElementDescriptor.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIBPA/HIBPAv3.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIBPA/HIBPAv3.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIBPA/UnterstuetzteHbciVersionenV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIBPA/UnterstuetzteHbciVersionenV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIBPA/UnterstuetzteSprachenV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIBPA/UnterstuetzteSprachenV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIPINS/GeschaeftsvorfallspezifischePinTanInformationen.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIPINS/GeschaeftsvorfallspezifischePinTanInformationen.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIPINS/HIPINSv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIPINS/HIPINSv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIPINS/ParameterPinTanSpezifischeInformationen.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIPINS/ParameterPinTanSpezifischeInformationen.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMG/HIRMGv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMG/HIRMGv2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMS/FindRueckmeldungTrait.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMS/FindRueckmeldungTrait.php old mode 100755 new mode 100644 index 2f0bebd..d41e44b --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMS/FindRueckmeldungTrait.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMS/FindRueckmeldungTrait.php @@ -29,4 +29,10 @@ trait FindRueckmeldungTrait return $rueckmeldung->rueckmeldungscode === $code; })); } + + /** @return Rueckmeldung[] */ + public function getAllRueckmeldungen(): array + { + return $this->rueckmeldung; + } } diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMS/HIRMSv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMS/HIRMSv2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMS/Rueckmeldung.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMS/Rueckmeldung.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMS/RueckmeldungContainer.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMS/RueckmeldungContainer.php old mode 100755 new mode 100644 index 33bcdd0..5f45baa --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMS/RueckmeldungContainer.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMS/RueckmeldungContainer.php @@ -15,4 +15,7 @@ interface RueckmeldungContainer /** @return Rueckmeldung[] */ public function findRueckmeldungen(int $code): array; + + /** @return Rueckmeldung[] */ + public function getAllRueckmeldungen(): array; } diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMS/Rueckmeldungscode.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMS/Rueckmeldungscode.php old mode 100755 new mode 100644 index 7a53a5e..d401cbb --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMS/Rueckmeldungscode.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIRMS/Rueckmeldungscode.php @@ -2,6 +2,8 @@ namespace Fhp\Segment\HIRMS; +use Fhp\Protocol\DialogInitialization; + /** * Enum for the response codes that the server can send. * @@ -77,7 +79,17 @@ abstract class Rueckmeldungscode * Tells the client that the response is incomplete and the request needs to be re-sent with the pagination token * ("Aufsetzpunkt") that is contained in the Rueckmeldung parameters. */ - public const PAGINATION = 3040; + public const AUFSETZPUNKT = 3040; + + public const VOP_KEINE_NAMENSABWEICHUNG = 25; + + public const VOP_ERGEBNIS_NAMENSABGLEICH_PRUEFEN = 3090; + + public const VOP_AUSFUEHRUNGSAUFTRAG_NICHT_BENOETIGT = 3091; + + public const VOP_NAMENSABGLEICH_IST_NOCH_IN_BEARBEITUNG = 3093; + + public const VOP_NAMENSABGLEICH_IST_KOMPLETT = 3094; /** * Zugelassene Ein- und Zwei-Schritt-Verfahren für den Benutzer (+ Rückmeldungsparameter). @@ -99,6 +111,14 @@ abstract class Rueckmeldungscode */ public const ZUGANG_VORLAEUFIG_GESPERRT = 3938; + /** + * Der eingereichte HKTAN ist entwertet und der Auftrag (nach + * vollständiger Übermittlung des Prüfergebnisses) soll erneut mit einem neuen + * HKTAN in Verbindung mit einem HKVPA eingereicht werden, sofern der + * Kunde die Ausführung weiterhin wünscht. + */ + public const FREIGABE_KANN_NICHT_ERTEILT_WERDEN = 3945; + /** * Starke Kundenauthentifizierung noch ausstehend. * Indicates that the decoupled authentication is still outstanding. @@ -110,6 +130,12 @@ abstract class Rueckmeldungscode */ public const TEILWEISE_FEHLERHAFT = 9050; + /** + * Neue Kundensystem-ID anfordern. + * Als Antwort auf eine Dialoginitialisierungsnachricht ({@link DialogInitialization}). + */ + public const NEUE_KUNDENSYSTEM_ID_HOLEN = 9391; + /** * Kreditinstitutsseitige Beendigung des Dialoges */ diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HISYN/HISYNv4.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HISYN/HISYNv4.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPA/HIUPAv4.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPA/HIUPAv4.php old mode 100755 new mode 100644 index 5dc197f..5088d3e --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPA/HIUPAv4.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPA/HIUPAv4.php @@ -24,7 +24,6 @@ class HIUPAv4 extends BaseSegment * it does not support it, so sending such a request to the bank will always lead to failure. * 1: Explicitly declared types are definitely supported, anything else may be reported and can be sent; the bank * will check online and accept/reject accordingly. - * @var int */ public int $updVerwendung; /** Max length: 35 */ diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/ErlaubteGeschaeftsvorfaelle.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/ErlaubteGeschaeftsvorfaelle.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/ErlaubteGeschaeftsvorfaelleV1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/ErlaubteGeschaeftsvorfaelleV1.php old mode 100755 new mode 100644 index f473ae0..8b33098 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/ErlaubteGeschaeftsvorfaelleV1.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/ErlaubteGeschaeftsvorfaelleV1.php @@ -22,7 +22,6 @@ class ErlaubteGeschaeftsvorfaelleV1 extends BaseDeg implements ErlaubteGeschaeft /** If present, must be greater than 0 */ public ?int $limitTage = null; - /** {@inheritdoc} */ public function getGeschaeftsvorfall(): string { return $this->geschaeftsvorfall; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/ErlaubteGeschaeftsvorfaelleV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/ErlaubteGeschaeftsvorfaelleV2.php old mode 100755 new mode 100644 index 7766078..23b0dba --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/ErlaubteGeschaeftsvorfaelleV2.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/ErlaubteGeschaeftsvorfaelleV2.php @@ -22,7 +22,6 @@ class ErlaubteGeschaeftsvorfaelleV2 extends BaseDeg implements ErlaubteGeschaeft /** Only allowed for limitart==Z, must be greater than zero. */ public ?int $limitTage = null; - /** {@inheritdoc} */ public function getGeschaeftsvorfall(): string { return $this->geschaeftsvorfall; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/HIUPD.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/HIUPD.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/HIUPDv4.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/HIUPDv4.php old mode 100755 new mode 100644 index 234bc25..4429fdd --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/HIUPDv4.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/HIUPDv4.php @@ -29,14 +29,12 @@ class HIUPDv4 extends BaseSegment implements HIUPD /** @var ErlaubteGeschaeftsvorfaelleV1[]|null @Max(98) */ public ?array $erlaubteGeschaeftsvorfaelle = null; - /** {@inheritdoc} */ public function matchesAccount(SEPAAccount $account): bool { return !is_null($this->kontoverbindung->kontonummer) && $this->kontoverbindung->kontonummer == $account->getAccountNumber(); } - /** {@inheritdoc} */ public function getErlaubteGeschaeftsvorfaelle(): array { return $this->erlaubteGeschaeftsvorfaelle ?? []; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/HIUPDv6.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/HIUPDv6.php old mode 100755 new mode 100644 index 94e5c42..3ecd9d6 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/HIUPDv6.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/HIUPDv6.php @@ -51,13 +51,15 @@ class HIUPDv6 extends BaseSegment implements HIUPD */ public ?string $erweiterungKontobezogen = null; - /** {@inheritdoc} */ public function matchesAccount(SEPAAccount $account): bool { - return !is_null($this->iban) && $this->iban == $account->getIban(); + if (!is_null($this->iban)) { + return $this->iban == $account->getIban(); + } + // Sparkasse (Koblenz) does not provide an IBAN in this segment, fall back to kontonummer: + return !is_null($this->kontoverbindung->kontonummer) && $this->kontoverbindung->kontonummer == $account->getAccountNumber(); } - /** {@inheritdoc} */ public function getErlaubteGeschaeftsvorfaelle(): array { return $this->erlaubteGeschaeftsvorfaelle ?? []; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/KontolimitV1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/KontolimitV1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/KontolimitV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HIUPD/KontolimitV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HKEND/HKENDv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HKEND/HKENDv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HKIDN/HKIDNv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HKIDN/HKIDNv2.php old mode 100755 new mode 100644 index 155abd2..f4147de --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/HKIDN/HKIDNv2.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/HKIDN/HKIDNv2.php @@ -30,7 +30,6 @@ class HKIDNv2 extends BaseSegment * 0: Kundensystem-ID wird nicht benötigt (HBCI DDV-Verfahren und chipkartenbasierte Verfahren ab * Sicherheitsprofil-Version 3) * 1: Kundensystem-ID wird benötigt (sonstige HBCI RAH-/RDH- und PIN/TAN-Verfahren) - * @var int */ public int $kundensystemStatus = 1; // This library only supports PIN/TAN, hence 1 is the right choice. diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HKSYN/HKSYNv3.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HKSYN/HKSYNv3.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HKVVB/HKVVBv3.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HKVVB/HKVVBv3.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HNHBK/BezugsnachrichtV1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HNHBK/BezugsnachrichtV1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HNHBK/HNHBKv3.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HNHBK/HNHBKv3.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HNHBS/HNHBSv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HNHBS/HNHBSv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HNSHA/BenutzerdefinierteSignaturV1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HNSHA/BenutzerdefinierteSignaturV1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HNSHA/HNSHAv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HNSHA/HNSHAv2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HNSHK/HNSHKv4.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HNSHK/HNSHKv4.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HNSHK/HashalgorithmusV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HNSHK/HashalgorithmusV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HNSHK/SignaturalgorithmusV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HNSHK/SignaturalgorithmusV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HNVSD/HNVSDv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HNVSD/HNVSDv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HNVSK/HNVSKv3.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HNVSK/HNVSKv3.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HNVSK/SchluesselnameV3.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HNVSK/SchluesselnameV3.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HNVSK/SicherheitsdatumUndUhrzeitV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HNVSK/SicherheitsdatumUndUhrzeitV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HNVSK/SicherheitsidentifikationDetailsV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HNVSK/SicherheitsidentifikationDetailsV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HNVSK/SicherheitsprofilV1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HNVSK/SicherheitsprofilV1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HNVSK/VerschluesselungsalgorithmusV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HNVSK/VerschluesselungsalgorithmusV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/HNVSK/ZertifikatV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/HNVSK/ZertifikatV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HIIPZSv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HIIPZSv1.php old mode 100755 new mode 100644 index 21b915a..2f4d7f2 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HIIPZSv1.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HIIPZSv1.php @@ -11,7 +11,6 @@ use Fhp\Segment\BaseSegment; * @link https://www.hbci-zka.de/dokumente/spezifikation_deutsch/fintsv3/FinTS_3.0_Messages_Geschaeftsvorfaelle_2022-04-15_final_version.pdf * Section: C.10.2.9.1.1 c) */ - class HIIPZSv1 extends BaseGeschaeftsvorfallparameter { public ParameterSEPAInstantPaymentZahlungV1 $parameter; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HIIPZSv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HIIPZSv2.php old mode 100755 new mode 100644 index e78c92b..b31acf3 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HIIPZSv2.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HIIPZSv2.php @@ -2,7 +2,6 @@ namespace Fhp\Segment\IPZ; -use Fhp\Segment\IPZ\ParameterSEPAInstantPaymentZahlungV2; use Fhp\Segment\BaseGeschaeftsvorfallparameter; use Fhp\Segment\BaseSegment; @@ -12,7 +11,6 @@ use Fhp\Segment\BaseSegment; * @link https://www.hbci-zka.de/dokumente/spezifikation_deutsch/fintsv3/FinTS_3.0_Messages_Geschaeftsvorfaelle_2022-04-15_final_version.pdf * Section: C.10.2.9.1.2 c) */ - class HIIPZSv2 extends BaseGeschaeftsvorfallparameter { public ParameterSEPAInstantPaymentZahlungV2 $parameter; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HIIPZv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HIIPZv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HIIPZv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HIIPZv2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HKIPZv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HKIPZv1.php old mode 100755 new mode 100644 index b5ffdf9..9d7dcdd --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HKIPZv1.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HKIPZv1.php @@ -12,5 +12,4 @@ use Fhp\Segment\CCS\HKCCSv1; */ class HKIPZv1 extends HKCCSv1 { - } diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HKIPZv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/HKIPZv2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/ParameterSEPAInstantPaymentZahlungV1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/ParameterSEPAInstantPaymentZahlungV1.php old mode 100755 new mode 100644 index 9ae83ab..11cf6d6 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/ParameterSEPAInstantPaymentZahlungV1.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/ParameterSEPAInstantPaymentZahlungV1.php @@ -21,4 +21,4 @@ class ParameterSEPAInstantPaymentZahlungV1 extends BaseDeg implements Unterstuet /** @var string[]|null @Max(9) Max length: 256 */ public ?array $unterstuetzteSEPADatenformate = null; -} \ No newline at end of file +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/ParameterSEPAInstantPaymentZahlungV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/IPZ/ParameterSEPAInstantPaymentZahlungV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/EKP/HIEKP.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/HIKAA.php similarity index 72% rename from vendor/nemiah/php-fints/lib/Fhp/Segment/EKP/HIEKP.php rename to vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/HIKAA.php index 81a70e4..ff137b9 100644 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/EKP/HIEKP.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/HIKAA.php @@ -1,18 +1,27 @@ parameter; + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/EKP/HIEKPv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/HIKAAv1.php similarity index 54% rename from vendor/nemiah/php-fints/lib/Fhp/Segment/EKP/HIEKPv2.php rename to vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/HIKAAv1.php index 8d76d5d..3062af9 100644 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/EKP/HIEKPv2.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/HIKAAv1.php @@ -1,27 +1,35 @@ gebuchteUmsaetze->getData(); + return $this->kontoauszugsdaten->getData(); } public function getStatementNumber(): ?int @@ -67,7 +69,7 @@ class HIEKPv2 extends BaseSegment implements HIEKP public function getIban(): ?string { - return $this->ibanKonto; + return $this->iban; } public function getFilename(): ?string @@ -75,12 +77,17 @@ class HIEKPv2 extends BaseSegment implements HIEKP return $this->dateiname; } + public function getFormat(): ?int + { + return $this->format; + } + public function getCreationDate(): ?\DateTime { - if ($this->erstellungsdatumKontoauszug === null) { + if ($this->erstellungsdatum === null) { return null; } - return \DateTime::createFromFormat('Ymd', $this->erstellungsdatumKontoauszug) ?: null; + return \DateTime::createFromFormat('Ymd', $this->erstellungsdatum) ?: null; } public function needsReceipt(): bool diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/HIKAAv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/HIKAAv2.php new file mode 100644 index 0000000..c9e4910 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/HIKAAv2.php @@ -0,0 +1,102 @@ +kontoauszugsdaten->getData(); + } + + public function getStatementNumber(): ?int + { + return $this->kontoauszugsnummer; + } + + public function getStatementYear(): ?int + { + return $this->kontoauszugsjahr; + } + + public function getIban(): ?string + { + return $this->iban; + } + + public function getFilename(): ?string + { + return $this->dateiname; + } + + public function getFormat(): ?int + { + return $this->format; + } + + public function getCreationDate(): ?\DateTime + { + if ($this->erstellungsdatum === null) { + return null; + } + return \DateTime::createFromFormat('Ymd', $this->erstellungsdatum) ?: null; + } + + public function needsReceipt(): bool + { + return $this->quittungscode !== null; + } + + public function getReceiptCode(): ?string + { + return $this->quittungscode?->getData(); + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/HKKAAv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/HKKAAv1.php new file mode 100644 index 0000000..ad3417e --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/HKKAAv1.php @@ -0,0 +1,81 @@ +kontoverbindungInternational = $kti; + $result->format = $format; + $result->vonDatum = $vonDatum; + $result->bisDatum = $bisDatum; + $result->aufsetzpunkt = $aufsetzpunkt; + return $result; + } + + public function setPaginationToken(string $paginationToken): void + { + $this->aufsetzpunkt = $paginationToken; + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/HKKAAv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/HKKAAv2.php new file mode 100644 index 0000000..1f12d60 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/HKKAAv2.php @@ -0,0 +1,83 @@ +kontoverbindungInternational = $kti; + $result->format = $format; + $result->vonDatum = $vonDatum; + $result->bisDatum = $bisDatum; + $result->aufsetzpunkt = $aufsetzpunkt; + return $result; + } + + public function setPaginationToken(string $paginationToken): void + { + $this->aufsetzpunkt = $paginationToken; + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/ParameterKontoauszugArchiv.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/ParameterKontoauszugArchiv.php new file mode 100644 index 0000000..7850bdf --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAA/ParameterKontoauszugArchiv.php @@ -0,0 +1,90 @@ +unterstuetzteFormate)) { + return false; + } + // Format "4;PDF;1" - Code 4 ist PDF + return str_contains($this->unterstuetzteFormate, '4;') || + stripos($this->unterstuetzteFormate, 'PDF') !== false; + } + + /** + * Gibt den Format-Code für PDF zurück (normalerweise 4) + */ + public function getPdfFormatCode(): int + { + return 4; + } + + /** + * Prüft ob Einzelabruf möglich ist + */ + public function canFetchSingle(): bool + { + return $this->einzelabrufMoeglich === 'J'; + } + + /** + * Prüft ob Zeitraum-Abruf möglich ist + */ + public function canFetchByDateRange(): bool + { + return $this->zeitraumAbrufMoeglich === 'J'; + } + + /** + * Prüft ob Quittierung erforderlich ist + */ + public function requiresReceipt(): bool + { + return $this->quittierungErforderlich === 'J'; + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZ.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZ.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZS.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZS.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZSv4.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZSv4.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZSv5.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZSv5.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZSv6.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZSv6.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZSv7.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZSv7.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZv4.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZv4.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZv5.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZv5.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZv6.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZv6.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZv7.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HIKAZv7.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HKKAZv4.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HKKAZv4.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HKKAZv5.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HKKAZv5.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HKKAZv6.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HKKAZv6.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HKKAZv7.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/HKKAZv7.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/ParameterKontoumsaetze.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/ParameterKontoumsaetze.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/ParameterKontoumsaetzeV1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/ParameterKontoumsaetzeV1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/ParameterKontoumsaetzeV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/KAZ/ParameterKontoumsaetzeV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/Paginateable.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/Paginateable.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISAL.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISAL.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISALSv4.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISALSv4.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISALSv5.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISALSv5.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISALSv6.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISALSv6.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISALSv7.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISALSv7.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISALv4.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISALv4.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISALv5.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISALv5.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISALv6.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISALv6.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISALv7.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HISALv7.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HKSALv4.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HKSALv4.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HKSALv5.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HKSALv5.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HKSALv6.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HKSALv6.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HKSALv7.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SAL/HKSALv7.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HISPA.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HISPA.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HISPAS.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HISPAS.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HISPASv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HISPASv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HISPASv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HISPASv2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HISPASv3.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HISPASv3.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HISPAv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HISPAv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HISPAv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HISPAv2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HISPAv3.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HISPAv3.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HKSPAv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HKSPAv1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HKSPAv2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HKSPAv2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HKSPAv3.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/HKSPAv3.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/ParameterSepaKontoverbindungAnfordern.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/ParameterSepaKontoverbindungAnfordern.php old mode 100755 new mode 100644 index d0b09eb..27e5f17 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/ParameterSepaKontoverbindungAnfordern.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/ParameterSepaKontoverbindungAnfordern.php @@ -10,5 +10,4 @@ use Fhp\Segment\UnterstuetzteSEPADatenformate; */ interface ParameterSepaKontoverbindungAnfordern extends UnterstuetzteSEPADatenformate { - } diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/ParameterSepaKontoverbindungAnfordernV1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/ParameterSepaKontoverbindungAnfordernV1.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/ParameterSepaKontoverbindungAnfordernV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/ParameterSepaKontoverbindungAnfordernV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/ParameterSepaKontoverbindungAnfordernV3.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SPA/ParameterSepaKontoverbindungAnfordernV3.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SegmentDescriptor.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SegmentDescriptor.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/SegmentInterface.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/SegmentInterface.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/Segmentkopf.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/Segmentkopf.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HITAB.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HITAB.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HITABSv4.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HITABSv4.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HITABSv5.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HITABSv5.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HITABv4.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HITABv4.php old mode 100755 new mode 100644 index 9973795..046c1af --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HITABv4.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HITABv4.php @@ -22,7 +22,6 @@ class HITABv4 extends BaseSegment implements HITAB /** @var TanMediumListeV4[]|null @Max(99) */ public ?array $tanMediumListe = null; - /** {@inheritdoc} */ public function getTanMediumListe(): array { return $this->tanMediumListe; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HITABv5.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HITABv5.php old mode 100755 new mode 100644 index c7f8916..6a72c8c --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HITABv5.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HITABv5.php @@ -22,7 +22,6 @@ class HITABv5 extends BaseSegment implements HITAB /** @var TanMediumListeV5[]|null @Max(99) */ public ?array $tanMediumListe = null; - /** {@inheritdoc} */ public function getTanMediumListe(): array { return $this->tanMediumListe; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HKTABv4.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HKTABv4.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HKTABv5.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/HKTABv5.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/TanMediumListe.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/TanMediumListe.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/TanMediumListeV4.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/TanMediumListeV4.php old mode 100755 new mode 100644 index 4f53401..abe3dae --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/TanMediumListeV4.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/TanMediumListeV4.php @@ -56,13 +56,11 @@ class TanMediumListeV4 extends BaseDeg implements TanMediumListe /** JJJJMMTT gemäß ISO 8601 */ public ?string $freigeschaltetAm = null; - /** {@inheritdoc} */ public function getName(): string { return $this->bezeichnungDesTanMediums; } - /** {@inheritdoc} */ public function getPhoneNumber(): ?string { return $this->mobiltelefonnummer !== null ? $this->mobiltelefonnummer : $this->mobiltelefonnummerVerschleiert; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/TanMediumListeV5.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/TanMediumListeV5.php old mode 100755 new mode 100644 index be5aa7f..13bf8b0 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/TanMediumListeV5.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAB/TanMediumListeV5.php @@ -59,13 +59,11 @@ class TanMediumListeV5 extends BaseDeg implements TanMediumListe /** JJJJMMTT gemäß ISO 8601 */ public ?string $freigeschaltetAm = null; - /** {@inheritdoc} */ public function getName(): string { return $this->bezeichnungDesTanMediums; } - /** {@inheritdoc} */ public function getPhoneNumber(): ?string { return $this->mobiltelefonnummer !== null ? $this->mobiltelefonnummer : $this->mobiltelefonnummerVerschleiert; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/AntwortHhdUc.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/AntwortHhdUc.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/GueltigkeitsdatumUndUhrzeitFuerChallenge.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/GueltigkeitsdatumUndUhrzeitFuerChallenge.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HITAN.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HITAN.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HITANS.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HITANS.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HITANSv6.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HITANSv6.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HITANSv7.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HITANSv7.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HITANv6.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HITANv6.php old mode 100755 new mode 100644 index 2d641f2..c1032f9 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HITANv6.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HITANv6.php @@ -55,21 +55,18 @@ class HITANv6 extends BaseSegment implements HITAN */ public ?string $bezeichnungDesTanMediums = null; - /** {@inheritdoc} */ public function getProcessId(): string { // Note: This is non-null because tanProzess==4. return $this->auftragsreferenz; } - /** {@inheritdoc} */ public function getChallenge(): ?string { // Note: This is non-null because tanProzess==4. return $this->challenge === static::DUMMY_CHALLENGE ? null : $this->challenge; } - /** {@inheritdoc} */ public function getTanMediumName(): ?string { return $this->bezeichnungDesTanMediums; diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HITANv7.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HITANv7.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HKTAN.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HKTAN.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HKTANFactory.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HKTANFactory.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HKTANv6.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HKTANv6.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HKTANv7.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/HKTANv7.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/ParameterChallengeKlasse.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/ParameterChallengeKlasse.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/ParameterZweiSchrittTanEinreichung.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/ParameterZweiSchrittTanEinreichung.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/ParameterZweiSchrittTanEinreichungV6.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/ParameterZweiSchrittTanEinreichungV6.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/ParameterZweiSchrittTanEinreichungV7.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/ParameterZweiSchrittTanEinreichungV7.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/VerfahrensparameterZweiSchrittVerfahrenV6.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/VerfahrensparameterZweiSchrittVerfahrenV6.php old mode 100755 new mode 100644 index 6695917..38ae6cb --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/VerfahrensparameterZweiSchrittVerfahrenV6.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/VerfahrensparameterZweiSchrittVerfahrenV6.php @@ -49,115 +49,96 @@ class VerfahrensparameterZweiSchrittVerfahrenV6 extends BaseDeg implements TanMo public bool $antwortHhdUcErforderlich; public ?int $anzahlUnterstuetzterAktiverTanMedien = null; - /** {@inheritdoc} */ public function getId(): int { return $this->sicherheitsfunktion; } - /** {@inheritdoc} */ public function getName(): string { return $this->nameDesZweiSchrittVerfahrens; } - /** {@inheritdoc} */ public function isProzessvariante2(): bool { return $this->tanProzess === HKTAN::TAN_PROZESS_2; } - /** {@inheritdoc} */ public function isDecoupled(): bool { return false; } - /** {@inheritdoc} */ public function getSmsAbbuchungskontoErforderlich(): bool { return $this->smsAbbuchungskontoErforderlich === 2; } - /** {@inheritdoc} */ public function getAuftraggeberkontoErforderlich(): bool { return $this->auftraggeberkontoErforderlich === 2; } - /** {@inheritdoc} */ public function getChallengeKlasseErforderlich(): bool { return $this->challengeKlasseErforderlich; } - /** {@inheritdoc} */ public function getAntwortHhdUcErforderlich(): bool { return $this->antwortHhdUcErforderlich; } - /** {@inheritdoc} */ public function getChallengeLabel(): string { return $this->textZurBelegungDesRueckgabewertes; } - /** {@inheritdoc} */ public function getMaxChallengeLength(): int { return $this->maximaleLaengeDesRueckgabewertes; } - /** {@inheritdoc} */ public function getMaxTanLength(): int { return $this->maximaleLaengeDesTanEingabewertes; } - /** {@inheritdoc} */ public function getTanFormat(): int { return $this->erlaubtesFormat; } - /** {@inheritdoc} */ public function needsTanMedium(): bool { return $this->bezeichnungDesTanMediumsErforderlich === 2 && $this->anzahlUnterstuetzterAktiverTanMedien > 0; } - /** {@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'); } - /** {@inheritdoc} */ public function createHKTAN(): HKTAN { return HKTANv6::createEmpty(); diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/VerfahrensparameterZweiSchrittVerfahrenV7.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/VerfahrensparameterZweiSchrittVerfahrenV7.php old mode 100755 new mode 100644 index 17c47c6..3834f80 --- a/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/VerfahrensparameterZweiSchrittVerfahrenV7.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/TAN/VerfahrensparameterZweiSchrittVerfahrenV7.php @@ -70,67 +70,56 @@ class VerfahrensparameterZweiSchrittVerfahrenV7 extends BaseDeg implements TanMo /** Maybe present if isDecoupled. */ public ?bool $automatisierteStatusabfragenErlaubt = null; - /** {@inheritdoc} */ public function getId(): int { return $this->sicherheitsfunktion; } - /** {@inheritdoc} */ public function getName(): string { return $this->nameDesZweiSchrittVerfahrens; } - /** {@inheritdoc} */ public function isProzessvariante2(): bool { return $this->tanProzess === HKTAN::TAN_PROZESS_2; } - /** {@inheritdoc} */ public function isDecoupled(): bool { return $this->dkTanVerfahren === 'Decoupled' || $this->dkTanVerfahren === 'DecoupledPush'; } - /** {@inheritdoc} */ public function getSmsAbbuchungskontoErforderlich(): bool { return $this->smsAbbuchungskontoErforderlich === 2; } - /** {@inheritdoc} */ public function getAuftraggeberkontoErforderlich(): bool { return $this->auftraggeberkontoErforderlich === 2; } - /** {@inheritdoc} */ public function getChallengeKlasseErforderlich(): bool { return $this->challengeKlasseErforderlich; } - /** {@inheritdoc} */ public function getAntwortHhdUcErforderlich(): bool { return $this->antwortHhdUcErforderlich; } - /** {@inheritdoc} */ public function getChallengeLabel(): string { return $this->textZurBelegungDesRueckgabewertes; } - /** {@inheritdoc} */ public function getMaxChallengeLength(): int { return $this->maximaleLaengeDesRueckgabewertes; } - /** {@inheritdoc} */ public function getMaxTanLength(): int { if ($this->isDecoupled()) { @@ -142,7 +131,6 @@ class VerfahrensparameterZweiSchrittVerfahrenV7 extends BaseDeg implements TanMo return $this->maximaleLaengeDesTanEingabewertes; } - /** {@inheritdoc} */ public function getTanFormat(): int { if ($this->isDecoupled()) { @@ -154,13 +142,11 @@ class VerfahrensparameterZweiSchrittVerfahrenV7 extends BaseDeg implements TanMo return $this->erlaubtesFormat; } - /** {@inheritdoc} */ public function needsTanMedium(): bool { return $this->bezeichnungDesTanMediumsErforderlich === 2 && $this->anzahlUnterstuetzterAktiverTanMedien > 0; } - /** {@inheritdoc} */ public function getMaxDecoupledChecks(): int { if (!$this->isDecoupled()) { @@ -172,7 +158,6 @@ class VerfahrensparameterZweiSchrittVerfahrenV7 extends BaseDeg implements TanMo return $this->maximaleAnzahlStatusabfragen; } - /** {@inheritdoc} */ public function getFirstDecoupledCheckDelaySeconds(): int { if (!$this->isDecoupled()) { @@ -184,7 +169,6 @@ class VerfahrensparameterZweiSchrittVerfahrenV7 extends BaseDeg implements TanMo return $this->wartezeitVorErsterStatusabfrage; } - /** {@inheritdoc} */ public function getPeriodicDecoupledCheckDelaySeconds(): int { if (!$this->isDecoupled()) { @@ -196,7 +180,6 @@ class VerfahrensparameterZweiSchrittVerfahrenV7 extends BaseDeg implements TanMo return $this->wartezeitVorNaechsterStatusabfrage; } - /** {@inheritdoc} */ public function allowsManualConfirmation(): bool { if (!$this->isDecoupled()) { @@ -208,7 +191,6 @@ class VerfahrensparameterZweiSchrittVerfahrenV7 extends BaseDeg implements TanMo return $this->manuelleBestaetigungMoeglich; } - /** {@inheritdoc} */ public function allowsAutomatedPolling(): bool { if (!$this->isDecoupled()) { @@ -220,7 +202,6 @@ class VerfahrensparameterZweiSchrittVerfahrenV7 extends BaseDeg implements TanMo return $this->automatisierteStatusabfragenErlaubt; } - /** {@inheritdoc} */ public function createHKTAN(): HKTAN { return HKTANv7::createEmpty(); diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/UnterstuetzteSEPADatenformate.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/UnterstuetzteSEPADatenformate.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/UnterstuetzteSEPADatenformateTrait.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/UnterstuetzteSEPADatenformateTrait.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/VPA/HKVPAv1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/VPA/HKVPAv1.php new file mode 100644 index 0000000..843d88a --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/VPA/HKVPAv1.php @@ -0,0 +1,17 @@ +unterstuetztePaymentStatusReports = new UnterstuetztePaymentStatusReportsV1(); + return $hkvpp; + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/VPP/ParameterNamensabgleichPruefauftragV1.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/VPP/ParameterNamensabgleichPruefauftragV1.php new file mode 100644 index 0000000..df2331f --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Fhp/Segment/VPP/ParameterNamensabgleichPruefauftragV1.php @@ -0,0 +1,30 @@ +getLatestSupportedParameters('HIVPPS'); + $supportedFormats = explode(';', $hivpps->parameter->unterstuetztePaymentStatusReportDatenformate); + if ($hivpps->parameter->artDerLieferungPaymentStatusReport !== 'V') { + throw new UnsupportedException('The stepwise transfer of VOP reports is not yet supported'); + } + + $hkvpp = HKVPPv1::createEmpty(); + $hkvpp->unterstuetztePaymentStatusReports->paymentStatusReportDescriptor = $supportedFormats; + return $hkvpp; + } + + /** + * @param BPD $bpd The BPD. + * @param VopPollingInfo $pollingInfo The polling info we got from the immediately preceding request. + * @return HKVPPv1 A segment to poll the server for the completion of Verification of Payee. + */ + public static function createHKVPPForPollingRequest(BPD $bpd, VopPollingInfo $pollingInfo): HKVPPv1 + { + $hkvpp = static::createHKVPPForInitialRequest($bpd); + $hkvpp->aufsetzpunkt = $pollingInfo->getAufsetzpunkt(); + $hkvpp->pollingId = $pollingInfo->getPollingId(); + return $hkvpp; + } + + /** + * @param Message $response The response we just received from the server. + * @param int $hkvppSegmentNumber The number of the HKVPP segment in the request we had sent. + * @return ?VopPollingInfo If the response indicates that the Verification of Payee is still ongoing, such that the + * client should keep polling the server to (actively) wait until the result is available, this function returns + * a corresponding polling info object. If no polling is required, it returns null. + */ + public static function checkPollingRequired(Message $response, int $hkvppSegmentNumber): ?VopPollingInfo + { + // Note: We determine whether polling is required purely based on the presence of the primary polling token ( + // the Aufsetzpunkt is mandatory, the polling ID is optional). + // The specification also contains the code "3093 Namensabgleich ist noch in Bearbeitung", which could also be + // used to indicate that polling is required. But the specification does not mandate its use, and we have not + // observed banks using it consistently, so we don't rely on it here. + $aufsetzpunkt = $response->findRueckmeldung(Rueckmeldungscode::AUFSETZPUNKT, $hkvppSegmentNumber); + if ($aufsetzpunkt === null) { + return null; + } + /** @var HIVPPv1 $hivpp */ + $hivpp = $response->findSegment(HIVPPv1::class); + if ($hivpp->vopId !== null || $hivpp->paymentStatusReport !== null) { + // Implementation note: If this ever happens, it could be related to $artDerLieferungPaymentStatusReport. + throw new UnexpectedResponseException('Got response with Aufsetzpunkt AND vopId/paymentStatusReport.'); + } + return new VopPollingInfo( + $aufsetzpunkt->rueckmeldungsparameter[0], + $hivpp?->pollingId, + $hivpp?->wartezeitVorNaechsterAbfrage, + ); + } + + /** + * @param Message $response The response we just received from the server. + * @param int $hkvppSegmentNumber The number of the HKVPP segment in the request we had sent. + * @return ?VopConfirmationRequestImpl If the response contains a confirmation request for the user, it is returned, + * otherwise null (which may imply that the action was executed without requiring confirmation). + */ + public static function checkVopConfirmationRequired( + Message $response, + int $hkvppSegmentNumber, + ): ?VopConfirmationRequestImpl { + $codes = $response->findRueckmeldungscodesForReferenceSegment($hkvppSegmentNumber); + if (in_array(Rueckmeldungscode::VOP_AUSFUEHRUNGSAUFTRAG_NICHT_BENOETIGT, $codes)) { + return null; + } + /** @var HIVPPv1 $hivpp */ + $hivpp = $response->findSegment(HIVPPv1::class); + if ($hivpp === null) { + throw new UnexpectedResponseException('Missing HIVPP in response to a request with HKVPP'); + } + if ($hivpp->vopId === null) { + throw new UnexpectedResponseException('Missing HIVPP.vopId even though VOP should be completed.'); + } + + $verificationNotApplicableReason = null; + if ($hivpp->paymentStatusReport === null) { + if ($hivpp->ergebnisVopPruefungEinzeltransaktion === null) { + throw new UnsupportedException('Missing paymentStatusReport and ergebnisVopPruefungEinzeltransaktion'); + } + $verificationResult = VopVerificationResult::parse( + $hivpp->ergebnisVopPruefungEinzeltransaktion->vopPruefergebnis + ); + $verificationNotApplicableReason = $hivpp->ergebnisVopPruefungEinzeltransaktion->grundRVNA; + } else { + $report = simplexml_load_string($hivpp->paymentStatusReport->getData()); + $verificationResult = VopVerificationResult::parse( + $report->CstmrPmtStsRpt->OrgnlGrpInfAndSts->GrpSts ?: null + ); + + // For a single transaction, we can do better than "CompletedPartialMatch", + // which can indicate either CompletedCloseMatch or CompletedNoMatch + if (intval($report->CstmrPmtStsRpt->OrgnlGrpInfAndSts->OrgnlNbOfTxs ?: 0) === 1 + && $verificationResult === VopVerificationResult::CompletedPartialMatch + && $verificationResultCode = $report->CstmrPmtStsRpt->OrgnlPmtInfAndSts->TxInfAndSts?->TxSts + ) { + $verificationResult = VopVerificationResult::parse($verificationResultCode); + } + } + + return new VopConfirmationRequestImpl( + $hivpp->vopId, + $hivpp->vopIdGueltigBis?->asDateTime(), + $hivpp->aufklaerungstextAutorisierungTrotzAbweichung, + $verificationResult, + $verificationNotApplicableReason, + ); + } + + /** + * @param VopConfirmationRequestImpl $vopConfirmationRequest The VOP request we're confirming. + * @return HKVPAv1 A HKVPA segment that tells the bank the request is good to execute. + */ + public static function createHKVPAForConfirmation(VopConfirmationRequestImpl $vopConfirmationRequest): HKVPAv1 + { + $hkvpa = HKVPAv1::createEmpty(); + $hkvpa->vopId = $vopConfirmationRequest->getVopId(); + return $hkvpa; + } +} diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/WPD/HIWPD.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/WPD/HIWPD.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/WPD/HIWPDS.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/WPD/HIWPDS.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/WPD/HIWPDSv5.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/WPD/HIWPDSv5.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/WPD/HIWPDv5.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/WPD/HIWPDv5.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/WPD/HKWPDv5.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/WPD/HKWPDv5.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/WPD/ParameterDepotaufstellung.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/WPD/ParameterDepotaufstellung.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Segment/WPD/ParameterDepotaufstellungV2.php b/vendor/nemiah/php-fints/lib/Fhp/Segment/WPD/ParameterDepotaufstellungV2.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Syntax/Bin.php b/vendor/nemiah/php-fints/lib/Fhp/Syntax/Bin.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Syntax/Delimiter.php b/vendor/nemiah/php-fints/lib/Fhp/Syntax/Delimiter.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Fhp/Syntax/InvalidResponseException.php b/vendor/nemiah/php-fints/lib/Fhp/Syntax/InvalidResponseException.php old mode 100755 new mode 100644 index c6fe5f8..f69f75d --- a/vendor/nemiah/php-fints/lib/Fhp/Syntax/InvalidResponseException.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Syntax/InvalidResponseException.php @@ -7,7 +7,7 @@ namespace Fhp\Syntax; */ class InvalidResponseException 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); } diff --git a/vendor/nemiah/php-fints/lib/Fhp/Syntax/Parser.php b/vendor/nemiah/php-fints/lib/Fhp/Syntax/Parser.php old mode 100755 new mode 100644 index 5e73043..57c8ba2 --- a/vendor/nemiah/php-fints/lib/Fhp/Syntax/Parser.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Syntax/Parser.php @@ -159,8 +159,8 @@ abstract class Parser $delimiterPos = strpos($rawValue, Delimiter::BINARY, 1); if ( - substr($rawValue, 0, 1) !== Delimiter::BINARY || - $delimiterPos === false + substr($rawValue, 0, 1) !== Delimiter::BINARY + || $delimiterPos === false ) { throw new \InvalidArgumentException("Expected binary block header, got $rawValue"); } @@ -192,8 +192,10 @@ abstract class Parser $rawElements = static::splitEscapedString(Delimiter::GROUP, $rawElements); list($result, $offset) = static::parseDegElements($rawElements, $type, $allowEmpty); if ($offset < count($rawElements)) { - throw new \InvalidArgumentException( - "Expected only $offset elements, but got " . count($rawElements) . ': ' . print_r($rawElements, true)); + // Bank sends more elements than expected - ignore extra elements instead of failing + // This happens when the bank uses a newer format version than the library supports + error_log("FinTS Parser: Ignoring " . (count($rawElements) - $offset) . " extra elements in DEG " . + (is_string($type) ? $type : get_class($type)) . ': ' . print_r(array_slice($rawElements, $offset), true)); } return $result; } @@ -205,7 +207,7 @@ abstract class Parser * write to (the same instance will be returned from this function). * @param bool $allowEmpty If true, this returns either a valid DEG, or null if *all* the fields were empty. * @param int $offset The position in $rawElements to be read next. - * @return array (BaseDeg|null, integer) + * @return array (BaseDeg|null, int) * 1. The parsed value, which has the given $type or is null in case all the fields were empty and $allowEmpty * is true. * 2. The offset at which parsing should continue. The difference between this returned offset and the $offset diff --git a/vendor/nemiah/php-fints/lib/Fhp/Syntax/Serializer.php b/vendor/nemiah/php-fints/lib/Fhp/Syntax/Serializer.php old mode 100755 new mode 100644 index a5d1430..c0d64ff --- a/vendor/nemiah/php-fints/lib/Fhp/Syntax/Serializer.php +++ b/vendor/nemiah/php-fints/lib/Fhp/Syntax/Serializer.php @@ -71,6 +71,15 @@ abstract class Serializer return implode(Delimiter::ELEMENT, static::flattenAndTrimEnd($serializedElements)) . Delimiter::SEGMENT; } + /** + * @param BaseSegment[] $segments The segments to be serialized. + * @return string The concatenated HBCI wire format representation of the segments. + */ + public static function serializeSegments(array $segments): string + { + return implode(array_map([self::class, 'serializeSegment'], $segments)); + } + /** * @param BaseSegment|BaseDeg|null $obj An object to be serialized. If null, all fields are implicitly null. * @param BaseDescriptor $descriptor The descriptor for the object to be serialized. @@ -101,11 +110,27 @@ abstract class Serializer throw new \InvalidArgumentException( "Expected array value for $descriptor->class.$elementDescriptor->field, got: $value"); } - for ($repetition = 0; $repetition < $elementDescriptor->repeated; ++$repetition) { + if ($elementDescriptor->repeated === PHP_INT_MAX) { + // For an uncapped repeated field (with @Unlimited), it must be the very last field and we do not + // need to insert padding elements, so we only output its actual contents. + if ($index !== $lastKey) { + throw new \AssertionError( + "Expected unlimited field at $index to be the last one, but the last one is $lastKey" + ); + } + $numOutputElements = count($value); + } else { + // For a capped repeated field (with @Max), we need to output the specified number of elements, such + // that subsequent fields will be at the right place. If this is the last field, the trailing empty + // elements will be trimmed away again by flattenAndTrimEnd() later. + $numOutputElements = $elementDescriptor->repeated; + } + for ($repetition = 0; $repetition < $numOutputElements; ++$repetition) { $serializedElements[$index + $repetition] = static::serializeElement( $value === null || $repetition >= count($value) ? null : $value[$repetition], $elementDescriptor->type, $isSegment); } + $index += $numOutputElements - 1; // The outer loop will increment by 1 as well. } } return $serializedElements; @@ -120,7 +145,7 @@ abstract class Serializer */ private static function serializeElement($value, $type, bool $fullySerialize) { - if (is_string($type)) { + if (is_string($type)) { // Scalar value / DE return static::serializeDataElement($value, $type); } elseif ($type->getName() === Bin::class) { /* @var Bin|null $value */ diff --git a/vendor/nemiah/php-fints/lib/Fhp/UnsupportedException.php b/vendor/nemiah/php-fints/lib/Fhp/UnsupportedException.php old mode 100755 new mode 100644 index 9c1ca4d..2365ff2 --- a/vendor/nemiah/php-fints/lib/Fhp/UnsupportedException.php +++ b/vendor/nemiah/php-fints/lib/Fhp/UnsupportedException.php @@ -7,7 +7,7 @@ namespace Fhp; */ class UnsupportedException 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); } diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Action/SendSEPATransferTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Action/SendSEPATransferTest.php new file mode 100644 index 0000000..03a8151 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Tests/Fhp/Action/SendSEPATransferTest.php @@ -0,0 +1,43 @@ +initDialog(); + $this->expectMessage($this->getSendTransferRequest(), static::SEND_TRANSFER_RESPONSE); + $originalAction = $this->runInitialRequest(); + + // The key behavior we need is that the action produces the same request again after (un)serialization. It is + // not necessary for us to check the field values inside the action directly. + $originalRequest = $originalAction->getNextRequest($this->fints->getBpd(), null); + $this->assertIsArray($originalRequest); + Message::setSegmentNumbers($originalRequest, 42); + + // Sanity-check that the request we're getting is something sensible (not empty string or so). + $serializedRequest = Serializer::serializeSegments($originalRequest); + $this->assertStringContainsString('HKCCS', $serializedRequest); + $this->assertStringContainsString('DE42000000001234567890', $serializedRequest); + + // Do a serialization roundtrip. + $serializedAction = serialize($originalAction); + $unserializedAction = unserialize($serializedAction); + + // Verify that the request is still the same. + $newRequest = $unserializedAction->getNextRequest($this->fints->getBpd(), null); + $this->assertIsArray($newRequest); + Message::setSegmentNumbers($newRequest, 42); + $this->assertEquals($originalRequest, $newRequest); + } +} diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/BaseActionTanSerializationTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/BaseActionTanSerializationTest.php new file mode 100644 index 0000000..a33b2fd --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Tests/Fhp/BaseActionTanSerializationTest.php @@ -0,0 +1,32 @@ +initDialog(); + $this->expectMessage($this->getSendTransferRequest(), static::SEND_TRANSFER_RESPONSE); + $originalAction = $this->runInitialRequest(); + + // Sanity-check that the TAN request is present. + $this->assertNotNull($originalAction->getTanRequest()); + $this->assertNotNull($originalAction->getNeedTanForSegment()); + + // Do a serialization roundtrip. + $serializedAction = serialize($originalAction); + $unserializedAction = unserialize($serializedAction); + + // Verify that the TAN request hasn't changed. + $this->assertEquals($originalAction->getTanRequest(), $unserializedAction->getTanRequest()); + $this->assertEquals($originalAction->getNeedTanForSegment(), $unserializedAction->getNeedTanForSegment()); + } +} diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/BaseActionVopSerializationTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/BaseActionVopSerializationTest.php new file mode 100644 index 0000000..5546c14 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Tests/Fhp/BaseActionVopSerializationTest.php @@ -0,0 +1,58 @@ +initDialog(); + $originalAction = $this->createAction(); + $this->expectMessage(static::SEND_TRANSFER_REQUEST, mb_convert_encoding(static::SEND_TRANSFER_RESPONSE_POLLING_NEEDED, 'ISO-8859-1', 'UTF-8')); + $this->fints->execute($originalAction); + + // Sanity-check that the polling is now expected. + $this->assertNotNull($originalAction->getPollingInfo()); + + // Do a serialization roundtrip. + $serializedAction = serialize($originalAction); + $unserializedAction = unserialize($serializedAction); + + // Verify that the polling info is still the same. + $this->assertEquals($originalAction->getPollingInfo(), $unserializedAction->getPollingInfo()); + } + + /** + * @throws \Throwable + */ + public function testSerializesVopConfirmationRequest() + { + // We piggy-back on the Atruvia integration test to provide an action that has some reasonable data inside and + // has already been executed so that polling is now required. + $this->initDialog(); + $originalAction = $this->createAction(); + $this->expectMessage(static::SEND_TRANSFER_REQUEST, mb_convert_encoding(static::SEND_TRANSFER_RESPONSE_POLLING_NEEDED, 'ISO-8859-1', 'UTF-8')); + $response = static::buildVopReportResponse(static::VOP_REPORT_PARTIAL_MATCH_RESPONSE, static::VOP_REPORT_PARTIAL_MATCH_XML_PAYLOAD); + $this->expectMessage(static::POLL_VOP_REQUEST, $response); + $this->fints->execute($originalAction); + $this->assertTrue($originalAction->needsPollingWait()); + $this->fints->pollAction($originalAction); + + // Sanity-check that the VOP confirmation is now expected. + $this->assertNotNull($originalAction->getVopConfirmationRequest()); + + // Do a serialization roundtrip. + $serializedAction = serialize($originalAction); + $unserializedAction = unserialize($serializedAction); + + // Verify that the polling info is still the same. + $this->assertEquals($originalAction->getVopConfirmationRequest(), $unserializedAction->getVopConfirmationRequest()); + } +} diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/CLILogger.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/CLILogger.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/FinTsPeer.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/FinTsPeer.php old mode 100755 new mode 100644 index 3a6e276..3ee01d5 --- a/vendor/nemiah/php-fints/lib/Tests/Fhp/FinTsPeer.php +++ b/vendor/nemiah/php-fints/lib/Tests/Fhp/FinTsPeer.php @@ -13,32 +13,27 @@ use Fhp\Protocol\ServerException; */ class FinTsPeer extends FinTs { - /** - * @var Connection - */ - public static $mockConnection; + public static ?Connection $mockConnection = null; public function __construct(FinTsOptions $options, ?Credentials $credentials) { parent::__construct($options, $credentials); } - /** {@inheritdoc} */ protected function newConnection(): Connection { return self::$mockConnection; } /** - * {@inheritdoc} * @throws ServerException */ - public function endDialog(bool $isAnonymous = false) // parent::endDialog() is protected + public function endDialog(bool $isAnonymous = false): void // parent::endDialog() is protected { parent::endDialog($isAnonymous); } - public function getDialogId() + public function getDialogId(): ?string { return $this->dialogId; } diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/FinTsTestCase.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/FinTsTestCase.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Atruvia/AtruviaIntegrationTestBase.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Atruvia/AtruviaIntegrationTestBase.php new file mode 100644 index 0000000..efdd455 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Atruvia/AtruviaIntegrationTestBase.php @@ -0,0 +1,90 @@ +expectMessage(static::ANONYMOUS_INIT_REQUEST, mb_convert_encoding(static::ANONYMOUS_INIT_RESPONSE, 'ISO-8859-1', 'UTF-8')); + $this->expectMessage(static::ANONYMOUS_END_REQUEST, mb_convert_encoding(static::ANONYMOUS_END_RESPONSE, 'ISO-8859-1', 'UTF-8')); + + $this->fints->getBpd(); + } + + /** + * Executes dialog synchronization and initialization, so that BPD and UPD are filled. + * @throws \Throwable + */ + protected function initDialog() + { + // We already know the TAN mode, so it will only fetch the BPD (anonymously) to verify it. + $this->expectMessage(static::ANONYMOUS_INIT_REQUEST, mb_convert_encoding(static::ANONYMOUS_INIT_RESPONSE, 'ISO-8859-1', 'UTF-8')); + $this->expectMessage(static::ANONYMOUS_END_REQUEST, mb_convert_encoding(static::ANONYMOUS_END_RESPONSE, 'ISO-8859-1', 'UTF-8')); + + // Then when we initialize a dialog, it's going to request a Kundensystem-ID and UPD. + $this->expectMessage(static::SYNC_REQUEST, mb_convert_encoding(static::SYNC_RESPONSE, 'ISO-8859-1', 'UTF-8')); + $this->expectMessage(static::SYNC_END_REQUEST, mb_convert_encoding(static::SYNC_END_RESPONSE, 'ISO-8859-1', 'UTF-8')); + + // And finally it can initialize the main dialog. + $this->expectMessage(static::INIT_REQUEST, mb_convert_encoding(static::INIT_RESPONSE, 'ISO-8859-1', 'UTF-8')); + + $this->fints->selectTanMode(intval(static::TEST_TAN_MODE)); + $login = $this->fints->login(); + $login->ensureDone(); // No TAN required upon login.*/ + $this->assertAllMessagesSeen(); + } + + protected function getTestAccount(): SEPAAccount + { + $sepaAccount = new SEPAAccount(); + $sepaAccount->setIban('DE00ABCDEFGH1234567890'); + $sepaAccount->setBic('ABCDEFGHIJK'); + $sepaAccount->setAccountNumber('1234567890'); + $sepaAccount->setBlz(self::TEST_BANK_CODE); + return $sepaAccount; + } +} diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Atruvia/SendTransferVoPTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Atruvia/SendTransferVoPTest.php new file mode 100644 index 0000000..19bb3a7 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Atruvia/SendTransferVoPTest.php @@ -0,0 +1,247 @@ +' . "\n" + . 'M12345678902025-10-10T12:52:56+02:00110.00PRIVATE__________________P12345678TRF110.00SEPA
1999-01-01
PRIVATE__________________DE00ABCDEFGH1234567890ABCDEFGHIJKSLEVNOTPROVIDED10.00EmpfängerDE00ABCDEFGH1234567890Testüberweisung
' + ); + + public const SEND_TRANSFER_REQUEST = ( + 'HKCCS:3:1+DE00ABCDEFGH1234567890:ABCDEFGHIJK:1234567890::280:11223344+urn?:iso?:std?:iso?:20022?:tech?:xsd?:pain.001.001.09+@1161@' . + self::XML_PAYLOAD . + "'HKTAN:4:7+4+HKCCS'HKVPP:5:1+urn?:iso?:std?:iso?:20022?:tech?:xsd?:pain.002.001.10'" + ); + public const SEND_TRANSFER_RESPONSE_POLLING_NEEDED = "HIRMG:3:2+3060::Bitte beachten Sie die enthaltenen Warnungen/Hinweise.+3905::Es wurde keine Challenge erzeugt.'HIRMS:4:2:5+3040::Es liegen weitere Informationen vor.:staticscrollref'HIRMS:5:2:4+3945::Freigabe ohne VOP-Bestätigung nicht möglich.'HIVPP:6:1:5+++@36@c0f5c2a4-ebb7-4e72-be44-c68742177a2b+++++2'"; + public const SEND_TRANSFER_RESPONSE_IMMEDIATE_SUCCESS = "HIRMG:3:2+3060::Bitte beachten Sie die enthaltenen Warnungen/Hinweise.+3905::Es wurde keine Challenge erzeugt.'HIRMS:4:2:5+3091::VOP-Ausführungsauftrag nicht benötigt.+0025::Keine Namensabweichung.'HIRMS:5:2:4+3076::Keine starke Authentifizierung erforderlich.'HIVPP:6:1:5+@36@5e3b5c99-df27-4d42-835b-18b35d0c66ff+++urn?:iso?:std?:iso?:20022?:tech?:xsd?:pain.002.001.10'HITAN:6:7:4+4++noref+nochallenge'HIRMS:7:2:3+0020::*SEPA-Einzelüberweisung erfolgreich+0900::Freigabe erfolgreich'"; + + public const POLL_VOP_REQUEST = "HKVPP:3:1+urn?:iso?:std?:iso?:20022?:tech?:xsd?:pain.002.001.10+@36@c0f5c2a4-ebb7-4e72-be44-c68742177a2b++staticscrollref'"; + + public const VOP_REPORT_MATCH_RESPONSE = "HIRMG:3:2+0010::Nachricht entgegengenommen.'HIRMS:4:2:3+0020::Auftrag ausgeführt.+0025::Keine Namensabweichung.'HIVPP:5:1:3+@36@5e3b5c99-df27-4d42-835b-18b35d0c66ff+++urn?:iso?:std?:iso?:20022?:tech?:xsd?:pain.002.001.10'"; + public const VOP_REPORT_MATCH_NO_CONFIRMATION_RESPONSE = "HIRMG:3:2+0010::Nachricht entgegengenommen.'HIRMS:4:2:3+3091::VOP-Ausführungsauftrag nicht benötigt.+0025::Keine Namensabweichung.'HIVPP:5:1:3+@36@5e3b5c99-df27-4d42-835b-18b35d0c66ff+++urn?:iso?:std?:iso?:20022?:tech?:xsd?:pain.002.001.10'HITAN:6:7:5+4++1234567890123456789012345678+Bitte bestätigen Sie den Vorgang in Ihrer SecureGo plus App'"; + public const VOP_REPORT_MATCH_XML_PAYLOAD = "ATRUVIA-20251013-125258-XXXXXXXXXXXXXXXX2025-10-13T11:36:04.201+02:00ABCDEFGHIJKM1234567890pain.001.001.091100.00RCVCRCVC Der von Ihnen eingegebene Name des Zahlungsempfängers stimmt mit dem für diese IBANRCVC hinterlegten Namen bei der Zahlungsempfängerbank überein.RVMC Der von Ihnen eingegebene Name des Zahlungsempfängers stimmt nahezu mit dem für diese IBANRVMC hinterlegten Namen bei der Zahlungsempfängerbank überein. Die Autorisierung der ZahlungRVMC kann dazu führen, dass das Geld auf ein Konto überwiesen wird, dessen Inhaber nichtRVMC der von Ihnen angegebene Empfänger ist. In diesem Fall haften die Zahlungsdienstleister nicht fürRVMC die Folgen der fehlenden Übereinstimmung, insbesondere besteht kein Anspruch auf Rückerstattung.RVNM Der von Ihnen eingegebene Name des Zahlungsempfängers stimmt nicht mit dem für diese IBAN hinter-RVNM legten Namen bei der Zahlungsempfängerbank überein. Bitte prüfen Sie den Empfängernamen. Die Autori-RVNM sierung der Zahlung kann dazu führen, dass das Geld auf ein Konto überwiesen wird, dessen InhaberRVNM nicht der von Ihnen angegebene Empfänger ist. In diesem Fall haften die Zahlungsdienstleister nichtRVNM für die Folgen der fehlenden Übereinstimmung, insbesondere besteht kein Anspruch auf Rückerstattung.RVNA Der von Ihnen eingegebene Name des Zahlungsempfängers konnte nicht mit dem für diese IBAN hinter-RVNA legten Namen bei der Zahlungsempfängerbank abgeglichen werden (z.B. technischer Fehler). Die Autori-RVNA sierung der Zahlung kann dazu führen, dass das Geld auf ein Konto überwiesen wird, dessen InhaberRVNA nicht der von Ihnen angegebene Empfänger ist. In diesem Fall haften die Zahlungsdienstleister nichtRVNA für die Folgen der fehlenden Übereinstimmung, insbesondere besteht kein Anspruch auf Rückerstattung.1RCVC0RVMC0RVNM0RVNA176034816211RCVC0RVMC0RVNM0RVNANOTPROVIDEDRCVCTestempfängerDE00ABCDEFGH1234567890"; + + public const VOP_REPORT_PARTIAL_MATCH_RESPONSE = "HIRMG:3:2+3060::Bitte beachten Sie die enthaltenen Warnungen/Hinweise.'HIRMS:4:2:3+3090::Ergebnis des Namensabgleichs prüfen.'HIVPP:5:1:3+@36@5e3b5c99-df27-4d42-835b-18b35d0c66ff+++urn?:iso?:std?:iso?:20022?:tech?:xsd?:pain.002.001.10+++Bei mindestens einem Zahlungsempfänger stimmt der Name mit dem für diese IBAN bei der Zahlungsempfängerbank hinterlegten Namen nicht oder nur nahezu überein.
Alternativ konnte der Name des Zahlungsempfängers nicht mit dem bei der Zahlungsempfängerbank hinterlegten Namen abgeglichen werden.

Eine nicht mögliche Empfängerüberprüfung kann auftreten, wenn ein technisches Problem vorliegt, die Empfängerbank diesen Service nicht anbietet oder eine Prüfung für das Empfängerkonto nicht möglich ist.

Wichtiger Hinweis?: Die Überweisung wird ohne Korrektur ausgeführt.

Dies kann dazu führen, dass das Geld auf ein Konto überwiesen wird, dessen Inhaber nicht der von Ihnen angegebene Empfänger ist.
In diesem Fall haftet die Bank nicht für die Folgen der fehlenden Übereinstimmung, insbesondere besteht kein Anspruch auf Rückerstattung.

Eine Haftung der an der Ausführung der Überweisung beteiligten Zahlungsdienstleister ist ebenfalls ausgeschlossen.'"; + public const VOP_REPORT_PARTIAL_MATCH_XML_PAYLOAD = "ATRUVIA-20251010-125258-X2025-10-10T12:52:58.283+02:00ABCDEFGHIJKM1234567890pain.001.001.09110.00RVCMRCVC Der von Ihnen eingegebene Name des Zahlungsempfängers stimmt mit dem für diese IBANRCVC hinterlegten Namen bei der Zahlungsempfängerbank überein.RVMC Der von Ihnen eingegebene Name des Zahlungsempfängers stimmt nahezu mit dem für diese IBANRVMC hinterlegten Namen bei der Zahlungsempfängerbank überein. Die Autorisierung der ZahlungRVMC kann dazu führen, dass das Geld auf ein Konto überwiesen wird, dessen Inhaber nichtRVMC der von Ihnen angegebene Empfänger ist. In diesem Fall haften die Zahlungsdienstleister nicht fürRVMC die Folgen der fehlenden Übereinstimmung, insbesondere besteht kein Anspruch auf Rückerstattung.RVNM Der von Ihnen eingegebene Name des Zahlungsempfängers stimmt nicht mit dem für diese IBAN hinter-RVNM legten Namen bei der Zahlungsempfängerbank überein. Bitte prüfen Sie den Empfängernamen. Die Autori-RVNM sierung der Zahlung kann dazu führen, dass das Geld auf ein Konto überwiesen wird, dessen InhaberRVNM nicht der von Ihnen angegebene Empfänger ist. In diesem Fall haften die Zahlungsdienstleister nichtRVNM für die Folgen der fehlenden Übereinstimmung, insbesondere besteht kein Anspruch auf Rückerstattung.RVNA Der von Ihnen eingegebene Name des Zahlungsempfängers konnte nicht mit dem für diese IBAN hinter-RVNA legten Namen bei der Zahlungsempfängerbank abgeglichen werden (z.B. technischer Fehler). Die Autori-RVNA sierung der Zahlung kann dazu führen, dass das Geld auf ein Konto überwiesen wird, dessen InhaberRVNA nicht der von Ihnen angegebene Empfänger ist. In diesem Fall haften die Zahlungsdienstleister nichtRVNA für die Folgen der fehlenden Übereinstimmung, insbesondere besteht kein Anspruch auf Rückerstattung.0RCVC0RVMC1RVNM0RVNA176009357610RCVC0RVMC1RVNM0RVNANOTPROVIDEDRVNMTestempfängerDE00ABCDEFGH1234567890"; + + public const CONFIRM_VOP_REQUEST = ( + 'HKCCS:3:1+DE00ABCDEFGH1234567890:ABCDEFGHIJK:1234567890::280:11223344+urn?:iso?:std?:iso?:20022?:tech?:xsd?:pain.001.001.09+@1161@' + . self::XML_PAYLOAD + . "'HKVPA:4:1+@36@5e3b5c99-df27-4d42-835b-18b35d0c66ff'HKTAN:5:7+4+HKCCS'" + ); + public const CONFIRM_VOP_RESPONSE = "HIRMG:3:2+3060::Bitte beachten Sie die enthaltenen Warnungen/Hinweise.'HIRMS:4:2:4+0020::Ausführungsbestätigung nach Namensabgleich erhalten.'HIRMS:5:2:5+3955::Sicherheitsfreigabe erfolgt über anderen Kanal.'HITAN:6:7:5+4++1234567890123456789012345678+Bitte bestätigen Sie den Vorgang in Ihrer SecureGo plus App'"; + + public const CHECK_DECOUPLED_SUBMISSION_REQUEST = "HKTAN:3:7+S++++1234567890123456789012345678+N'"; + public const CHECK_DECOUPLED_SUBMISSION_RESPONSE = "HIRMG:3:2+0010::Nachricht entgegengenommen.'HIRMS:4:2:3+0020::*SEPA-Einzelüberweisung erfolgreich+0900::Freigabe erfolgreich'HITAN:5:7:3+S++1234567890123456789012345678'"; + + /** + * @throws \Throwable + */ + public function testVopWithResultMatchButConfirmationRequired(): void + { + $this->initDialog(); + $action = $this->createAction(); + + // We send the transfer and the bank asks to wait while VOP is happening. + $this->expectMessage(static::SEND_TRANSFER_REQUEST, mb_convert_encoding(static::SEND_TRANSFER_RESPONSE_POLLING_NEEDED, 'ISO-8859-1', 'UTF-8')); + $this->fints->execute($action); + $this->assertTrue($action->needsPollingWait()); + $this->assertFalse($action->needsVopConfirmation()); + $this->assertFalse($action->needsTan()); + $this->assertFalse($action->isDone()); + $this->assertEquals(2, $action->getPollingInfo()->getNextAttemptInSeconds()); + + // We poll the bank for the first and only time, now the VOP process is done, the result is available, and it's + // a match (CompletedFullMatch). But the bank still asks for the VOP confirmation. + $response = static::buildVopReportResponse(static::VOP_REPORT_MATCH_RESPONSE, static::VOP_REPORT_MATCH_XML_PAYLOAD); + $this->expectMessage(static::POLL_VOP_REQUEST, $response); + $this->fints->pollAction($action); + $this->assertFalse($action->needsPollingWait()); + $this->assertTrue($action->needsVopConfirmation()); + $this->assertFalse($action->needsTan()); + $this->assertFalse($action->isDone()); + $this->assertEquals( + VopVerificationResult::CompletedFullMatch, + $action->getVopConfirmationRequest()->getVerificationResult() + ); + + // We confirm to the bank that it's okay to proceed, the bank asks for decoupled 2FA authentication. + $this->expectMessage(static::CONFIRM_VOP_REQUEST, mb_convert_encoding(static::CONFIRM_VOP_RESPONSE, 'ISO-8859-1', 'UTF-8')); + $this->fints->confirmVop($action); + $this->assertFalse($action->needsPollingWait()); + $this->assertFalse($action->needsVopConfirmation()); + $this->assertTrue($action->needsTan()); + $this->assertFalse($action->isDone()); + $this->assertEquals( + 'Bitte bestätigen Sie den Vorgang in Ihrer SecureGo plus App', + $action->getTanRequest()->getChallenge() + ); + + // After having completed the 2FA on the other device (not shown in this unit test), we ask the bank again, and + // it confirms that the transfer was executed. + $this->expectMessage(static::CHECK_DECOUPLED_SUBMISSION_REQUEST, mb_convert_encoding(static::CHECK_DECOUPLED_SUBMISSION_RESPONSE, 'ISO-8859-1', 'UTF-8')); + $this->fints->checkDecoupledSubmission($action); + $this->assertFalse($action->needsPollingWait()); + $this->assertFalse($action->needsVopConfirmation()); + $this->assertFalse($action->needsTan()); + $this->assertTrue($action->isDone()); + + $action->ensureDone(); + } + + /** + * @throws \Throwable + */ + public function testVopWithResultPartialMatch(): void + { + $this->initDialog(); + $action = $this->createAction(); + + // We send the transfer and the bank asks to wait while VOP is happening. + $this->expectMessage(static::SEND_TRANSFER_REQUEST, mb_convert_encoding(static::SEND_TRANSFER_RESPONSE_POLLING_NEEDED, 'ISO-8859-1', 'UTF-8')); + $this->fints->execute($action); + $this->assertTrue($action->needsPollingWait()); + $this->assertFalse($action->needsVopConfirmation()); + $this->assertFalse($action->needsTan()); + $this->assertFalse($action->isDone()); + $this->assertEquals(2, $action->getPollingInfo()->getNextAttemptInSeconds()); + + // We poll the bank for the first and only time, now the VOP process is done and the VOP result is available, + // but the payee didn't match, and so we're being asked to confirm. + $response = static::buildVopReportResponse(static::VOP_REPORT_PARTIAL_MATCH_RESPONSE, static::VOP_REPORT_PARTIAL_MATCH_XML_PAYLOAD); + $this->expectMessage(static::POLL_VOP_REQUEST, $response); + $this->fints->pollAction($action); + $this->assertFalse($action->needsPollingWait()); + $this->assertTrue($action->needsVopConfirmation()); + $this->assertFalse($action->needsTan()); + $this->assertFalse($action->isDone()); + $this->assertEquals( + VopVerificationResult::CompletedNoMatch, + $action->getVopConfirmationRequest()->getVerificationResult() + ); + + // We confirm to the bank that it's okay to proceed, the bank asks for decoupled 2FA authentication. + $this->expectMessage(static::CONFIRM_VOP_REQUEST, mb_convert_encoding(static::CONFIRM_VOP_RESPONSE, 'ISO-8859-1', 'UTF-8')); + $this->fints->confirmVop($action); + $this->assertFalse($action->needsPollingWait()); + $this->assertFalse($action->needsVopConfirmation()); + $this->assertTrue($action->needsTan()); + $this->assertFalse($action->isDone()); + $this->assertEquals( + 'Bitte bestätigen Sie den Vorgang in Ihrer SecureGo plus App', + $action->getTanRequest()->getChallenge() + ); + + // After having completed the 2FA on the other device (not shown in this unit test), we ask the bank again, and + // it confirms that the transfer was executed. + $this->expectMessage(static::CHECK_DECOUPLED_SUBMISSION_REQUEST, mb_convert_encoding(static::CHECK_DECOUPLED_SUBMISSION_RESPONSE, 'ISO-8859-1', 'UTF-8')); + $this->fints->checkDecoupledSubmission($action); + $this->assertFalse($action->needsPollingWait()); + $this->assertFalse($action->needsVopConfirmation()); + $this->assertFalse($action->needsTan()); + $this->assertTrue($action->isDone()); + + $action->ensureDone(); + } + + /** + * This is a hypothetical test case in the sense that it wasn't recorded based on real traffic with the bank, but + * constructed based on what the specification has to say. + * @see FinTS_3.0_Messages_Geschaeftsvorfaelle_VOP_1.01_2025_06_27_FV.pdf (E.8.1.1.1 and exclude red part). + * @throws \Throwable + */ + public function testVopWithResultMatchWithoutConfirmation(): void + { + $this->initDialog(); + $action = $this->createAction(); + + // We send the transfer and the bank asks to wait while VOP is happening. + $this->expectMessage(static::SEND_TRANSFER_REQUEST, mb_convert_encoding(static::SEND_TRANSFER_RESPONSE_POLLING_NEEDED, 'ISO-8859-1', 'UTF-8')); + $this->fints->execute($action); + $this->assertTrue($action->needsPollingWait()); + $this->assertFalse($action->needsVopConfirmation()); + $this->assertFalse($action->needsTan()); + $this->assertFalse($action->isDone()); + $this->assertEquals(2, $action->getPollingInfo()->getNextAttemptInSeconds()); + + // We poll the bank for the first and only time, now the VOP process is done, the result is available, and it's + // a match (CompletedFullMatch). The bank does not want a VOP confirmation (as indicated by code 3091), so we + // move straight on to 2FA authentication. + $response = static::buildVopReportResponse( + static::VOP_REPORT_MATCH_NO_CONFIRMATION_RESPONSE, + static::VOP_REPORT_MATCH_XML_PAYLOAD + ); + $this->expectMessage(static::POLL_VOP_REQUEST, $response); + $this->fints->pollAction($action); + $this->assertFalse($action->needsPollingWait()); + $this->assertFalse($action->needsVopConfirmation()); + $this->assertTrue($action->needsTan()); + $this->assertFalse($action->isDone()); + // Note: We currently lack an API for applications to retrieve the CompletedFullMatch result in this case, + // because the VOP check itself is no longer actionable. + $this->assertEquals( + 'Bitte bestätigen Sie den Vorgang in Ihrer SecureGo plus App', + $action->getTanRequest()->getChallenge() + ); + + // After having completed the 2FA on the other device (not shown in this unit test), we ask the bank again, and + // it confirms that the transfer was executed. + $this->expectMessage(static::CHECK_DECOUPLED_SUBMISSION_REQUEST, mb_convert_encoding(static::CHECK_DECOUPLED_SUBMISSION_RESPONSE, 'ISO-8859-1', 'UTF-8')); + $this->fints->checkDecoupledSubmission($action); + $this->assertFalse($action->needsPollingWait()); + $this->assertFalse($action->needsVopConfirmation()); + $this->assertFalse($action->needsTan()); + $this->assertTrue($action->isDone()); + + $action->ensureDone(); + } + + /** + * This is a hypothetical test case in the sense that it wasn't recorded based on real traffic with the bank, but + * constructed based on what the specification has to say. + * @see FinTS_3.0_Messages_Geschaeftsvorfaelle_VOP_1.01_2025_06_27_FV.pdf (E.8.1 bullet point 2.). + * @throws \Throwable + */ + public function testVopWithResultImmediateSuccess(): void + { + $this->initDialog(); + $action = $this->createAction(); + + // We send the transfer and the bank asks to wait while VOP is happening. + $this->expectMessage(static::SEND_TRANSFER_REQUEST, mb_convert_encoding(static::SEND_TRANSFER_RESPONSE_IMMEDIATE_SUCCESS, 'ISO-8859-1', 'UTF-8')); + $this->fints->execute($action); + $this->assertFalse($action->needsPollingWait()); + $this->assertFalse($action->needsVopConfirmation()); + $this->assertFalse($action->needsTan()); + $this->assertTrue($action->isDone()); + + $action->ensureDone(); + } + + protected function createAction(): SendSEPATransfer + { + return SendSEPATransfer::create($this->getTestAccount(), self::XML_PAYLOAD); + } + + protected static function buildVopReportResponse( + string $outerFintsMessageInUtf8, + string $innerXmlInUtf8, + ): string { + $segments = Parser::parseSegments(mb_convert_encoding($outerFintsMessageInUtf8, 'ISO-8859-1', 'UTF-8')); + foreach ($segments as $segment) { + if ($segment instanceof HIVPPv1) { + $segment->paymentStatusReport = new Bin($innerXmlInUtf8); + } + } + return Serializer::serializeSegments($segments); + } +} diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Consors/ConsorsIntegrationTestBase.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Consors/ConsorsIntegrationTestBase.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Consors/GetBPDTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Consors/GetBPDTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Consors/GetSEPAAccountsTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Consors/GetSEPAAccountsTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Consors/GetStatementOfAccountTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Consors/GetStatementOfAccountTest.php old mode 100755 new mode 100644 index 466f554..a492764 --- a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Consors/GetStatementOfAccountTest.php +++ b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Consors/GetStatementOfAccountTest.php @@ -10,15 +10,17 @@ class GetStatementOfAccountTest extends ConsorsIntegrationTestBase public const GET_STATEMENT_REQUEST = "HKKAZ:3:7+DExxABCDEFGH1234567890:CSDBDE71XXX:1234567890::280:50220500+N+20190601+20190922'HKTAN:4:6+4+HKKAZ'"; // Note: Consorsbank weirdly returns November statements even when only up to September was requested. - public const GET_STATEMENT_RESPONSE = "HIRMG:2:2:+3060::Teilweise liegen Warnungen/Hinweise vor.'HIRMS:3:2:3+0020::Der Auftrag wurde ausgefuhrt.+3076::Keine starke Authentifizierung erforderlich.+3997::Der Auftrag wurde nur teilweise ausgefuhrt.'" - . "HIKAZ:4:7:3+@1034@\r\n" - . ":20:0\r\n:21:NONREF\r\n:25:50220500/123456789\r\n:28C:0/7\r\n:60M:C191118EUR950,59\r\n" - . ":61:1911181118D2,8N008NONREF\r\n:86:008?00Dauerauftrag?20EREF+NOTPROVIDED ?21 ?\r\n22KREF+NONREF?23SVWZ+XY?30BICBICBICBI?31DExx444444444444444444?32\r\nMax Mustermannig\r\n:62M:C191118EUR947,79\r\n-\r\n" - . ":20:0\r\n:21:NONREF\r\n:25:50220500/123456789\r\n:28C:0/8\r\n:60M:C191120EUR947,79\r\n" - . ":61:1911201120D11,3N005NONREF\r\n:86:005?00Lastschrift (Einzugsermächtigung)?20EREF+ZAA0987654321 \r\n ?21 ?22KREF+NONREF?23SVWZ+LogPay OnlineTicket i.?\r\n24A.v. Irgendeine Firma und S?25oehne AG. Ihre Kundenn r. 2?26019\r\n999999999?30BICBICBI?31DExx555555555555555555?32LOGPAY FINANCIAL \r\nSERVICES G?33MBH\r\n" - . ":61:1911201120D15,5N005NONREF\r\n:86:005?00Lastschrift (Einzugsermächtigung)?20EREF+ZAA0123456789 \r\n ?21 ?22KREF+NONREF?23SVWZ+LogPay OnlineTicket i.?\r\n24A.v. Irgendeine Firma und S?25oehne AG. Ihre Kundenn r. 2?26019\r\n999999999?30BICBICBI?31DExx555555555555555555?32LOGPAY FINANCIAL \r\nSERVICES G?33MBH\r\n" - . ":62F:C191120EUR920,99\r\n-'" - . "HITAN:5:6:4+4++noref+nochallenge'"; + public const GET_STATEMENT_RESPONSE = ( + "HIRMG:2:2:+3060::Teilweise liegen Warnungen/Hinweise vor.'HIRMS:3:2:3+0020::Der Auftrag wurde ausgefuhrt.+3076::Keine starke Authentifizierung erforderlich.+3997::Der Auftrag wurde nur teilweise ausgefuhrt.'" + . "HIKAZ:4:7:3+@1034@\r\n" + . ":20:0\r\n:21:NONREF\r\n:25:50220500/123456789\r\n:28C:0/7\r\n:60M:C191118EUR950,59\r\n" + . ":61:1911181118D2,8N008NONREF\r\n:86:008?00Dauerauftrag?20EREF+NOTPROVIDED ?21 ?\r\n22KREF+NONREF?23SVWZ+XY?30BICBICBICBI?31DExx444444444444444444?32\r\nMax Mustermannig\r\n:62M:C191118EUR947,79\r\n-\r\n" + . ":20:0\r\n:21:NONREF\r\n:25:50220500/123456789\r\n:28C:0/8\r\n:60M:C191120EUR947,79\r\n" + . ":61:1911201120D11,3N005NONREF\r\n:86:005?00Lastschrift (Einzugsermächtigung)?20EREF+ZAA0987654321 \r\n ?21 ?22KREF+NONREF?23SVWZ+LogPay OnlineTicket i.?\r\n24A.v. Irgendeine Firma und S?25oehne AG. Ihre Kundenn r. 2?26019\r\n999999999?30BICBICBI?31DExx555555555555555555?32LOGPAY FINANCIAL \r\nSERVICES G?33MBH\r\n" + . ":61:1911201120D15,5N005NONREF\r\n:86:005?00Lastschrift (Einzugsermächtigung)?20EREF+ZAA0123456789 \r\n ?21 ?22KREF+NONREF?23SVWZ+LogPay OnlineTicket i.?\r\n24A.v. Irgendeine Firma und S?25oehne AG. Ihre Kundenn r. 2?26019\r\n999999999?30BICBICBI?31DExx555555555555555555?32LOGPAY FINANCIAL \r\nSERVICES G?33MBH\r\n" + . ":62F:C191120EUR920,99\r\n-'" + . "HITAN:5:6:4+4++noref+nochallenge'" + ); // Note: There is no HIKAZ at all in this response, but it's still valid. public const GET_STATEMENT_EMPTY_RESPONSE = "HIRMG:2:2:+3060::Teilweise liegen Warnungen/Hinweise vor.'HIRMS:3:2:3+3010::Keine Umsatze gefunden+3076::Keine starke Authentifizierung erforderlich.'HITAN:4:6:4+4++noref+nochallenge'"; diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Consors/InitEndDialogTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Consors/InitEndDialogTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/DKB/DKBIntegrationTestBase.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/DKB/DKBIntegrationTestBase.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/DKB/GetBalanceTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/DKB/GetBalanceTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/DKB/GetSEPAAccountsTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/DKB/GetSEPAAccountsTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/DKB/GetStatementOfAccountTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/DKB/GetStatementOfAccountTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/DKB/InitEndDialogTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/DKB/InitEndDialogTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/DKB/SendSEPATransferTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/DKB/SendSEPATransferTest.php old mode 100755 new mode 100644 index b409aee..cdaa011 --- a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/DKB/SendSEPATransferTest.php +++ b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/DKB/SendSEPATransferTest.php @@ -81,7 +81,7 @@ class SendSEPATransferTest extends DKBIntegrationTestBase public const SEND_TAN_REQUEST = "HNHBK:1:3+000000000425+300+FAKEDIALOGIDabcdefghijklmnopqr+3'HNVSK:998:3+PIN:2+998+1+1::FAKEKUNDENSYSTEMIDabcdefghij+1:20190102:030405+2:2:13:@8@00000000:5:1+280:12030000:test?@user:V:0:0+0'HNVSD:999:1+@206@HNSHK:2:4+PIN:2+921+9999999+1+1+1::FAKEKUNDENSYSTEMIDabcdefghij+1+1:20190102:030405+1:999:1+6:10:19+280:12030000:test?@user:S:0:0'HKTAN:3:6+2++++2472-12-07-21.27.57.456789+N'HNSHA:4:2+9999999++12345:666555''HNHBS:5:1+3'"; public const SEND_TAN_RESPONSE = "HIRMG:3:2+0010::Nachricht entgegengenommen.'HIRMS:4:2:3+0010::Der Auftrag wurde entgegengenommen.'HITAN:5:6:3+2++2472-12-07-21.27.57.456789'"; - private function getSendTransferRequest(): string + protected function getSendTransferRequest(): string { // Note: strlen() is computed instead of hard-coded because it depends on the indentation in this file, which // may be changed by linters and other tools, and because it contains line breaks, which are different depending @@ -93,7 +93,7 @@ class SendSEPATransferTest extends DKBIntegrationTestBase /** * @throws \Throwable */ - private function runInitialRequest(): SendSEPATransfer + protected function runInitialRequest(): SendSEPATransfer { $sendTransfer = SendSEPATransfer::create($this->getTestAccount(), static::PAIN_MESSAGE); $this->fints->execute($sendTransfer); diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/GLS/GLSIntegrationTestBase.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/GLS/GLSIntegrationTestBase.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/GLS/GetStatementOfAccountXMLTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/GLS/GetStatementOfAccountXMLTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/GLS/InitEndDialogTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/GLS/InitEndDialogTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/IngDiba/GetSEPAAccountsTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/IngDiba/GetSEPAAccountsTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/IngDiba/GetStatementOfAccountTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/IngDiba/GetStatementOfAccountTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/IngDiba/IngDibaIntegrationTestBase.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/IngDiba/IngDibaIntegrationTestBase.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/IngDiba/InitDialogWithBlockedPinTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/IngDiba/InitDialogWithBlockedPinTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/IngDiba/InitEndDialogTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/IngDiba/InitEndDialogTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/InitializationErrorTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/InitializationErrorTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/KSK/Biberach/GetBPDTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/KSK/Biberach/GetBPDTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/KSK/Biberach/KskBiberachIntegrationTestBase.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/KSK/Biberach/KskBiberachIntegrationTestBase.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/KSK/InitDialogWithBlockedPinTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/KSK/InitDialogWithBlockedPinTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/KSK/KSKIntegrationTestBase.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/KSK/KSKIntegrationTestBase.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Postbank/GetSEPAAccountsTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Postbank/GetSEPAAccountsTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Postbank/InitDialogWithBlockedPinTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Postbank/InitDialogWithBlockedPinTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Postbank/InitEndDialogTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Postbank/InitEndDialogTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Postbank/PostbankIntegrationTestBase.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Integration/Postbank/PostbankIntegrationTestBase.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Model/FlickerTan/TanRequestChallengeFlickerTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Model/FlickerTan/TanRequestChallengeFlickerTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Options/SanitizingLoggerTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Options/SanitizingLoggerTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Protocol/DialogInitializationTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Protocol/DialogInitializationTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Protocol/DialogInitializationTestModel.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Protocol/DialogInitializationTestModel.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Protocol/ServerExceptionTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Protocol/ServerExceptionTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/AnonymousSegmentTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/AnonymousSegmentTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/Common/TspTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/Common/TspTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/FindRueckmeldungTraitTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/FindRueckmeldungTraitTest.php new file mode 100644 index 0000000..3b9ce9a --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/FindRueckmeldungTraitTest.php @@ -0,0 +1,62 @@ +testMessage = Message::createPlainMessage( + MessageBuilder::create() + ->add(Parser::parseSegments(self::TEST_RESPONSE)) + ); + } + + public function testFindRueckmeldungFound() + { + $this->assertEquals('Angemeldet.', $this->testMessage->findRueckmeldung(20)->rueckmeldungstext); + $this->assertEquals([900], $this->testMessage->findRueckmeldung(3920)->rueckmeldungsparameter); + } + + public function testFindRueckmeldungNotFound() + { + $this->assertNull($this->testMessage->findRueckmeldung(42)); + } + + public function testFindRueckmeldungen() + { + $this->assertCount(3, $this->testMessage->findRueckmeldungen(20)); + $this->assertCount(1, $this->testMessage->findRueckmeldungen(3920)); + $this->assertCount(0, $this->testMessage->findRueckmeldungen(42)); + } + + public function testGetAllRueckmeldungen() + { + /** @var HIRMGv2 $hirmg */ + $hirmg = $this->testMessage->findSegmentByNumber(2); + $this->assertCount(1, $hirmg->getAllRueckmeldungen()); + + /** @var HIRMSv2 $hirms */ + $hirms = $this->testMessage->findSegmentByNumber(3); + $this->assertCount(3, $hirms->getAllRueckmeldungen()); + } + + public function testFindRueckmeldungscodesForReferenceSegment() + { + $this->assertEquals([20, 3076, 901], $this->testMessage->findRueckmeldungscodesForReferenceSegment(3)); + $this->assertEquals([20, 3920], $this->testMessage->findRueckmeldungscodesForReferenceSegment(4)); + $this->assertEquals([20], $this->testMessage->findRueckmeldungscodesForReferenceSegment(6)); + } +} diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HICAZTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HICAZTest.php old mode 100755 new mode 100644 index 77ecf67..54e61d9 --- a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HICAZTest.php +++ b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HICAZTest.php @@ -13,59 +13,69 @@ class HICAZTest extends \PHPUnit\Framework\TestCase // Inside segemnts several XMLs can be present, seperated by ":" private const HICAZ_TEST_START = 'HICAZ:5:1:3+DE06940594210000027227:TESTDETT421:::280:+urn?:iso?:std?:iso?:20022?:tech?:xsd?:camt.052.001.02+'; - private const SAMPLE_XML_DOC1 = '' . - '' . - 'camt52_20131118101510__ONLINEBA' . - '2013-11-18T10:15:10+01:001true' . - 'camt052_ONLINEBA' . - 'BOOK' . - 'BOOK' . - ''; - private const SAMPLE_XML_DOC2 = '' . - '' . - 'camt52_20131118101510__ONLINEBA' . - '2013-11-18T10:15:10+01:001true' . - 'camt052_ONLINEBA' . - 'BOOK' . - 'BOOK' . - 'BOOK' . - 'BOOK' . - ''; - private const SAMPLE_XML_DOC3 = '' . - '' . - 'camt52_20131118101510__ONLINEBA' . - '2013-11-18T10:15:10+01:001true' . - 'camt052_ONLINEBA' . - 'PDNG' . - ''; + private const SAMPLE_XML_DOC1 = ( + '' . + '' . + 'camt52_20131118101510__ONLINEBA' . + '2013-11-18T10:15:10+01:001true' . + 'camt052_ONLINEBA' . + 'BOOK' . + 'BOOK' . + '' + ); + private const SAMPLE_XML_DOC2 = ( + '' . + '' . + 'camt52_20131118101510__ONLINEBA' . + '2013-11-18T10:15:10+01:001true' . + 'camt052_ONLINEBA' . + 'BOOK' . + 'BOOK' . + 'BOOK' . + 'BOOK' . + '' + ); + private const SAMPLE_XML_DOC3 = ( + '' . + '' . + 'camt52_20131118101510__ONLINEBA' . + '2013-11-18T10:15:10+01:001true' . + 'camt052_ONLINEBA' . + 'PDNG' . + '' + ); public function testHICAZparse() { // First example: two XMLs seperated by ":" - both are gebuchteUmsaetze - $hicaz1 = HICAZv1::parse(static::HICAZ_TEST_START . - '@' . strlen(static::SAMPLE_XML_DOC1) . '@' . - static::SAMPLE_XML_DOC1 . - ':' . - '@' . strlen(static::SAMPLE_XML_DOC2) . '@' . - static::SAMPLE_XML_DOC2 . - "'"); + $hicaz1 = HICAZv1::parse( + static::HICAZ_TEST_START . + '@' . strlen(static::SAMPLE_XML_DOC1) . '@' . + static::SAMPLE_XML_DOC1 . + ':' . + '@' . strlen(static::SAMPLE_XML_DOC2) . '@' . + static::SAMPLE_XML_DOC2 . + "'" + ); $this->assertEquals([static::SAMPLE_XML_DOC1, static::SAMPLE_XML_DOC2], $hicaz1->getGebuchteUmsaetze()); // Second example: two areas seperated by +, first area has a group of two XMLs seperated by : - $hicaz2 = HICAZv1::parse(static::HICAZ_TEST_START . - '@' . strlen(static::SAMPLE_XML_DOC1) . '@' . - static::SAMPLE_XML_DOC1 . - ':@' . strlen(static::SAMPLE_XML_DOC2) . '@' . - static::SAMPLE_XML_DOC2 . - '+@' . strlen(static::SAMPLE_XML_DOC3) . '@' . - static::SAMPLE_XML_DOC3 . - "'"); + $hicaz2 = HICAZv1::parse( + static::HICAZ_TEST_START . + '@' . strlen(static::SAMPLE_XML_DOC1) . '@' . + static::SAMPLE_XML_DOC1 . + ':@' . strlen(static::SAMPLE_XML_DOC2) . '@' . + static::SAMPLE_XML_DOC2 . + '+@' . strlen(static::SAMPLE_XML_DOC3) . '@' . + static::SAMPLE_XML_DOC3 . + "'" + ); $this->assertEquals([static::SAMPLE_XML_DOC1, static::SAMPLE_XML_DOC2], $hicaz2->getGebuchteUmsaetze()); $this->assertEquals(static::SAMPLE_XML_DOC3, diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HISALTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HISALTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HITABTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HITABTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HITANSTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HITANSTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HIUPATest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HIUPATest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HIUPDTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HIUPDTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HIVPPSTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HIVPPSTest.php new file mode 100644 index 0000000..54cbf19 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HIVPPSTest.php @@ -0,0 +1,44 @@ +hivpps = HIVPPSv1::createEmpty(); + $this->hivpps->setSegmentNumber(42); + $this->hivpps->maximaleAnzahlAuftraege = 43; + $this->hivpps->anzahlSignaturenMindestens = 44; + $this->hivpps->sicherheitsklasse = 45; + $this->hivpps->parameter = new ParameterNamensabgleichPruefauftragV1(); + $this->hivpps->parameter->maximaleAnzahlCreditTransferTransactionInformationOptIn = 1; + $this->hivpps->parameter->aufklaerungstextStrukturiert = true; + $this->hivpps->parameter->artDerLieferungPaymentStatusReport = 'Art'; + $this->hivpps->parameter->sammelzahlungenMitEinemAuftragErlaubt = false; + $this->hivpps->parameter->eingabeAnzahlEintraegeErlaubt = false; + $this->hivpps->parameter->unterstuetztePaymentStatusReportDatenformate = 'Test'; + } + + public function testPopulatedArray() + { + $this->hivpps->parameter->vopPflichtigerZahlungsverkehrsauftrag = ['HKFOO', 'HKBAR']; + + $serialized = $this->hivpps->serialize(); + $this->assertEquals("HIVPPS:42:1+43+44+45+1:J:Art:N:N:Test:HKFOO:HKBAR'", $serialized); + + /** @var HIVPPSv1 $parsed */ + $parsed = Parser::parseSegment($serialized, HIVPPSv1::class); + $this->assertEquals(['HKFOO', 'HKBAR'], $parsed->parameter->vopPflichtigerZahlungsverkehrsauftrag); + } +} diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HKCCSTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HKCCSTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HKSPATest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HKSPATest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HKVPPTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HKVPPTest.php new file mode 100644 index 0000000..99ab281 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HKVPPTest.php @@ -0,0 +1,28 @@ +setSegmentNumber(42); + $hkvpp->unterstuetztePaymentStatusReports->paymentStatusReportDescriptor = ['A', 'B', 'C']; + + $serialized = $hkvpp->serialize(); + $this->assertEquals("HKVPP:42:1+A:B:C'", $serialized); + + /** @var HKVPPv1 $hkvpp */ + $hkvpp = Parser::parseSegment($serialized, HKVPPv1::class); + $this->assertEquals(42, $hkvpp->getSegmentNumber()); + $this->assertEquals(['A', 'B', 'C'], $hkvpp->unterstuetztePaymentStatusReports->paymentStatusReportDescriptor); + } +} diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HNVSDTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HNVSDTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HNVSKTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/HNVSKTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/SegmentComparator.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/SegmentComparator.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/UpdSerializationTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/UpdSerializationTest.php new file mode 100644 index 0000000..8df47a6 --- /dev/null +++ b/vendor/nemiah/php-fints/lib/Tests/Fhp/Segment/UpdSerializationTest.php @@ -0,0 +1,33 @@ +assertEquals(static::HIUPD, Serializer::serializeSegment($hiupd)); + } + + public function testNativePhpSerialization(): void + { + /** @var HIUPDv6 $hiupd */ + $hiupd = Parser::parseSegment(static::HIUPD, HIUPDv6::class); + $before = $hiupd->getErlaubteGeschaeftsvorfaelle(); + + /** @var HIUPDv6 $hiupd */ + $hiupd = unserialize(serialize($hiupd)); + $after = $hiupd->getErlaubteGeschaeftsvorfaelle(); + + $this->assertEquals($before, $after); + } +} diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Syntax/BinTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Syntax/BinTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Syntax/ParserTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Syntax/ParserTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Syntax/SerializerTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Syntax/SerializerTest.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/Fhp/Unit/SendSEPADirectDebitTest.php b/vendor/nemiah/php-fints/lib/Tests/Fhp/Unit/SendSEPADirectDebitTest.php old mode 100755 new mode 100644 index 96d7d82..f92c4a8 --- a/vendor/nemiah/php-fints/lib/Tests/Fhp/Unit/SendSEPADirectDebitTest.php +++ b/vendor/nemiah/php-fints/lib/Tests/Fhp/Unit/SendSEPADirectDebitTest.php @@ -2,7 +2,6 @@ namespace Tests\Fhp\Unit; - use Fhp\Action\SendSEPADirectDebit; use Fhp\Model\SEPAAccount; use Tests\Fhp\FinTsTestCase; diff --git a/vendor/nemiah/php-fints/lib/Tests/phpunit_bootstrap.php b/vendor/nemiah/php-fints/lib/Tests/phpunit_bootstrap.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/lib/Tests/resources/pain.008.002.02.xml b/vendor/nemiah/php-fints/lib/Tests/resources/pain.008.002.02.xml old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/phpunit.xml.dist b/vendor/nemiah/php-fints/phpunit.xml.dist old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/prettify_message.php b/vendor/nemiah/php-fints/prettify_message.php old mode 100755 new mode 100644 diff --git a/vendor/nemiah/php-fints/prettify_segment.php b/vendor/nemiah/php-fints/prettify_segment.php old mode 100755 new mode 100644