diff --git a/.gitignore b/.gitignore index bc959c5..6fa6728 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /composer.lock /phpunit.xml /vendor +.idea diff --git a/.travis.yml b/.travis.yml index 39875eb..1e6d3a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ php: - 7.1 - 7.2 - 7.3 + - 7.4 before_script: - cp phpunit.xml.dist phpunit.xml diff --git a/LICENCE.powercloud.txt b/LICENCE.powercloud.txt new file mode 100644 index 0000000..6dd3b4c --- /dev/null +++ b/LICENCE.powercloud.txt @@ -0,0 +1,20 @@ +Copyright (c) 2020 Dominic Richter - Powercloud Gmbh (https://www.powercloud.de) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 258f8e5..ff691d5 100644 --- a/README.md +++ b/README.md @@ -66,16 +66,42 @@ Properties that are not supplied will be `null`. * `getDescription()` Description text * `getValueDate()` Date of the transaction as a `\DateTime` * `getBookDate()` Date the transaction was booked as a `\DateTime` + * `getCode()` Get Code for this transaction + * `getRef()` Get Ref for this transaction + * `getBankRef()` Get BankRef for this transaction + * `getGVC()` Get GVC for this transaction + * `getTxText()` Get txText for this transaction + * `getPrimanota()` Get primanota for this transaction + * `getExtCode()` Get extCode for this transaction + * `getEref()` Get ERef for this transaction + * `getBIC()` Get BIC for this transaction + * `getIBAN()` Get IBAN for this transaction + * `getAccountHolder()` Get Account Holder for this transaction + * `getKref()` Get Kref for this transaction + * `getMref()` Get Mref for this transaction + * `getCred()` Get Cred for this transaction + * `getSvwz()` Get Svwz for this transaction ## Supported banks Currencly there are statement parsers for the following banks: -* ABN-AMRO -* ING -* Rabobank -* SNS -* Triodos bank +* ABN-AMRO +* Commerzbank +* Deutsche Bank +* German Bank +* ING +* Knab +* Landesbank Berlin +* NuaPay Bank +* Oldenburgische Landesbank +* PostFinance +* Rabobank +* SNS +* Sparkasse +* StarMoney +* Triodos Bank +* UniCredit Bank ## Adding bank parsers @@ -219,3 +245,8 @@ Jejik\MT940 is licensed under the MIT license. See the LICENSE.txt file for the full details. The test files for the ABN-AMRO, ING, Rabobank and Triodos bank come from the [dovadi/mt940](https://github.com/dovadi/mt940) ruby parser. Their license can be found in the LICENSE.fixtures.txt file. + +The test file for Sparkasse come from [Dominic Richter / Powercloud GmbH](https://github.com/twitnic). +The Parser Commerzbank, Deutsche Bank, German Bank, Landesbank Berlin, +NuaPay, Oldenburgische Landesbank, Sparkasse, StarMoney and Unicredit come from +[Powercloud GmbH](https://www.powercloud.de). diff --git a/UPGRADE.md b/UPGRADE.md index 3956eac..72dd1ea 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -2,6 +2,10 @@ This document list backwards-incompatible changes only. +## 0.3 to 0.4 + +* Upgraded from Php 5.X to minimum Php 7.1 + ## 0.2 to 0.3 * The `statementDelimiter` for parsers was dropped in favour of a more reliable diff --git a/lib/Jejik/MT940/Account.php b/lib/Jejik/MT940/Account.php index a14ae5d..6ab3991 100644 --- a/lib/Jejik/MT940/Account.php +++ b/lib/Jejik/MT940/Account.php @@ -22,6 +22,10 @@ class Account implements AccountInterface { // Properties {{{ + /** + * @var string Account currency + */ + private $currency; /** * @var ?string Account number @@ -37,6 +41,23 @@ class Account implements AccountInterface // Getters and setters {{{ + /** + * Get currency for this account + */ + public function getCurrency(): string + { + return $this->currency; + } + + /** + * Set currency for this account + */ + public function setCurrency(string $currency): AccountInterface + { + $this->currency = $currency; + return $this; + } + /** * Getter for number */ diff --git a/lib/Jejik/MT940/AccountInterface.php b/lib/Jejik/MT940/AccountInterface.php index b5d6b7f..3515fcd 100644 --- a/lib/Jejik/MT940/AccountInterface.php +++ b/lib/Jejik/MT940/AccountInterface.php @@ -21,6 +21,16 @@ */ interface AccountInterface { + /** + * Get currency for this account + */ + public function getCurrency(): string; + + /** + * Set currency for this account + */ + public function setCurrency(string $currency): self; + /** * Getter for number */ diff --git a/lib/Jejik/MT940/Exception/NoParserFoundException.php b/lib/Jejik/MT940/Exception/NoParserFoundException.php new file mode 100644 index 0000000..9507594 --- /dev/null +++ b/lib/Jejik/MT940/Exception/NoParserFoundException.php @@ -0,0 +1,31 @@ + + * Licensed under the MIT license + * + * For the full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + */ + +namespace Jejik\MT940\Exception; + +/** + * Class NoParserFoundException An exception that is thrown when no one of the given parsers accepted the document. + * @package Jejik\MT940\Exception + */ +class NoParserFoundException extends \Exception +{ + /** + * NoParserFoundException constructor. + * Creates the exception instance with a hardcoded message. + */ + public function __construct() + { + parent::__construct('No suitable parser found.'); + } +} diff --git a/lib/Jejik/MT940/Exception/UserException.php b/lib/Jejik/MT940/Exception/UserException.php new file mode 100644 index 0000000..f84b6e9 --- /dev/null +++ b/lib/Jejik/MT940/Exception/UserException.php @@ -0,0 +1,31 @@ + + * Licensed under the MIT license + * + * For the full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + */ + +namespace Jejik\MT940\Exception; + +/** + * Class UserException + * @package Jejik\MT940\Exception + */ +class UserException extends \Exception +{ + /** + * UserException constructor. + * Creates the exception instance with a hardcoded message. + */ + public function __construct() + { + parent::__construct('UserException'); + } +} diff --git a/lib/Jejik/MT940/Parser/AbnAmro.php b/lib/Jejik/MT940/Parser/AbnAmro.php index e649eda..b55d7d4 100644 --- a/lib/Jejik/MT940/Parser/AbnAmro.php +++ b/lib/Jejik/MT940/Parser/AbnAmro.php @@ -98,4 +98,12 @@ protected function contraAccountName(array $lines): ?string return null; } + + /** + * Get an array of allowed BLZ for this bank + */ + public function getAllowedBLZ(): array + { + return []; + } } diff --git a/lib/Jejik/MT940/Parser/AbstractParser.php b/lib/Jejik/MT940/Parser/AbstractParser.php index 30edf5e..61c5d19 100644 --- a/lib/Jejik/MT940/Parser/AbstractParser.php +++ b/lib/Jejik/MT940/Parser/AbstractParser.php @@ -50,6 +50,59 @@ public function __construct(Reader $reader) $this->reader = $reader; } + /** + * Check whether provided bank statement contains CRLF or not + * - if not then replace existing with CRLF (required for this parser) + * @param $text + */ + public function checkCRLF(&$text) + { + $text = preg_replace("#(\r\n|\r|\n)#", "\r\n", $text); + } + + /** + * Get the transaction reference number of an MT940 document. + * It is the :20: field at the beginning of each MT940 bankaccount statement. + * + * @param string $text The MT940 document + * @return string The transaction reference number + */ + public function getTransactionReferenceNumber(string $text): string + { + $startpos = strpos($text, ':20:'); + if ($startpos === false) { + throw new \RuntimeException('Not an MT940 statement'); + } + $endpos = strpos($text, "\r\n", $startpos); + if ($endpos === false) { + throw new \RuntimeException('Not an MT940 statement'); + } + return substr($text, $startpos + 4, $endpos - $startpos - 4); + } + + /** + * Check whether BLZ for provided bank statement text is allowed or not + * @param string $text + * @return bool + */ + public function isBLZAllowed($text): bool + { + $this->checkCRLF($text); + if ($account = $this->getLine('25', $text)) { + $accountExploded = explode('/', $account); + if (isset($accountExploded[0]) && in_array($accountExploded[0], $this->getAllowedBLZ())) { + return true; + } + } + + return false; + } + + /** + * Get an array of allowed BLZ for this bank + */ + abstract public function getAllowedBLZ(): array; + /** * Parse an MT940 document * @@ -60,6 +113,7 @@ public function __construct(Reader $reader) */ public function parse(string $text): array { + $this->checkCRLF($text); $statements = []; foreach ($this->splitStatements($text) as $chunk) { if ($statement = $this->statement($chunk)) { @@ -90,19 +144,23 @@ protected function getLine( int &$position = null, int &$length = null ): string { - $pcre = '/(?:^|\r?\n)\:(' . $id . ')\:' // "::" at the start of a line + $pcre = '/(?:^|\r\n)\:(' . $id . ')\:' // "::" at the start of a line . '(.+)' // Contents of the line - . '(:?$|\r?\n\:[[:alnum:]]{2,3}\:)' // End of the text or next "::" + . '(:?$|\r\n\:[[:alnum:]]{2,3}\:)' // End of the text or next "::" . '/Us'; // Ungreedy matching - // Offset manually, so the start of the offset can match ^ - if (preg_match($pcre, substr($text, $offset), $match, PREG_OFFSET_CAPTURE)) { - $position = $offset + $match[1][1] - 1; - $length = strlen($match[2][0]); + $substring = substr($text, $offset); + if ($substring !== false) { + // Offset manually, so the start of the offset can match ^ + if (preg_match($pcre, $substring, $match, PREG_OFFSET_CAPTURE)) { + $position = $offset + $match[1][1] - 1; + $length = strlen($match[2][0]); - return rtrim($match[2][0]); + return rtrim($match[2][0]); + } } + return ''; } @@ -137,13 +195,13 @@ protected function splitStatements(string $text): array */ protected function splitTransactions(string $text): array { - $offset = 0; - $length = 0; - $position = 0; + $offset = 0; + $length = 0; + $position = 0; $transactions = []; while ($line = $this->getLine('61', $text, $offset, $offset, $length)) { - $offset += 4 + $length + 2; + $offset += 4 + $length + 2; $transaction = [$line]; // See if the next description line belongs to this transaction line. @@ -151,7 +209,7 @@ protected function splitTransactions(string $text): array $description = []; while ($line = $this->getLine('86', $text, $offset, $position, $length)) { if ($position == $offset) { - $offset += 4 + $length + 2; + $offset += 4 + $length + 2; $description[] = $line; } else { break; @@ -206,14 +264,16 @@ protected function statementHeader(string $text): void protected function statementBody(string $text): ?Statement { $accountNumber = $this->accountNumber($text); - $account = $this->reader->createAccount($accountNumber); + $accountCurrency = $this->accountCurrency($text); + $account = $this->reader->createAccount($accountNumber); if (!($account instanceof AccountInterface)) { return null; } $account->setNumber($accountNumber); - $number = $this->statementNumber($text); + $account->setCurrency($accountCurrency); + $number = $this->statementNumber($text); /** @var Statement $statement */ $statement = $this->reader->createStatement($account, $number); @@ -263,7 +323,33 @@ protected function accountNumber(string $text): ?string } /** - * Fill a Balance object from an MT940 balance line + * Parse account currency + */ + protected function accountCurrency($text): ?string + { + $accountNumber = $this->accountNumber($text); + if ($accountNumber == null) { + return null; + } + // last 3 characters comprises its ISO currency code + $currency = substr($accountNumber, strlen($accountNumber) - 3, 3); + $pcreCurrency = '/([A-Z]{3})$/'; + if (!preg_match($pcreCurrency, $currency)) { + // try it from 60F + if ($line60F = $this->getLine('60F', $text)) { + $pcreCurrency = '/(C|D)(\d{6})([A-Z]{3})([0-9,]{1,15})/'; + preg_match($pcreCurrency, $text, $match); + if (isset($match[3])) { + return $match[3]; + } + return null; + } + } + return $currency; + } + + /** + * Create a Balance object from an MT940 balance line */ protected function balance(BalanceInterface $balance, string $text): BalanceInterface { @@ -271,7 +357,7 @@ protected function balance(BalanceInterface $balance, string $text): BalanceInte throw new \RuntimeException(sprintf('Cannot parse balance: "%s"', $text)); } - $amount = (float) str_replace(',', '.', $match[4]); + $amount = (float)str_replace(',', '.', $match[4]); if ($match[1] === 'D') { $amount *= -1; } @@ -321,13 +407,13 @@ protected function closingBalance(string $text): ?Balance */ protected function transaction(array $lines): TransactionInterface { - if (!preg_match('/(\d{6})((\d{2})(\d{2}))?(C|D)([A-Z]?)([0-9,]{1,15})/', $lines[0], $match)) { + if (!preg_match('/(\d{6})(\d{4})?((?:C|D)R?)([0-9,]{1,15})/', $lines[0], $match)) { throw new \RuntimeException(sprintf('Could not parse transaction line "%s"', $lines[0])); } // Parse the amount - $amount = (float) str_replace(',', '.', $match[7]); - if ($match[5] === 'D') { + $amount = (float)str_replace(',', '.', $match[4]); + if (in_array($match[3], array('D', 'DR'))) { $amount *= -1; } @@ -338,10 +424,36 @@ protected function transaction(array $lines): TransactionInterface $bookDate = null; if ($match[2]) { - // Construct book date from the month and day provided by adding the year of the value date as best guess. - $month = intval($match[3]); - $day = intval($match[4]); - $bookDate = $this->getNearestDateTimeFromDayAndMonth($valueDate, $day, $month); + // current|same year as valueDate + $bookDate_sameYear = \DateTime::createFromFormat('ymd', $valueDate->format('y') . $match[2]); + $bookDate_sameYear->setTime(0, 0, 0); + + /* consider proper year -- $valueDate = '160104'(YYMMTT) & $bookDate = '1228'(MMTT) */ + // previous year bookDate + $bookDate_previousYear = clone($bookDate_sameYear); + $bookDate_previousYear->modify('-1 year'); + + // next year bookDate + $bookDate_nextYear = clone($bookDate_sameYear); + $bookDate_nextYear->modify('+1 year'); + + // bookDate collection + $bookDateCollection = []; + + // previous year diff + $bookDate_previousYear_diff = $valueDate->diff($bookDate_previousYear); + $bookDateCollection[$bookDate_previousYear_diff->days] = $bookDate_previousYear; + + // current|same year as valueDate diff + $bookDate_sameYear_diff = $valueDate->diff($bookDate_sameYear); + $bookDateCollection[$bookDate_sameYear_diff->days] = $bookDate_sameYear; + + // next year diff + $bookDate_nextYear_diff = $valueDate->diff($bookDate_nextYear); + $bookDateCollection[$bookDate_nextYear_diff->days] = $bookDate_nextYear; + + // get the min from these diffs + $bookDate = $bookDateCollection[min(array_keys($bookDateCollection))]; } $description = isset($lines[1]) ? $lines[1] : null; @@ -351,48 +463,26 @@ protected function transaction(array $lines): TransactionInterface ->setContraAccount($this->contraAccount($lines)) ->setValueDate($valueDate) ->setBookDate($bookDate) + ->setCode($this->code($lines)) + ->setRef($this->ref($lines)) + ->setBankRef($this->bankRef($lines)) + ->setGVC($this->gvc($lines)) + ->setTxText($this->txText($lines)) + ->setPrimanota($this->primanota($lines)) + ->setExtCode($this->extCode($lines)) + ->setEref($this->eref($lines)) + ->setBIC($this->bic($lines)) + ->setIBAN($this->iban($lines)) + ->setAccountHolder($this->accountHolder($lines)) + ->setKref($this->kref($lines)) + ->setMref($this->mref($lines)) + ->setCred($this->cred($lines)) + ->setSvwz($this->svwz($lines)) ->setDescription($this->description($description)); return $transaction; } - /** - * Finds the closest \DateTime to the given target \DateTime with the set - * day and month. Will try at most 3 \Datetime's, one a year before our - * initial guess, and one a year after. Returns the one with the least days - * difference in days. - * - * @throws \Exception - */ - protected function getNearestDateTimeFromDayAndMonth( - \DateTime $target, - int $day, - int $month - ): \DateTime { - $initialGuess = new \DateTime(); - $initialGuess->setDate((int)$target->format('Y'), $month, $day); - $initialGuess->setTime(0, 0, 0); - $initialGuessDiff = $target->diff($initialGuess); - - $yearEarlier = clone $initialGuess; - $yearEarlier->modify('-1 year'); - $yearEarlierDiff = $target->diff($yearEarlier); - - if ($yearEarlierDiff->days < $initialGuessDiff->days) { - return $yearEarlier; - } - - $yearLater = clone $initialGuess; - $yearLater->modify('+1 year'); - $yearLaterDiff = $target->diff($yearLater); - - if ($yearLaterDiff->days < $initialGuessDiff->days) { - return $yearLater; - } - - return $initialGuess; - } - /** * Get the contra account from a transaction * @@ -450,4 +540,124 @@ protected function description(?string $description): ?string * Test if the document can be read by the parser */ abstract public function accept(string $text): bool; + + /** + * Parse GVC for provided transaction lines + */ + protected function gvc(array $lines): ?string + { + return null; + } + + /** + * Parse code for provided transaction lines + */ + protected function code(array $lines): ?string + { + return null; + } + + /** + * Parse ref for provided transaction lines + */ + protected function ref(array $lines): ?string + { + return null; + } + + /** + * Parse bankRef for provided transaction lines + */ + protected function bankRef(array $lines): ?string + { + return null; + } + + /** + * Parse txText for provided transaction lines + */ + protected function txText(array $lines): ?string + { + return null; + } + + /** + * Parse primanota for provided transaction lines + */ + protected function primanota(array $lines): ?string + { + return null; + } + + /** + * Parse extCode for provided transaction lines + */ + protected function extCode(array $lines): ?string + { + return null; + } + + /** + * Parse eref for provided transaction lines + */ + protected function eref(array $lines): ?string + { + return null; + } + + /** + * Parse bic for provided transaction lines + */ + protected function bic(array $lines): ?string + { + return null; + } + + /** + * Parse iban for provided transaction lines + */ + protected function iban(array $lines): ?string + { + return null; + } + + /** + * Parse accountHolder for provided transaction lines + */ + protected function accountHolder(array $lines): ?string + { + return null; + } + + /** + * Parse kref for provided transaction lines + */ + protected function kref(array $lines): ?string + { + return null; + } + + /** + * Parse mref for provided transaction lines + */ + protected function mref(array $lines): ?string + { + return null; + } + + /** + * Parse cred for provided transaction lines + */ + protected function cred(array $lines): ?string + { + return null; + } + + /** + * Parse svwz for provided transaction lines + */ + protected function svwz(array $lines): ?string + { + return null; + } } diff --git a/lib/Jejik/MT940/Parser/Commerzbank.php b/lib/Jejik/MT940/Parser/Commerzbank.php new file mode 100755 index 0000000..917343b --- /dev/null +++ b/lib/Jejik/MT940/Parser/Commerzbank.php @@ -0,0 +1,55 @@ + + * Licensed under the MIT license + * + * For the full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + */ + +namespace Jejik\MT940\Parser; + +/** + * Commerzbank provides a parser for Commerz Bank + * @package Jejik\MT940\Parser + */ +class Commerzbank extends GermanBank +{ + /** + * Check whether provided MT940 statement string can be parsed by this parser + */ + public function accept(string $text): bool + { + $allowedUniqueIdentifiers = [ + ':20:012CIXCIA7V1OGWA', + ':20:0157VSNLKBG9WGWA', + ]; + + // unique identifier check + $mt940Identifier = substr($text, 0, 20); + if (in_array($mt940Identifier, $allowedUniqueIdentifiers)) { + return true; + } + + // if not check it's BLZ + return $this->isBLZAllowed($text); + } + + /** + * Get an array of allowed BLZ for this bank + * @return array + */ + public function getAllowedBLZ(): array + { + return [ + '70040041', + '66280053', + '28540034' + ]; + } +} diff --git a/lib/Jejik/MT940/Parser/DeutscheBank.php b/lib/Jejik/MT940/Parser/DeutscheBank.php new file mode 100755 index 0000000..8a57213 --- /dev/null +++ b/lib/Jejik/MT940/Parser/DeutscheBank.php @@ -0,0 +1,54 @@ + + * Licensed under the MIT license + * + * For the full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + */ + +namespace Jejik\MT940\Parser; + +/** + * DeutscheBank provides a parser for Deutsche Bank + * @package Jejik\MT940\Parser + */ +class DeutscheBank extends GermanBank +{ + /** + * Check whether provided MT940 statement string can be parsed by this parser + */ + public function accept(string $text): bool + { + // unique identifier check + $allowedUniqueIdentifiers = [ + ':20:DEUTDEFF', + ':20:DEUTDEMM', + ':20:DEUTDEBB' + ]; + + // unique identifier check + $mt940Identifier = substr($text, 0, 12); + if (in_array($mt940Identifier, $allowedUniqueIdentifiers)) { + return true; + } + + // if not check it's BLZ + return $this->isBLZAllowed($text); + } + + /** + * Get an array of allowed BLZ for this bank + */ + public function getAllowedBLZ(): array + { + return [ + '66470035' + ]; + } +} diff --git a/lib/Jejik/MT940/Parser/GermanBank.php b/lib/Jejik/MT940/Parser/GermanBank.php new file mode 100755 index 0000000..1f0ecbc --- /dev/null +++ b/lib/Jejik/MT940/Parser/GermanBank.php @@ -0,0 +1,457 @@ + + * Licensed under the MIT license + * + * For the full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + */ + +namespace Jejik\MT940\Parser; + +/** + * GermanBank provides an abstract mt940 parser layer for german banks + * @package Jejik\MT940\Parser + */ +abstract class GermanBank extends AbstractParser +{ + + protected const IDENTIFIER_EREF = 'EREF'; + protected const IDENTIFIER_KREF = 'KREF'; + protected const IDENTIFIER_MREF = 'MREF'; + protected const IDENTIFIER_CRED = 'CRED'; + protected const IDENTIFIER_DEBT = 'DEBT'; + protected const IDENTIFIER_COAM = 'COAM'; + protected const IDENTIFIER_OAMT = 'OAMT'; + protected const IDENTIFIER_SVWZ = 'SVWZ'; + protected const IDENTIFIER_ABWA = 'ABWA'; + protected const IDENTIFIER_ABWE = 'ABWE'; + + /** + * Parse GVC for provided transaction lines + */ + protected function gvc(array $lines): ?string + { + // get :86: line -- it is second in provided array [:61:,:86:,....] + $gvcLine = isset($lines[1]) ? $lines[1] : null; + + // assure gvc line + if ($gvcLine == null) { + return null; + } + + // return + return substr($gvcLine, 0, 3); // gvc has fixed 3 bytes + } + + /** + * Parse code for provided transaction lines + */ + protected function code(array $lines): ?string + { + // get :61: line -- it is first in provided array [:61:,:86:,....] + $codeLine = isset($lines[0]) ? $lines[0] : null; + + // assure code line + if ($codeLine == null) { + return null; + } + + // match it + preg_match('#(\d{6})(\d{4})?(R?(?:C|D))([0-9,]{1,15})N([a-zA-Z0-9]+)#', $codeLine, $match); + + // assure match + if (!isset($match[5])) { + return null; + } + + // return + return substr($match[5], 0, 3); + } + + /** + * Parse ref for provided transaction lines + */ + protected function ref(array $lines): ?string + { + // get :61: line -- it is first in provided array [:61:,:86:,....] + $refLine = isset($lines[0]) ? $lines[0] : null; + + // assure ref line + if ($refLine == null) { + return null; + } + + // match it + preg_match('#(\d{6})(\d{4})?(R?(?:C|D))([0-9,]{1,15})N([a-zA-Z0-9]+)#', $refLine, $match); + + // assure match + if (!isset($match[5])) { + return null; + } + + // return + return substr($match[5], 3); + } + + /** + * Parse bankRef for provided transaction lines + */ + protected function bankRef(array $lines): ?string + { + // TODO search its proper explanation and implement it + return $this->ref($lines); + } + + /** + * Parse txText for provided transaction lines + */ + protected function txText(array $lines): ?string + { + // get :86: line -- it is second in provided array [:61:,:86:,....] + $txTextLine = isset($lines[1]) ? $lines[1] : null; + + // assure txText line + if ($txTextLine === null) { + return null; + } + + // match it + /** @var string $txTextLine */ + preg_match('#\?00([a-zA-Z0-9\-\s\.]+)#', $this->removeNewLinesFromLine($txTextLine), $match); + + // assure match + if (!isset($match[1])) { + return null; + } + + // return + return $match[1]; + } + + /** + * Parse primanota for provided transaction lines + */ + protected function primanota(array $lines): ?string + { + // get :86: line -- it is second in provided array [:61:,:86:,....] + $primanotaLine = isset($lines[1]) ? $lines[1] : null; + + // assure primanota line + if ($primanotaLine === null) { + return null; + } + + /** @var string $primanotaLine */ + preg_match('#\?10([a-zA-Z0-9/]{1,10})#', $this->removeNewLinesFromLine($primanotaLine), $match); + + // assure match + if (!isset($match[1])) { + return null; + } + + // return + return $match[1]; + } + + /** + * Parse extCode for provided transaction lines + */ + protected function extCode(array $lines): ?string + { + // get :86: line -- it is second in provided array [:61:,:86:,....] + $extCodeLine = isset($lines[1]) ? $lines[1] : null; + + // assure extCode line + if ($extCodeLine === null) { + return null; + } + + /** @var string $extCodeLine */ + preg_match('#\?34(\d{3})#', $this->removeNewLinesFromLine($extCodeLine), $match); + + if (!isset($match[1])) { + return null; + } + + return $match[1]; + } + + /** + */ + protected function getSubfield(string $multiUseLine, string $identifier): ?string + { + $multiUseLine = $this->removeNewLinesFromLine($multiUseLine); + // extract reference line ?20 - ?29 + $foundLine = (bool) preg_match( + '#(?(\?2[0-9][^?]+)+)#', + $multiUseLine, + $match + ); + + $referenceLine = $match['referenceLine'] ?? null; + + if (!$foundLine || empty($referenceLine)) { + return null; + } + + $identifiers = [ + static::IDENTIFIER_EREF, + static::IDENTIFIER_KREF, + static::IDENTIFIER_MREF, + static::IDENTIFIER_CRED, + static::IDENTIFIER_DEBT, + static::IDENTIFIER_COAM, + static::IDENTIFIER_OAMT, + static::IDENTIFIER_SVWZ, + static::IDENTIFIER_ABWA, + static::IDENTIFIER_ABWE, + ]; + + $regex = sprintf( + '#(?\?2[0-9])(?%s)\+#m', + implode('|', $identifiers) + ); + + $splitReferenceLine = preg_split( + $regex, + $referenceLine, + -1, + PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE + ); + $subfields = []; + + // check if leading value is an separator: '?20' '?2X' '' '' + if (current($splitReferenceLine) != '?20') { + // remove first element if no separator found + next($splitReferenceLine); + } + + // expects : '?2X' '' '' + do { + $fieldIdentifier = next($splitReferenceLine) ?: 'unknown'; + $fieldContent = next($splitReferenceLine) ?: null; + $subfields[$fieldIdentifier] = preg_replace('#\?2[0-9]#', '', $fieldContent); + } while (next($splitReferenceLine) !== false); + + return $subfields[$identifier] ?? null; + } + + /** + * Parse eref for provided transaction lines + */ + protected function eref(array $lines): ?string + { + // get :86: line -- it is second in provided array [:61:,:86:,....] + $multiUseLine = $lines[1] ?? null; + + /** @var string|null $multiUseLine */ + return $multiUseLine + ? $this->getSubfield($multiUseLine, static::IDENTIFIER_EREF) + : null; + } + + /** + * Parse bic for provided transaction lines + */ + protected function bic(array $lines): ?string + { + // get :86: line -- it is second in provided array [:61:,:86:,....] + $bicLine = isset($lines[1]) ? $lines[1] : null; + + // assure bic line + if ($bicLine === null) { + return null; + } + + /** @var string $bicLine */ + preg_match('#\?30([a-zA-Z0-9]+)#', $this->removeNewLinesFromLine($bicLine), $match); + + // assure match + if (!isset($match[1])) { + return null; + } + + return $match[1]; + } + + /** + * Parse iban for provided transaction lines + */ + protected function iban(array $lines): ?string + { + // get :86: line -- it is second in provided array [:61:,:86:,....] + $ibanLine = isset($lines[1]) ? $lines[1] : null; + + // assure iban line + if ($ibanLine == null) { + return null; + } + + // match it + /** @var string $ibanLine */ + preg_match('#\?31([a-zA-Z0-9]+)#', $this->removeNewLinesFromLine($ibanLine), $match); + + // assure match + if (!isset($match[1])) { + return null; + } + + // return + return $match[1]; + } + + /** + * Parse accountHolder for provided transaction lines + */ + protected function accountHolder(array $lines): ?string + { + // get :86: line -- it is second in provided array [:61:,:86:,....] + $accHolderLine = isset($lines[1]) ? $lines[1] : null; + + // assure acc holder line + if ($accHolderLine == null) { + return null; + } + + // TODO try to match names containing ? character + preg_match( + '#\?32((?:[a-zA-ZöäüÖÄÜß0-9\(\)\s,\-\./\+]+(?:\?[^\?33|34])?)+)#', + $this->removeNewLinesFromLine($accHolderLine), + $match + ); + + if (!isset($match[1])) { + return null; + } + + // additional field ?33 + /** @var string $accHolderLine */ + preg_match( + '#\?33([a-zA-ZöäüÖÄÜß0-9\(\)\s,\-\./\+]+)#', + $this->removeNewLinesFromLine($accHolderLine), + $matchAdd + ); + + if (!isset($matchAdd[1])) { + return preg_replace('#(\?\d{2})#', '', $match[1]); + } + + return preg_replace('#(\?\d{2})#', '', $match[1] . $matchAdd[1]); + } + + /** + * Parse kref for provided transaction lines + */ + protected function kref(array $lines): ?string + { + // get :86: line -- it is second in provided array [:61:,:86:,....] + $krefLine = isset($lines[1]) ? $lines[1] : null; + + // pattern + $pattern = 'K(?:\?2[1-9])?R(?:\?2[1-9])?E(?:\?2[1-9])?F(?:\?2[1-9])?\+([a-zA-ZöäüÖÄÜß0-9\./?\+\-\s,]+)(C(?:\?2[1-9])?R(?:\?2[1-9])?E(?:\?2[1-9])?D|S(?:\?2[1-9])?V(?:\?2[1-9])?W(?:\?2[1-9])?Z)'; + + /** @var string $krefLine */ + preg_match("#{$pattern}#", $this->removeNewLinesFromLine($krefLine), $match); + + // assure match + if (!isset($match[1])) { + // try it without CRED|SVWZ info + $pattern = 'K(?:\?2[1-9])?R(?:\?2[1-9])?E(?:\?2[1-9])?F(?:\?2[1-9])?\+([a-zA-ZöäüÖÄÜß0-9\./?\+\-\s,]+?)(\?3[0-9])'; + + // match it + preg_match("#{$pattern}#", $this->removeNewLinesFromLine($krefLine), $match); + } + + // assure match again after avoiding CRED|SVWZ info + if (!isset($match[1])) { + return null; + } + + // return + return preg_replace('#(\?\d{0,2})#', '', $match[1]); + } + + /** + * Parse mref for provided transaction lines + */ + protected function mref(array $lines): ?string + { + // get :86: line -- it is second in provided array [:61:,:86:,....] + $mrefLine = isset($lines[1]) ? $lines[1] : null; + + // pattern + $pattern = 'M(?:\?2[1-9])?R(?:\?2[1-9])?E(?:\?2[1-9])?F(?:\?2[1-9])?\+([a-zA-ZöäüÖÄÜß0-9\./?\+\-\s,]+)(C(?:\?2[1-9])?R(?:\?2[1-9])?E(?:\?2[1-9])?D|S(?:\?2[1-9])?V(?:\?2[1-9])?W(?:\?2[1-9])?Z)'; + + // match it + preg_match("#{$pattern}#", $this->removeNewLinesFromLine($mrefLine), $match); + + // assure match + if (!isset($match[1])) { + return null; + } + + // return + return preg_replace('#(\?\d{0,2})#', '', $match[1]); + } + + /** + * Parse cred for provided transaction lines + */ + protected function cred(array $lines): ?string + { + // get :86: line -- it is second in provided array [:61:,:86:,....] + $credLine = isset($lines[1]) ? $lines[1] : null; + + // pattern + $pattern = 'C(?:\?2[1-9])?R(?:\?2[1-9])?E(?:\?2[1-9])?D(?:\?2[1-9])?\+([a-zA-ZöäüÖÄÜß0-9\./?\+\-\s,]+)S(?:\?2[1-9])?V(?:\?2[1-9])?W(?:\?2[1-9])?Z'; + + // match it + preg_match("#{$pattern}#", $this->removeNewLinesFromLine($credLine), $match); + + // assure match + if (!isset($match[1])) { + return null; + } + + // return + return preg_replace('#(\?\d{0,2})#', '', $match[1]); + } + + /** + * Parse svwz for provided transaction lines + */ + protected function svwz(array $lines): ?string + { + // get :86: line -- it is second in provided array [:61:,:86:,....] + $svwzLine = isset($lines[1]) ? $lines[1] : null; + + // pattern + $pattern = 'S(?:\?2[1-9])?V(?:\?2[1-9])?W(?:\?2[1-9])?Z(?:\?2[1-9])?\+(?:\?2[1-9])?((?:[a-zA-ZöäüÖÄÜß\-/\s0-9\,\.\:]+(?:\?2[1-9])?)+)'; + + // match it + /** @var string $svwzLine */ + preg_match("#{$pattern}#", $this->removeNewLinesFromLine($svwzLine), $match); + + // assure match + if (!isset($match[1])) { + return null; + } + + // return + return preg_replace('#(\?2[1-9])#', '', $match[1]); + } + + /** + * Remove all new lines and carriage returns from provided input line + */ + private function removeNewLinesFromLine(string $stringLine): string + { + return str_replace(["\n", "\r", "\r\n"], '', $stringLine); + } +} diff --git a/lib/Jejik/MT940/Parser/Ing.php b/lib/Jejik/MT940/Parser/Ing.php index 08ee424..2da3b50 100644 --- a/lib/Jejik/MT940/Parser/Ing.php +++ b/lib/Jejik/MT940/Parser/Ing.php @@ -91,4 +91,12 @@ protected function contraAccountNumber(array $lines): ?string return null; } + + /** + * Get an array of allowed BLZ for this bank + */ + public function getAllowedBLZ(): array + { + return []; + } } diff --git a/lib/Jejik/MT940/Parser/Knab.php b/lib/Jejik/MT940/Parser/Knab.php index 81db95b..5b778a7 100644 --- a/lib/Jejik/MT940/Parser/Knab.php +++ b/lib/Jejik/MT940/Parser/Knab.php @@ -75,4 +75,12 @@ protected function contraAccountName(array $lines): ?string return null; } + + /** + * Get an array of allowed BLZ for this bank + */ + public function getAllowedBLZ(): array + { + return []; + } } diff --git a/lib/Jejik/MT940/Parser/LandesBankBerlin.php b/lib/Jejik/MT940/Parser/LandesBankBerlin.php new file mode 100644 index 0000000..4295634 --- /dev/null +++ b/lib/Jejik/MT940/Parser/LandesBankBerlin.php @@ -0,0 +1,56 @@ + + * Licensed under the MIT license + * + * For the full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + */ + +namespace Jejik\MT940\Parser; + +/** + * Class LandesBankBerlin provides a parser for Landes Bank Berlin + * - LBB + * @package Jejik\MT940\Parser + */ +class LandesBankBerlin extends GermanBank +{ + /** + * Check whether provided MT940 statement string can be parsed by this parser + */ + public function accept(string $text): bool + { + $allowedUniqueIdentifiers = [ + ':20:FI-C53-ID', + ]; + + // unique identifier check + $mt940Identifier = substr($text, 0, 13); + if (in_array($mt940Identifier, $allowedUniqueIdentifiers)) { + return true; + } + + // if not check it's BLZ + return $this->isBLZAllowed($text); + } + + /** + * Get an array of allowed BLZ for this bank + */ + public function getAllowedBLZ(): array + { + return [ + '10050000', + '10050005', + '10050006', + '10050007', + '10050008', + ]; + } +} diff --git a/lib/Jejik/MT940/Parser/NuaPayBank.php b/lib/Jejik/MT940/Parser/NuaPayBank.php new file mode 100755 index 0000000..de6b74f --- /dev/null +++ b/lib/Jejik/MT940/Parser/NuaPayBank.php @@ -0,0 +1,48 @@ + + * Licensed under the MIT license + * + * For the full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + */ + +namespace Jejik\MT940\Parser; + +/** + * NuaPayBank provides a parser for NuaPay Bank + * - Irisches Bank + * @package Jejik\MT940\Parser + */ +class NuaPayBank extends GermanBank +{ + /** + * Check whether provided MT940 statement string can be parsed by this parser + */ + public function accept(string $text): bool + { + // unique identifier check + $identifierCheck = substr($text, 0, 10) === ':20:NUAPAY'; + if ($identifierCheck) { + return true; + } + + // if not check it's BLZ + return $this->isBLZAllowed($text); + } + + /** + * Get an array of allowed BLZ for this bank + */ + public function getAllowedBLZ(): array + { + return [ + 'SELN0099' + ]; + } +} diff --git a/lib/Jejik/MT940/Parser/OldenburgischeLandesbank.php b/lib/Jejik/MT940/Parser/OldenburgischeLandesbank.php new file mode 100755 index 0000000..72d5d25 --- /dev/null +++ b/lib/Jejik/MT940/Parser/OldenburgischeLandesbank.php @@ -0,0 +1,77 @@ + + * Licensed under the MIT license + * + * For the full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + */ + +namespace Jejik\MT940\Parser; + +/** + * OldenburgischeLandesbank provides a parser for Oldenburgische Landesbank + * @package Jejik\MT940\Parser + */ +class OldenburgischeLandesbank extends GermanBank +{ + /** + * Test if the document can be read by the parser + */ + public function accept(string $text): bool + { + $allowedUniqueIdentifiers = [ + ':20:STARTUMS TA', + ':20:STARTUMS MC', + ]; + + // unique identifier check + $mt940Identifier = substr($text, 0, 15); + if (in_array($mt940Identifier, $allowedUniqueIdentifiers)) { + return true; + } + + // if not check it's BLZ + return $this->isBLZAllowed($text); + } + + /** + * Get an array of allowed BLZ for this bank + */ + public function getAllowedBLZ(): array + { + return [ + '28020050', + '25621327', + '26520017', + '26521703', + '26522319', + '26620010', + '26621413', + '26720028', + '28021002', + '28021301', + '28021504', + '28021623', + '28021705', + '28021906', + '28022015', + '28022412', + '28022511', + '28022620', + '28022822', + '28023224', + '28023325', + '28030300', + '28220026', + '28222208', + '28222621', + '28320014', + ]; + } +} diff --git a/lib/Jejik/MT940/Parser/PostFinance.php b/lib/Jejik/MT940/Parser/PostFinance.php index 369ad84..2a2ab2c 100644 --- a/lib/Jejik/MT940/Parser/PostFinance.php +++ b/lib/Jejik/MT940/Parser/PostFinance.php @@ -66,4 +66,12 @@ protected function contraAccountNumber(array $lines): ?string return null; } + + /** + * Get an array of allowed BLZ for this bank + */ + public function getAllowedBLZ(): array + { + return []; + } } diff --git a/lib/Jejik/MT940/Parser/Rabobank.php b/lib/Jejik/MT940/Parser/Rabobank.php index 44c04b6..89892dd 100644 --- a/lib/Jejik/MT940/Parser/Rabobank.php +++ b/lib/Jejik/MT940/Parser/Rabobank.php @@ -147,4 +147,12 @@ protected function contraAccountName(array $lines): ?string return null; } + + /** + * Get an array of allowed BLZ for this bank + */ + public function getAllowedBLZ(): array + { + return []; + } } diff --git a/lib/Jejik/MT940/Parser/Sns.php b/lib/Jejik/MT940/Parser/Sns.php index 205848e..32bf280 100644 --- a/lib/Jejik/MT940/Parser/Sns.php +++ b/lib/Jejik/MT940/Parser/Sns.php @@ -49,4 +49,12 @@ protected function contraAccountNumber(array $lines): ?string return null; } + + /** + * Get an array of allowed BLZ for this bank + */ + public function getAllowedBLZ(): array + { + return []; + } } diff --git a/lib/Jejik/MT940/Parser/Sparkasse.php b/lib/Jejik/MT940/Parser/Sparkasse.php new file mode 100755 index 0000000..b659ffa --- /dev/null +++ b/lib/Jejik/MT940/Parser/Sparkasse.php @@ -0,0 +1,79 @@ + + * Licensed under the MIT license + * + * For the full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + */ + +namespace Jejik\MT940\Parser; + +/** + * Sparkasse provides a parser for Sparkasse Bank + * @package Jejik\MT940\Parser + */ +class Sparkasse extends GermanBank +{ + /** + * Test if the document can be read by the parser + */ + public function accept(string $text): bool + { + $allowedUniqueIdentifiers = [ + ':20:STARTUMS' + ]; + + // unique identifier check + $mt940Identifier = substr($text, 0, 12); + if (in_array($mt940Identifier, $allowedUniqueIdentifiers)) { + return true; + } + + // if not check it's BLZ + return $this->isBLZAllowed($text); + } + + /** + * Get an array of allowed BLZ for this bank + */ + public function getAllowedBLZ(): array + { + return [ + ]; + } + + /** + * Get the contra account from a transaction + * + * @param array $lines The transaction text at offset 0 and the description at offset 1 + */ + protected function contraAccountNumber(array $lines): ?string + { + if (preg_match('/\?31(.*?)\?32/s', $lines[1], $match)) { + return trim(preg_replace('/\s\s+/', '', $match[1])); + } + + return null; + } + + protected function contraAccountName(array $lines): ?string + { + if (preg_match('/\?32(.*?)\?34/s', $lines[1], $match)) { + return trim(preg_replace('/\s\s+/', '', $match[1])); + } + + return null; + } + + //TODO: reformat :86: Mehrzweckfeld + protected function description(?string $description): ?string + { + return parent::description($description); // TODO: Change the autogenerated stub + } +} diff --git a/lib/Jejik/MT940/Parser/SpecificGermanBankParser.php b/lib/Jejik/MT940/Parser/SpecificGermanBankParser.php new file mode 100644 index 0000000..9993624 --- /dev/null +++ b/lib/Jejik/MT940/Parser/SpecificGermanBankParser.php @@ -0,0 +1,78 @@ + + * Licensed under the MIT license + * + * For the full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + */ + +namespace Jejik\MT940\Parser; + +use Jejik\MT940\Exception\UserException; + +class SpecificGermanBankParser extends \Jejik\MT940\Parser\GermanBank +{ + /** @var string */ + private $knownTransactionReferenceNumber; + + /** @var null */ + private $exception = null; + + /** + * Creates an instance of this parser. It will only accept statements with the given transaction reference number. + * + * @param \Jejik\MT940\Reader $reader + * @param string $knownTransactionReferenceNumber The given number that will be accepted by this parser. + */ + public function __construct( + \Jejik\MT940\Reader $reader, + string $knownTransactionReferenceNumber + ) { + parent::__construct($reader); + $this->knownTransactionReferenceNumber = $knownTransactionReferenceNumber; + } + + /** + * Method exists to fit the interface definition, but should not be called and throws always an exception. + * + * @return array + */ + public function getAllowedBLZ(): array + { + throw new \RuntimeException( + 'Bankaccount statements are not checked by allowed BLZ if an explicit transaction reference number is given.' + ); + } + + /** + * Test if the document can be read by the parser. In this case this means, that the transaction reference number in + * the bankaccount statement contains the expected reference number. (It does not need to be equal) + * + * @param string $text The MT940 document + * @return bool True if the transaction reference number is correct, false if not. + */ + public function accept(string $text): bool + { + // set all linebreaks to \r\n + $this->checkCRLF($text); + + $documentTransactionReferenceNumber = $this->getTransactionReferenceNumber($text); + return strpos($documentTransactionReferenceNumber, $this->knownTransactionReferenceNumber) !== false; + } + + /** + * Get the exception that has been saved, when the accept() method returned false last time. + * + * @return UserException|null The error message if one has been saved or null if not. + */ + public function getException(): ?UserException + { + return $this->exception; + } +} diff --git a/lib/Jejik/MT940/Parser/StarMoney.php b/lib/Jejik/MT940/Parser/StarMoney.php new file mode 100755 index 0000000..f3f88d1 --- /dev/null +++ b/lib/Jejik/MT940/Parser/StarMoney.php @@ -0,0 +1,46 @@ + + * Licensed under the MIT license + * + * For the full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + */ + +namespace Jejik\MT940\Parser; + +/** + * StarMoney provides a parser for StarMoney Bank + * + * @package Jejik\MT940\Parser + */ +class StarMoney extends GermanBank +{ + /** + * Check whether provided MT940 statement string can be parsed by this parser + */ + public function accept(string $text): bool + { + // unique identifier check + $identifierCheck = substr($text, 0, 16) === ':20:REFSTARMONEY'; + if ($identifierCheck) { + return true; + } + + // if not check it's BLZ + return $this->isBLZAllowed($text); + } + + /** + * Get an array of allowed BLZ for this bank + */ + public function getAllowedBLZ(): array + { + return ['10070024']; + } +} diff --git a/lib/Jejik/MT940/Parser/Triodos.php b/lib/Jejik/MT940/Parser/Triodos.php index 9009d3d..29d4396 100644 --- a/lib/Jejik/MT940/Parser/Triodos.php +++ b/lib/Jejik/MT940/Parser/Triodos.php @@ -69,4 +69,14 @@ protected function description(?string $description): string { return preg_replace('/>2[0-7]{1}/', '', $description); } + + /** + * Get an array of allowed BLZ for this bank + */ + public function getAllowedBLZ(): array + { + return [ + '50031000' // Frankfurt am Main + ]; + } } diff --git a/lib/Jejik/MT940/Parser/UniCreditBank.php b/lib/Jejik/MT940/Parser/UniCreditBank.php new file mode 100755 index 0000000..bf1760b --- /dev/null +++ b/lib/Jejik/MT940/Parser/UniCreditBank.php @@ -0,0 +1,89 @@ + + * Licensed under the MIT license + * + * For the full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + */ + +namespace Jejik\MT940\Parser; + +/** + * UniCreditBank provides a parser for Unicredit Bank + * - Hypovereinsbank + * @package Jejik\MT940\Parser + */ +class UniCreditBank extends GermanBank +{ + /** + * Check whether provided MT940 statement string can be parsed by this parser + */ + public function accept(string $text): bool + { + // unique identifier check + $identifierCheck = false; // TODO implement after clearing field :20: with Bank + if ($identifierCheck) { + return true; + } + + // if not check it's BLZ + return $this->isBLZAllowed($text); + } + + /** + * Get an array of allowed BLZ for this bank + */ + public function getAllowedBLZ(): array + { + return [ + '10020890', + '16020086', + '17020086', + '18020086', + '20030000', + '20730001', + '20730002', + '20730003', + '20730004', + '20730005', + '20730006', + '20730007', + '20730008', + '20730009', + '20730010', + '20730011', + '20730012', + '20730013', + '20730014', + '20730015', + '20730016', + '20730017', + '20730018', + '20730019', + '20730020', + '20730021', + '20730022', + '20730023', + '20730024', + '20730025', + '20730026', + '20730027', + '20730028', + '20730029', + '20730030', + '20730031', + '20730032', + '20730033', + '20730034', + '20730035', + '20730036', + '20730037', + ]; + } +} diff --git a/lib/Jejik/MT940/Reader.php b/lib/Jejik/MT940/Reader.php index 38cbd67..5f5e693 100644 --- a/lib/Jejik/MT940/Reader.php +++ b/lib/Jejik/MT940/Reader.php @@ -23,64 +23,95 @@ class Reader { // Properties {{{ + /** + * Is an absolute file name of bank statement which is to be parsed + * @var string + */ + private $fileName; + /** * @var array A class map of bank parsers */ - private $parsers = array(); + private $parsers = []; /** * @var array All the parsers shipped in this package */ private $defaultParsers = array( - 'ABN-AMRO' => 'Jejik\MT940\Parser\AbnAmro', - 'ING' => 'Jejik\MT940\Parser\Ing', - 'Knab' => 'Jejik\MT940\Parser\Knab', - 'PostFinance' => 'Jejik\MT940\Parser\PostFinance', - 'Rabobank' => 'Jejik\MT940\Parser\Rabobank', - 'Sns' => 'Jejik\MT940\Parser\Sns', - 'Triodos' => 'Jejik\MT940\Parser\Triodos' + 'ABN-AMRO' => Parser\AbnAmro::class, + 'Commerzbank' => Parser\Commerzbank::class, + 'DeutscheBank' => Parser\DeutscheBank::class, + 'ING' => Parser\Ing::class, + 'Knab' => Parser\Knab::class, + 'LandesBankBerlin' => Parser\LandesBankBerlin::class, + 'NuaPayBank' => Parser\NuaPayBank::class, + 'OldenburgischeLandesbank' => Parser\OldenburgischeLandesbank::class, + 'PostFinance' => Parser\PostFinance::class, + 'Rabobank' => Parser\Rabobank::class, + 'Sns' => Parser\Sns::class, + 'Sparkasse' => Parser\Sparkasse::class, + 'StarMoney' => Parser\StarMoney::class, + 'Triodos' => Parser\Triodos::class, + 'UniCreditBank' => Parser\UniCreditBank::class, ); /** * @see setStatementClass() * @var string|callable */ - private $statementClass = 'Jejik\MT940\Statement'; + private $statementClass = Statement::class; /** * @see setAccountClass() * @var string|callable */ - private $accountClass = 'Jejik\MT940\Account'; + private $accountClass = Account::class; /** * @see setContraAccountClass() * @var string|callable */ - private $contraAccountClass = 'Jejik\MT940\Account'; + private $contraAccountClass = Account::class; /** * @see setTransactionClass() * @var string|callable */ - private $transactionClass = 'Jejik\MT940\Transaction'; + private $transactionClass = Transaction::class; /** * @see setOpeningBalanceClass() * @var string|callable */ - private $openingBalanceClass = 'Jejik\MT940\Balance'; + private $openingBalanceClass = Balance::class; /** * @see setClosingBalanceClass() * @var string|callable */ - private $closingBalanceClass = 'Jejik\MT940\Balance'; + private $closingBalanceClass = Balance::class; // }}} // Parser management {{{ + /** + * Get bank statement file name for this parser + */ + public function getFileName(): string + { + return $this->fileName; + } + + /** + * Set bank statement file name for this parser + */ + public function setFileName(string $fileName): self + { + $this->fileName = $fileName; + return $this; + } + /** * Get a list of default parsers shippen in this package */ @@ -94,35 +125,39 @@ public function getDefaultParsers(): array */ public function getParsers(): array { - return $this->parsers; + $output_array = []; + foreach ($this->parsers as $name => $parser) { + $output_array[$name] = $parser[0]; // get the classname + } + return $output_array; } /** * Add a parser type to the list of parsers - * - * Some parsers can conflict with each other so order is important. Use - * the $before parameter in insert a parser in a specific place. - * + * - Some parsers can conflict with each other so order is important. Use + * -- the $before parameter in insert a parser in a specific place. * @param string $name Name of the parser * @param mixed $class Classname of the parser * @param mixed $before Insert the new parser before this parser + * @param array $arguments An array of arguments. Its elements will be passed as individual parameters to the + * constructor of the parser. + * @return $this * @throws \RuntimeException if the $before parser does not exist */ - public function addParser(string $name, $class, $before = null): self + public function addParser(string $name, $class, $before = null, $arguments = []): self { if ($before === null) { - $this->parsers[$name] = $class; + $this->parsers[$name] = [$class, $arguments]; return $this; } - if (($offset = array_search($before, array_keys($this->parsers))) !== false) { - $this->parsers = array_slice($this->parsers, 0, $offset, true) + $offset = array_search($before, array_keys($this->parsers)); + if ($offset !== false) { + $this->parsers = array_slice($this->parsers, $offset, 0, true) + array($name => $class) + array_slice($this->parsers, $offset, null, true); - return $this; } - throw new \RuntimeException(sprintf('Parser "%s" does not exist.', $before)); } @@ -155,9 +190,12 @@ public function removeParser(string $name): void * * @param array $parsers Associative array of 'name' => 'class' */ - public function setParsers(array $parsers = array()): void + public function setParsers(array $parsers = []): self { - $this->parsers = $parsers; + $this->parsers = array_map(function ($className) { + return [$className, []]; + }, $parsers); + return $this; } // }}} @@ -205,9 +243,15 @@ public function setStatementClass($statementClass): self * @param AccountInterface $account Account number * @param string $number Statement sequence number */ - public function createStatement(AccountInterface $account, string $number): ?StatementInterface - { - return $this->createObject($this->statementClass, 'Jejik\MT940\StatementInterface', array($account, $number)); + public function createStatement( + AccountInterface $account, + string $number + ): ?StatementInterface { + return $this->createObject( + $this->statementClass, + StatementInterface::class, + [$account, $number] + ); } /** @@ -246,10 +290,22 @@ public function setAccountClass($accountClass): self /** * Create a Account object + * @return AccountInterface */ - public function createAccount(string $accountNumber): AccountInterface + public function createAccount(string $accountNumber) { - return $this->createObject($this->accountClass, 'Jejik\MT940\AccountInterface', array($accountNumber)); + /** @var Account $object */ + $object = $this->createObject( + $this->accountClass, + AccountInterface::class, + [$accountNumber] + ); + + if (!empty($accountNumber)) { + $object->setNumber($accountNumber); + } + + return $object; } /** @@ -291,7 +347,11 @@ public function setContraAccountClass($contraAccountClass): self */ public function createContraAccount(?string $accountNumber): AccountInterface { - return $this->createObject($this->contraAccountClass, 'Jejik\MT940\AccountInterface', array($accountNumber)); + return $this->createObject( + $this->contraAccountClass, + AccountInterface::class, + [$accountNumber] + ); } /** @@ -331,7 +391,10 @@ public function setTransactionClass($transactionClass): self */ public function createTransaction(): TransactionInterface { - return $this->createObject($this->transactionClass, 'Jejik\MT940\TransactionInterface'); + return $this->createObject( + $this->transactionClass, + TransactionInterface::class + ); } /** @@ -371,7 +434,10 @@ public function setOpeningBalanceClass($openingBalanceClass): self */ public function createOpeningBalance(): BalanceInterface { - return $this->createObject($this->openingBalanceClass, 'Jejik\MT940\BalanceInterface'); + return $this->createObject( + $this->openingBalanceClass, + BalanceInterface::class + ); } /** @@ -411,19 +477,22 @@ public function setClosingBalanceClass($closingBalanceClass): self */ public function createClosingBalance(): BalanceInterface { - return $this->createObject($this->closingBalanceClass, 'Jejik\MT940\BalanceInterface'); + return $this->createObject( + $this->closingBalanceClass, + BalanceInterface::class + ); } /** * Create an object of a specified interface * * @param string|callable $className Classname or a callable that returns an object instance - * @param string $interface The interface the class must implement + * @param mixed $interface The interface the class must implement //TODO mixed is a workaround for StdClass * @param array $params Parameters to pass to the callable * * @return object An object that implements the interface */ - protected function createObject($className, $interface, $params = array()) + protected function createObject($className, $interface, $params = []) { if (is_string($className) && class_exists($className)) { $object = new $className(); @@ -440,28 +509,37 @@ protected function createObject($className, $interface, $params = array()) return $object; } - // }}} - /** * Get MT940 statements from the input text * * @param string $text * @return Statement[] * @throws \RuntimeException if no suitable parser is found + * @throws Exception\NoParserFoundException + * @throws \Exception */ - public function getStatements(string $text): array + public function getStatements(string $text = null): array { + if ($text === null) { + $text = file_get_contents($this->getFileName()); + } + if ($text === null || strlen(trim($text)) == 0) { + throw new \Exception("No text is found for parsing."); + } + if (($pos = strpos($text, ':20:')) === false) { + throw new \RuntimeException('Not an MT940 statement'); + } if (!$this->parsers) { $this->addParsers($this->getDefaultParsers()); } - foreach ($this->parsers as $class) { - $parser = new $class($this); + foreach ($this->parsers as [$class, $additionalConstructorArgs]) { + $parser = new $class($this, ...$additionalConstructorArgs); if ($parser->accept($text)) { return $parser->parse($text); } } - throw new \RuntimeException('No suitable parser found.'); + throw new Exception\NoParserFoundException(); } } diff --git a/lib/Jejik/MT940/Statement.php b/lib/Jejik/MT940/Statement.php index 7d30e0e..f5f4082 100644 --- a/lib/Jejik/MT940/Statement.php +++ b/lib/Jejik/MT940/Statement.php @@ -46,7 +46,7 @@ class Statement implements StatementInterface /** * @var TransactionInterface[] */ - private $transactions = array(); + private $transactions = []; // }}} @@ -80,7 +80,7 @@ public function getAccount(): ?AccountInterface /** * Setter for account */ - public function setAccount(?AccountInterface $account): StatementInterface + public function setAccount(?AccountInterface $account = null): StatementInterface { $this->account = $account; return $this; @@ -97,7 +97,7 @@ public function getOpeningBalance(): ?BalanceInterface /** * Setter for openingBalance */ - public function setOpeningBalance(?BalanceInterface $openingBalance): StatementInterface + public function setOpeningBalance(?BalanceInterface $openingBalance = null): StatementInterface { $this->openingBalance = $openingBalance; return $this; @@ -114,7 +114,7 @@ public function getClosingBalance(): ?BalanceInterface /** * Setter for closingBalance */ - public function setClosingBalance(?BalanceInterface $closingBalance): StatementInterface + public function setClosingBalance(?BalanceInterface $closingBalance = null): StatementInterface { $this->closingBalance = $closingBalance; return $this; @@ -133,9 +133,10 @@ public function getTransactions(): array /** * Add a transaction */ - public function addTransaction(TransactionInterface $transaction): void + public function addTransaction(TransactionInterface $transaction): ?StatementInterface { $this->transactions[] = $transaction; + return $this; } // }}} } diff --git a/lib/Jejik/MT940/StatementInterface.php b/lib/Jejik/MT940/StatementInterface.php index a3cbc79..2597b12 100644 --- a/lib/Jejik/MT940/StatementInterface.php +++ b/lib/Jejik/MT940/StatementInterface.php @@ -39,7 +39,7 @@ public function getAccount(): ?AccountInterface; /** * Setter for account */ - public function setAccount(?AccountInterface $account): self; + public function setAccount(?AccountInterface $account = null): self; /** * Getter for openingBalance @@ -49,7 +49,7 @@ public function getOpeningBalance(): ?BalanceInterface; /** * Setter for openingBalance */ - public function setOpeningBalance(?BalanceInterface $openingBalance): self; + public function setOpeningBalance(?BalanceInterface $openingBalance = null): self; /** * Getter for closingBalance @@ -59,7 +59,7 @@ public function getClosingBalance(): ?BalanceInterface; /** * Setter for closingBalance */ - public function setClosingBalance(?BalanceInterface $closingBalance): self; + public function setClosingBalance(?BalanceInterface $closingBalance = null): self; /** * Getter for transactions @@ -71,5 +71,5 @@ public function getTransactions(): array; /** * Add a transaction */ - public function addTransaction(TransactionInterface $transaction): void; + public function addTransaction(TransactionInterface $transaction): ?StatementInterface; } diff --git a/lib/Jejik/MT940/Transaction.php b/lib/Jejik/MT940/Transaction.php index 9f49448..4399c68 100644 --- a/lib/Jejik/MT940/Transaction.php +++ b/lib/Jejik/MT940/Transaction.php @@ -48,6 +48,81 @@ class Transaction implements TransactionInterface */ private $bookDate; + /** + * @var string + */ + private $code; + + /** + * @var string + */ + private $ref; + + /** + * @var string + */ + private $bankRef; + + /** + * @var string + */ + private $gvc; + + /** + * @var string + */ + private $txText; + + /** + * @var string + */ + private $primanota; + + /** + * @var string + */ + private $extCode; + + /** + * @var string + */ + private $eref; + + /** + * @var string + */ + private $bic; + + /** + * @var string + */ + private $iban; + + /** + * @var string + */ + private $accountHolder; + + /** + * @var string + */ + private $kref; + + /** + * @var string + */ + private $mref; + + /** + * @var string + */ + private $cred; + + /** + * @var string + */ + private $svwz; + // }}} // Getters and setters {{{ @@ -63,7 +138,7 @@ public function getContraAccount(): ?AccountInterface /** * Setter for contraAccount */ - public function setContraAccount(?AccountInterface $contraAccount): TransactionInterface + public function setContraAccount(?AccountInterface $contraAccount = null): TransactionInterface { $this->contraAccount = $contraAccount; return $this; @@ -91,7 +166,7 @@ public function setAmount(float $amount): TransactionInterface */ public function getDescription(): ?string { - return $this->description; + return ($this->description !== null) ? trim($this->description) : null; } /** @@ -114,7 +189,7 @@ public function getValueDate(): ?\DateTime /** * Setter for valueDate */ - public function setValueDate(?\DateTime $valueDate): TransactionInterface + public function setValueDate(?\DateTime $valueDate = null): TransactionInterface { $this->valueDate = $valueDate; return $this; @@ -131,11 +206,268 @@ public function getBookDate(): ?\DateTime /** * Setter for bookDate */ - public function setBookDate(?\DateTime $bookDate): TransactionInterface + public function setBookDate(?\DateTime $bookDate = null): TransactionInterface { $this->bookDate = $bookDate; return $this; } + /** + * Get Code for this transaction + */ + public function getCode(): ?string + { + return ($this->code !== null) ? trim($this->code) : null; + } + + /** + * Set Code for this transaction + * @param string $code + * @return $this + */ + public function setCode(string $code = null): TransactionInterface + { + $this->code = $code; + return $this; + } + + /** + * Get Ref for this transaction + */ + public function getRef(): ?string + { + return ($this->ref !== null) ? trim($this->ref) : null; + } + + /** + * Set Ref for this transaction + */ + public function setRef(string $ref = null): TransactionInterface + { + $this->ref = $ref; + return $this; + } + + /** + * Get BankRef for this transaction + */ + public function getBankRef(): ?string + { + return ($this->bankRef !== null) ? trim($this->bankRef) : null; + } + + /** + * Set BankRef for this transaction + */ + public function setBankRef(string $bankRef = null): TransactionInterface + { + $this->bankRef = $bankRef; + return $this; + } + + /** + * Get GVC for this transaction + */ + public function getGVC(): ?string + { + return ($this->gvc !== null) ? trim($this->gvc) : null; + } + + /** + * Set GVC for this transaction + */ + public function setGVC(string $gvc = null): TransactionInterface + { + $this->gvc = $gvc; + return $this; + } + + /** + * Get txText for this transaction + */ + public function getTxText(): ?string + { + return ($this->txText !== null) ? trim($this->txText) : null; + } + + /** + * Set txText for this transaction + */ + public function setTxText(string $txText = null): TransactionInterface + { + $this->txText = $txText; + return $this; + } + + /** + * Get primanota for this transaction + */ + public function getPrimanota(): ?string + { + return ($this->primanota !== null) ? trim($this->primanota) : null; + } + + /** + * Set primanota for this transaction + */ + public function setPrimanota(string $primanota = null): TransactionInterface + { + $this->primanota = $primanota; + return $this; + } + + /** + * Get extCode for this transaction + */ + public function getExtCode(): ?string + { + return ($this->extCode !== null) ? trim($this->extCode) : null; + } + + /** + * Set ExtCode for this transaction + */ + public function setExtCode(string $extCode = null): TransactionInterface + { + $this->extCode = $extCode; + return $this; + } + + /** + * Get ERef for this transaction + */ + public function getEref(): ?string + { + return ($this->eref !== null) ? trim($this->eref) : null; + } + + /** + * Set Eref for this transaction + */ + public function setEref(string $eref = null): TransactionInterface + { + $this->eref = $eref; + return $this; + } + + /** + * Get BIC for this transaction + */ + public function getBIC(): string + { + return trim($this->bic); + } + + /** + * Set BIC for this transaction + */ + public function setBIC(string $bic = null): TransactionInterface + { + $this->bic = $bic; + return $this; + } + + /** + * Get IBAN for this transaction + */ + public function getIBAN(): string + { + return trim($this->iban); + } + + /** + * Set IBAN for this transaction + */ + public function setIBAN(string $iban = null): TransactionInterface + { + $this->iban = $iban; + return $this; + } + + /** + * Get Account Holder for this transaction + */ + public function getAccountHolder(): ?string + { + return ($this->accountHolder !== null) ? trim($this->accountHolder) : null; + } + + /** + * Set IBAN for this transaction + */ + public function setAccountHolder(string $accountHolder = null): TransactionInterface + { + $this->accountHolder = $accountHolder; + return $this; + } + + /** + * Get Kref for this transaction + */ + public function getKref(): ?string + { + return ($this->kref !== null) ? trim($this->kref) : null; + } + + /** + * Set Kref for this transaction + */ + public function setKref(string $kref = null): TransactionInterface + { + $this->kref = $kref; + return $this; + } + + /** + * Get Mref for this transaction + */ + public function getMref(): ?string + { + return ($this->mref !== null) ? trim($this->mref) : null; + } + + /** + * Set Mref for this transaction + */ + public function setMref(string $mref = null): TransactionInterface + { + $this->mref = $mref; + return $this; + } + + /** + * Get Cred for this transaction + */ + public function getCred(): ?string + { + return ($this->cred !== null) ? trim($this->cred) : null; + } + + /** + * Set Cred for this transaction + */ + public function setCred(string $cred = null): TransactionInterface + { + $this->cred = $cred; + return $this; + } + + /** + * Get Svwz for this transaction + */ + public function getSvwz(): ?string + { + return ($this->svwz !== null) ? trim($this->svwz) : null; + } + + /** + * Set Svwz for this transaction + */ + public function setSvwz(string $svwz = null): TransactionInterface + { + $this->svwz = $svwz; + return $this; + } + // }}} } diff --git a/lib/Jejik/MT940/TransactionInterface.php b/lib/Jejik/MT940/TransactionInterface.php index 7ca4023..3bfca86 100644 --- a/lib/Jejik/MT940/TransactionInterface.php +++ b/lib/Jejik/MT940/TransactionInterface.php @@ -29,7 +29,7 @@ public function getContraAccount(): ?AccountInterface; /** * Setter for contraAccount */ - public function setContraAccount(?AccountInterface $contraAccount): self; + public function setContraAccount(?AccountInterface $contraAccount = null): self; /** * Getter for amount @@ -59,7 +59,7 @@ public function getValueDate(): ?\DateTime; /** * Setter for valueDate */ - public function setValueDate(?\DateTime $valueDate): self; + public function setValueDate(?\DateTime $valueDate = null): self; /** * Getter for bookDate @@ -69,5 +69,159 @@ public function getBookDate(): ?\DateTime; /** * Setter for bookDate */ - public function setBookDate(?\DateTime $bookDate): self; + public function setBookDate(?\DateTime $bookDate = null): self; + /** + * Get Code for this transaction + * @return null|string + */ + public function getCode(); + + /** + * Set Code for this transaction + */ + public function setCode(string $code = null): self; + + /** + * Get Ref for this transaction + */ + public function getRef(): ?string; + + /** + * Set Ref for this transaction + */ + public function setRef(string $ref = null): TransactionInterface; + + /** + * Get BankRef for this transaction + */ + public function getBankRef(): ?string; + + /** + * Set BankRef for this transaction + */ + public function setBankRef(string $bankRef = null): TransactionInterface; + + /** + * Get GVC for this transaction + */ + public function getGVC(): ?string; + + /** + * Set GVC for this transaction + */ + public function setGVC(string $gvc = null): TransactionInterface; + + /** + * Get extCode for this transaction + */ + public function getExtCode(): ?string; + + /** + * Set ExtCode for this transaction + */ + public function setExtCode(string $extCode = null): TransactionInterface; + + /** + * Get txText for this transaction + */ + public function getTxText(): ?string; + + /** + * Set txText for this transaction + */ + public function setTxText(string $txText = null): TransactionInterface; + + /** + * Get primanota for this transaction + */ + public function getPrimanota(): ?string; + + /** + * Set primanota for this transaction + */ + public function setPrimanota(string $primanota = null): TransactionInterface; + + /** + * Get ERef for this transaction + */ + public function getEref(): ?string; + + /** + * Set Eref for this transaction + * @param string $eref + * @return $this + */ + public function setEref(string $eref = null): TransactionInterface; + + /** + * Get BIC for this transaction + */ + public function getBIC(): ?string; + + /** + * Set BIC for this transaction + */ + public function setBIC(string $bic = null): TransactionInterface; + + /** + * Get IBAN for this transaction + */ + public function getIBAN(): ?string; + + /** + * Set IBAN for this transaction + * @param string $iban + * @return $this + */ + public function setIBAN(string $iban = null): TransactionInterface; + + /** + * Get Account Holder for this transaction + */ + public function getAccountHolder(): ?string; + + /** + * Set IBAN for this transaction + */ + public function setAccountHolder(string $accountHolder = null): TransactionInterface; + + /** + * Get Kref for this transaction + */ + public function getKref(): ?string; + + /** + * Set Kref for this transaction + */ + public function setKref(string $kref = null): TransactionInterface; + + /** + * Get Mref for this transaction + */ + public function getMref(): ?string; + + /** + * Set Mref for this transaction + */ + public function setMref(string $mref = null): TransactionInterface; + + /** + * Get Cred for this transaction + */ + public function getCred(): ?string; + + /** + * Set Cred for this transaction + */ + public function setCred(string $cred = null): TransactionInterface; + + /** + * Get Svwz for this transaction + */ + public function getSvwz(): ?string; + + /** + * Set Svwz for this transaction + */ + public function setSvwz(string $svwz = null): TransactionInterface; } diff --git a/tests/Jejik/Tests/MT940/Fixture/Parser.php b/tests/Jejik/Tests/MT940/Fixture/Parser.php index b0bd6f4..f986cd6 100644 --- a/tests/Jejik/Tests/MT940/Fixture/Parser.php +++ b/tests/Jejik/Tests/MT940/Fixture/Parser.php @@ -30,4 +30,12 @@ public function accept(string $text): bool { return substr($text, 0, 11) === ':20:GENERIC'; } + + /** + * Get an array of allowed BLZ for this bank + */ + public function getAllowedBLZ(): array + { + return []; + } } diff --git a/tests/Jejik/Tests/MT940/Fixture/document/sparkasse.txt b/tests/Jejik/Tests/MT940/Fixture/document/sparkasse.txt new file mode 100644 index 0000000..ba160c8 --- /dev/null +++ b/tests/Jejik/Tests/MT940/Fixture/document/sparkasse.txt @@ -0,0 +1,21 @@ +:20:STARTUMSE +:25:87052000/123456789 +:28C:00000/001 +:60F:C190215EUR194,57 +:61:1902180218DR20,00N037NONREF +:86:106?00KARTENZAHLUNG?109262?20SVWZ+2019-02-15T20.10 Debit?21k. +4 2019-12?22ABWA+Aral Tankstelle Chemni?23tz Leipziger Straße 257 +//Ch?24emnitz/DE?30DRESDEFF430?31DE95430800830802029200?32ARAL AG +?34011 +:62F:C190218EUR174,57 +- +:20:STARTUMSE +:25:87052000/123456789 +:28C:00000/001 +:60F:C190218EUR174,57 +:61:1902190219DR20,00N033NONREF +:86:177?00ONLINE-UEBERWEISUNG?109310?20SVWZ+Apple Pay?21DATUM 19. +02.2019, 13.24 UHR?221.TAN 002153?30NTSBDEB1XXX?31DE1234567890123 +4567890?32Max Mustermann?34997 +:62F:C190219EUR154,57 +- diff --git a/tests/Jejik/Tests/MT940/Parser/AbnAmroTest.php b/tests/Jejik/Tests/MT940/Parser/AbnAmroTest.php index 7545181..2ceb231 100644 --- a/tests/Jejik/Tests/MT940/Parser/AbnAmroTest.php +++ b/tests/Jejik/Tests/MT940/Parser/AbnAmroTest.php @@ -24,12 +24,15 @@ */ class AbnAmroTest extends TestCase { - public $statements = array(); + public $statements = []; + /** + * @throws \Jejik\MT940\Exception\NoParserFoundException + */ public function setUp(): void { $reader = new Reader(); - $reader->addParser('AbnAmro', 'Jejik\MT940\Parser\AbnAmro'); + $reader->addParser('AbnAmro', \Jejik\MT940\Parser\AbnAmro::class); $this->statements = $reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/abnamro.txt')); } @@ -45,7 +48,7 @@ public function testStatement() public function testBalance() { $balance = $this->statements[0]->getOpeningBalance(); - $this->assertInstanceOf('Jejik\MT940\Balance', $balance); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $balance); $this->assertEquals('2011-05-22 00:00:00', $balance->getDate()->format('Y-m-d H:i:s')); $this->assertEquals('EUR', $balance->getCurrency()); $this->assertEquals(3236.28, $balance->getAmount()); @@ -78,11 +81,11 @@ public function testContinuedStatement() $this->assertEquals('19322/1', $this->statements[1]->getNumber()); $balance = $this->statements[1]->getOpeningBalance(); - $this->assertInstanceOf('Jejik\MT940\Balance', $balance); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $balance); $this->assertEquals(2876.84, $balance->getAmount()); $balance = $this->statements[1]->getClosingBalance(); - $this->assertInstanceOf('Jejik\MT940\Balance', $balance); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $balance); $this->assertEquals(1849.75, $balance->getAmount()); } diff --git a/tests/Jejik/Tests/MT940/Parser/IngTest.php b/tests/Jejik/Tests/MT940/Parser/IngTest.php index be20e07..83e025c 100644 --- a/tests/Jejik/Tests/MT940/Parser/IngTest.php +++ b/tests/Jejik/Tests/MT940/Parser/IngTest.php @@ -49,7 +49,7 @@ public function testBalance($statements) { /** @var \Jejik\MT940\Balance $balance */ $balance = $statements[0]->getOpeningBalance(); - $this->assertInstanceOf('Jejik\MT940\Balance', $balance); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $balance); $this->assertEquals('2010-07-22 00:00:00', $balance->getDate()->format('Y-m-d H:i:s')); $this->assertEquals('EUR', $balance->getCurrency()); $this->assertEquals(0.0, $balance->getAmount()); @@ -69,7 +69,7 @@ public function testTransaction($statements) $this->assertEquals(null, $transactions[0]->getValueDate()); $this->assertEquals(-25.03, $transactions[0]->getAmount()); - $expected = " RC AFREKENING BETALINGSVERKEER\r\n" + $expected = "RC AFREKENING BETALINGSVERKEER\r\n" . "BETREFT REKENING 4715589 PERIODE: 01-10-2010 / 31-12-2010\r\n" . "ING Bank N.V. tarifering ING"; @@ -92,11 +92,12 @@ public function testBookDate($statements) /** * @dataProvider statementsProvider + * @throws \Jejik\MT940\Exception\NoParserFoundException */ - public function statementsProvider() + public function statementsProvider(): array { $reader = new Reader(); - $reader->addParser('Ing', 'Jejik\MT940\Parser\Ing'); + $reader->addParser('Ing', \Jejik\MT940\Parser\Ing::class); return array( array($reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/ing-dos.txt'))), diff --git a/tests/Jejik/Tests/MT940/Parser/KnabTest.php b/tests/Jejik/Tests/MT940/Parser/KnabTest.php index 34907c1..bcb6536 100644 --- a/tests/Jejik/Tests/MT940/Parser/KnabTest.php +++ b/tests/Jejik/Tests/MT940/Parser/KnabTest.php @@ -24,12 +24,15 @@ */ class KnabTest extends TestCase { - public $statements = array(); + public $statements = []; + /** + * @throws \Jejik\MT940\Exception\NoParserFoundException + */ public function setUp(): void { $reader = new Reader(); - $reader->addParser('Knab', 'Jejik\MT940\Parser\Knab'); + $reader->addParser('Knab', \Jejik\MT940\Parser\Knab::class); $this->statements = $reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/knab.txt')); } @@ -45,7 +48,7 @@ public function testStatement() public function testBalance() { $balance = $this->statements[0]->getOpeningBalance(); - $this->assertInstanceOf('Jejik\MT940\Balance', $balance); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $balance); $this->assertEquals('2014-05-07 00:00:00', $balance->getDate()->format('Y-m-d H:i:s')); $this->assertEquals('EUR', $balance->getCurrency()); $this->assertEquals(0, $balance->getAmount()); diff --git a/tests/Jejik/Tests/MT940/Parser/PostFinanceTest.php b/tests/Jejik/Tests/MT940/Parser/PostFinanceTest.php index 28c7f05..6768331 100644 --- a/tests/Jejik/Tests/MT940/Parser/PostFinanceTest.php +++ b/tests/Jejik/Tests/MT940/Parser/PostFinanceTest.php @@ -24,12 +24,15 @@ */ class PostFinanceTest extends TestCase { - public $statements = array(); + public $statements = []; + /** + * @throws \Jejik\MT940\Exception\NoParserFoundException + */ public function setUp(): void { $reader = new Reader(); - $reader->addParser('PostFinance', 'Jejik\MT940\Parser\PostFinance'); + $reader->addParser('PostFinance', \Jejik\MT940\Parser\PostFinance::class); $this->statements = $reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/postfinance.txt')); } @@ -45,7 +48,7 @@ public function testStatement() public function testBalance() { $balance = $this->statements[0]->getOpeningBalance(); - $this->assertInstanceOf('Jejik\MT940\Balance', $balance); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $balance); $this->assertEquals('2013-11-30 00:00:00', $balance->getDate()->format('Y-m-d H:i:s')); $this->assertEquals('CHF', $balance->getCurrency()); $this->assertEquals(0, $balance->getAmount()); diff --git a/tests/Jejik/Tests/MT940/Parser/RabobankIbanTest.php b/tests/Jejik/Tests/MT940/Parser/RabobankIbanTest.php index d141eb8..63cbf15 100644 --- a/tests/Jejik/Tests/MT940/Parser/RabobankIbanTest.php +++ b/tests/Jejik/Tests/MT940/Parser/RabobankIbanTest.php @@ -24,12 +24,15 @@ */ class RabobankIbanTest extends TestCase { - public $statements = array(); + public $statements = []; + /** + * @throws \Jejik\MT940\Exception\NoParserFoundException + */ public function setUp(): void { $reader = new Reader(); - $reader->addParser('Rabobank', 'Jejik\MT940\Parser\Rabobank'); + $reader->addParser('Rabobank', \Jejik\MT940\Parser\Rabobank::class); $this->statements = $reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/rabobank-iban.txt')); } @@ -46,7 +49,7 @@ public function testStatement() public function testBalance() { $balance = $this->statements[0]->getOpeningBalance(); - $this->assertInstanceOf('Jejik\MT940\Balance', $balance); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $balance); $this->assertEquals('2013-01-01 00:00:00', $balance->getDate()->format('Y-m-d H:i:s')); $this->assertEquals('EUR', $balance->getCurrency()); $this->assertEquals(1000, $balance->getAmount()); diff --git a/tests/Jejik/Tests/MT940/Parser/RabobankTest.php b/tests/Jejik/Tests/MT940/Parser/RabobankTest.php index 050f727..51c9178 100644 --- a/tests/Jejik/Tests/MT940/Parser/RabobankTest.php +++ b/tests/Jejik/Tests/MT940/Parser/RabobankTest.php @@ -24,12 +24,15 @@ */ class RabobankTest extends TestCase { - public $statements = array(); + public $statements = []; + /** + * @throws \Jejik\MT940\Exception\NoParserFoundException + */ public function setUp(): void { $reader = new Reader(); - $reader->addParser('Rabobank', 'Jejik\MT940\Parser\Rabobank'); + $reader->addParser('Rabobank', \Jejik\MT940\Parser\Rabobank::class); $this->statements = $reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/rabobank.txt')); } @@ -46,7 +49,7 @@ public function testStatement() public function testBalance() { $balance = $this->statements[0]->getOpeningBalance(); - $this->assertInstanceOf('Jejik\MT940\Balance', $balance); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $balance); $this->assertEquals('2011-06-14 00:00:00', $balance->getDate()->format('Y-m-d H:i:s')); $this->assertEquals('EUR', $balance->getCurrency()); $this->assertEquals(473.17, $balance->getAmount()); diff --git a/tests/Jejik/Tests/MT940/Parser/SnsTest.php b/tests/Jejik/Tests/MT940/Parser/SnsTest.php index e239f51..e0acf71 100644 --- a/tests/Jejik/Tests/MT940/Parser/SnsTest.php +++ b/tests/Jejik/Tests/MT940/Parser/SnsTest.php @@ -24,12 +24,15 @@ */ class SnsTest extends TestCase { - public $statements = array(); + public $statements = []; + /** + * @throws \Jejik\MT940\Exception\NoParserFoundException + */ public function setUp(): void { $reader = new Reader(); - $reader->addParser('Sns', 'Jejik\MT940\Parser\Sns'); + $reader->addParser('Sns', \Jejik\MT940\Parser\Sns::class); $this->statements = $reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/sns.txt')); } @@ -46,7 +49,7 @@ public function testStatement() public function testOpeningBalance() { $balance = $this->statements[0]->getOpeningBalance(); - $this->assertInstanceOf('Jejik\MT940\Balance', $balance); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $balance); $this->assertEquals('2012-06-08 00:00:00', $balance->getDate()->format('Y-m-d H:i:s')); $this->assertEquals('EUR', $balance->getCurrency()); $this->assertEquals(1234.56, $balance->getAmount()); @@ -55,7 +58,7 @@ public function testOpeningBalance() public function testClosingBalance() { $balance = $this->statements[0]->getClosingBalance(); - $this->assertInstanceOf('Jejik\MT940\Balance', $balance); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $balance); $this->assertEquals('2012-06-08 00:00:00', $balance->getDate()->format('Y-m-d H:i:s')); $this->assertEquals('EUR', $balance->getCurrency()); $this->assertEquals(1209.56, $balance->getAmount()); diff --git a/tests/Jejik/Tests/MT940/Parser/SparkasseTest.php b/tests/Jejik/Tests/MT940/Parser/SparkasseTest.php new file mode 100644 index 0000000..366635c --- /dev/null +++ b/tests/Jejik/Tests/MT940/Parser/SparkasseTest.php @@ -0,0 +1,96 @@ + + * Licensed under the MIT license + * + * For the full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + */ + +namespace Jejik\Tests\MT940\Parser; + +use Jejik\MT940\Reader; +use PHPUnit\Framework\TestCase; + +/** + * Tests for Jejik\MT940\Parser\Sparkasse + * + * @author Dominic Richter + */ +class SparkasseTest extends TestCase +{ + public $statements = []; + + /** + * @throws \Jejik\MT940\Exception\NoParserFoundException + */ + public function setUp(): void + { + $reader = new Reader(); + $reader->addParser('Sparkasse', \Jejik\MT940\Parser\Sparkasse::class); + $this->statements = $reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/sparkasse.txt')); + } + + public function testStatement() + { + $this->assertCount(2, $this->statements, 'Assert counting statements.'); + $statement = $this->statements[0]; + + $this->assertEquals('00000/001', $statement->getNumber()); + $this->assertEquals('87052000/123456789', $statement->getAccount()->getNumber()); + } + + public function testBalance() + { + $balance = $this->statements[0]->getOpeningBalance(); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $balance); + $this->assertEquals('2019-02-15 00:00:00', $balance->getDate()->format('Y-m-d H:i:s')); + $this->assertEquals('EUR', $balance->getCurrency()); + $this->assertEquals(194.57, $balance->getAmount()); + } + + public function testTransaction() + { + $transactions = $this->statements[1]->getTransactions(); + + $this->assertCount(1, $transactions); + + $this->assertNotNull($transactions[0]->getContraAccount()); + + $this->assertEquals(-20.00, $transactions[0]->getAmount()); + $expectedDescription = "177?00ONLINE-UEBERWEISUNG?109310?20SVWZ+Apple Pay?21DATUM 19.\r\n" . + "02.2019, 13.24 UHR?221.TAN 002153?30NTSBDEB1XXX?31DE1234567890123\r\n" . + "4567890?32Max Mustermann?34997"; + $this->assertEquals($expectedDescription, $transactions[0]->getDescription()); + $this->assertEquals('2019-02-19 00:00:00', $transactions[0]->getValueDate()->format('Y-m-d H:i:s'), 'Assert Value Date'); + $this->assertEquals('2019-02-19 00:00:00', $transactions[0]->getBookDate()->format('Y-m-d H:i:s'), 'Assert Book Date'); + + $this->assertNull($transactions[0]->getCode()); + $this->assertNull($transactions[0]->getRef()); + $this->assertNull($transactions[0]->getBankRef()); + + $this->assertEquals('177', $transactions[0]->getGVC()); + $this->assertEquals('ONLINE-UEBERWEISUNG', $transactions[0]->getTxText()); + $this->assertEquals('9310', $transactions[0]->getPrimanota()); + $this->assertEquals('997', $transactions[0]->getExtCode()); + + $this->assertNull($transactions[0]->getEref()); + + $this->assertEquals('NTSBDEB1XXX', $transactions[0]->getBIC()); + $this->assertEquals('DE12345678901234567890', $transactions[0]->getIBAN()); + $this->assertEquals('Max Mustermann', $transactions[0]->getAccountHolder()); + + $this->assertNull($transactions[0]->getKref()); + $this->assertNull($transactions[0]->getMref()); + $this->assertNull($transactions[0]->getCred()); + + $this->assertEquals('Apple PayDATUM 19.02.2019, 13.24 UHR1.TAN 002153', $transactions[0]->getSvwz()); + $this->assertEquals('DE12345678901234567890', $transactions[0]->getContraAccount()->getNumber()); + $this->assertEquals('Max Mustermann', $transactions[0]->getContraAccount()->getName()); + } +} diff --git a/tests/Jejik/Tests/MT940/Parser/SpecificGermanBankTest.php b/tests/Jejik/Tests/MT940/Parser/SpecificGermanBankTest.php new file mode 100644 index 0000000..216a8fd --- /dev/null +++ b/tests/Jejik/Tests/MT940/Parser/SpecificGermanBankTest.php @@ -0,0 +1,80 @@ + + * Licensed under the MIT license + * + * For the full copyright and license information, please see the LICENSE + * file that was distributed with this source code. + */ + +namespace Jejik\Tests\MT940\Parser; + +/** + * Class GeneralGermanBankTest A positive and negative test for SpecificGermanBankParser + * @package Jejik\Tests\MT940\Parser + */ +class SpecificGermanBankTest extends \PHPUnit\Framework\TestCase +{ + private $statements; + + /** + * Tries to parse an example MT940 file using the SpecificGermanBankParser + * + * @param string $expectedTransactionReferenceNumber The number to give to the parser + * @return array The resulting statements + * @throws \Exception If the parser failed to parse the example file + */ + private function parseExampleFile(string $expectedTransactionReferenceNumber): array + { + $reader = new \Jejik\MT940\Reader(); + $reader->addParser( + 'specific parser', + \Jejik\MT940\Parser\SpecificGermanBankParser::class, + null, + [$expectedTransactionReferenceNumber] + ); + return $reader->getStatements(<<parseExampleFile('MPLECO'); + $this->assertCount(1, $statements); + } + + /** + * Test the SpecificGermanBankParser with an incorrect transaction reference number. + * + * @throws \Exception + */ + public function testNonMatchingStatement(): void + { + // 'OTHER' is not contained in 'EXAMPLECODE', so this should be unsuccessful. + try { + $statements = $this->parseExampleFile('OTHER'); + $this->fail('expected an exception'); + } catch (\Jejik\MT940\Exception\NoParserFoundException $e) { + $this->assertEquals('No suitable parser found.', $e->getMessage()); + } + } +} diff --git a/tests/Jejik/Tests/MT940/Parser/TriodosTest.php b/tests/Jejik/Tests/MT940/Parser/TriodosTest.php index f55e306..aea400f 100644 --- a/tests/Jejik/Tests/MT940/Parser/TriodosTest.php +++ b/tests/Jejik/Tests/MT940/Parser/TriodosTest.php @@ -24,12 +24,15 @@ */ class TriodosTest extends TestCase { - public $statements = array(); + public $statements = []; + /** + * @throws \Jejik\MT940\Exception\NoParserFoundException + */ public function setUp(): void { $reader = new Reader(); - $reader->addParser('Triodos', 'Jejik\MT940\Parser\Triodos'); + $reader->addParser('Triodos', \Jejik\MT940\Parser\Triodos::class); $this->statements = $reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/triodos.txt')); } @@ -46,7 +49,7 @@ public function testStatement() public function testBalance() { $balance = $this->statements[0]->getOpeningBalance(); - $this->assertInstanceOf('Jejik\MT940\Balance', $balance); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $balance); $this->assertEquals('2011-01-01 00:00:00', $balance->getDate()->format('Y-m-d H:i:s')); $this->assertEquals('EUR', $balance->getCurrency()); $this->assertEquals(4975.09, $balance->getAmount()); diff --git a/tests/Jejik/Tests/MT940/ReaderTest.php b/tests/Jejik/Tests/MT940/ReaderTest.php index ec84d98..ccc7f15 100644 --- a/tests/Jejik/Tests/MT940/ReaderTest.php +++ b/tests/Jejik/Tests/MT940/ReaderTest.php @@ -33,11 +33,13 @@ public function testDefaultParsers() try { $reader->getStatements(''); - } catch (\RuntimeException $e) { + $this->fail('Expected an exception'); + } catch (\Exception $e) { // No parser can read an empty string + $this->assertTrue($e->getMessage() === 'No text is found for parsing.'); } - $this->assertCount(7, $reader->getParsers()); + $this->assertCount(15, $reader->getDefaultParsers()); } public function testAddParser() @@ -70,53 +72,70 @@ public function testAddParserBeforeFirst() $this->assertEquals('ABN-AMRO', $parsers[1]); } + /** + * @throws \Jejik\MT940\Exception\NoParserFoundException + */ public function testStringInjection() { $reader = new Reader(); - $reader->setParsers(array('Generic' => 'Jejik\Tests\MT940\Fixture\Parser')); + $reader->setParsers(['Generic' => \Jejik\Tests\MT940\Fixture\Parser::class]); - $reader->setStatementClass('Jejik\Tests\MT940\Fixture\Statement'); - $reader->setAccountClass('Jejik\Tests\MT940\Fixture\Account'); - $reader->setContraAccountClass('Jejik\Tests\MT940\Fixture\Account'); - $reader->setTransactionClass('Jejik\Tests\MT940\Fixture\Transaction'); - $reader->setOpeningBalanceClass('Jejik\Tests\MT940\Fixture\Balance'); - $reader->setClosingBalanceClass('Jejik\Tests\MT940\Fixture\Balance'); + $reader->setStatementClass(\Jejik\Tests\MT940\Fixture\Statement::class); + $reader->setAccountClass(\Jejik\Tests\MT940\Fixture\Account::class); + $reader->setContraAccountClass(\Jejik\Tests\MT940\Fixture\Account::class); + $reader->setTransactionClass(\Jejik\Tests\MT940\Fixture\Transaction::class); + $reader->setOpeningBalanceClass(\Jejik\Tests\MT940\Fixture\Balance::class); + $reader->setClosingBalanceClass(\Jejik\Tests\MT940\Fixture\Balance::class); $statements = $reader->getStatements(file_get_contents(__DIR__ . '/Fixture/document/generic.txt')); - $this->assertInstanceOf('Jejik\Tests\MT940\Fixture\Statement', $statements[0]); - $this->assertInstanceOf('Jejik\Tests\MT940\Fixture\Account', $statements[0]->getAccount()); - $this->assertInstanceOf('Jejik\Tests\MT940\Fixture\Balance', $statements[0]->getOpeningBalance()); - $this->assertInstanceOf('Jejik\Tests\MT940\Fixture\Balance', $statements[0]->getClosingBalance()); + $this->assertInstanceOf(\Jejik\Tests\MT940\Fixture\Statement::class, $statements[0]); + $this->assertInstanceOf(\Jejik\Tests\MT940\Fixture\Account::class, $statements[0]->getAccount()); + $this->assertInstanceOf(\Jejik\Tests\MT940\Fixture\Balance::class, $statements[0]->getOpeningBalance()); + $this->assertInstanceOf(\Jejik\Tests\MT940\Fixture\Balance::class, $statements[0]->getClosingBalance()); $transactions = $statements[0]->getTransactions(); - $this->assertInstanceOf('Jejik\Tests\MT940\Fixture\Transaction', $transactions[0]); + $this->assertInstanceOf(\Jejik\Tests\MT940\Fixture\Transaction::class, $transactions[0]); } + /** + * @throws \Jejik\MT940\Exception\NoParserFoundException + */ public function testCallableInjection() { $reader = new Reader(); - $reader->setParsers(array('Generic' => 'Jejik\Tests\MT940\Fixture\Parser')); + $reader->setParsers(array('Generic' => \Jejik\Tests\MT940\Fixture\Parser::class)); - $reader->setStatementClass(function () { return new Statement(); }); - $reader->setTransactionClass(function () { return new Transaction(); }); - $reader->setOpeningBalanceClass(function () { return new Balance(); }); - $reader->setClosingBalanceClass(function () { return new Balance(); }); + $reader->setStatementClass(function () { + return new Statement(); + }); + $reader->setTransactionClass(function () { + return new Transaction(); + }); + $reader->setOpeningBalanceClass(function () { + return new Balance(); + }); + $reader->setClosingBalanceClass(function () { + return new Balance(); + }); $statements = $reader->getStatements(file_get_contents(__DIR__ . '/Fixture/document/generic.txt')); - $this->assertInstanceOf('Jejik\Tests\MT940\Fixture\Statement', $statements[0]); - $this->assertInstanceOf('Jejik\Tests\MT940\Fixture\Balance', $statements[0]->getOpeningBalance()); - $this->assertInstanceOf('Jejik\Tests\MT940\Fixture\Balance', $statements[0]->getClosingBalance()); + $this->assertInstanceOf(\Jejik\Tests\MT940\Fixture\Statement::class, $statements[0]); + $this->assertInstanceOf(\Jejik\Tests\MT940\Fixture\Balance::class, $statements[0]->getOpeningBalance()); + $this->assertInstanceOf(\Jejik\Tests\MT940\Fixture\Balance::class, $statements[0]->getClosingBalance()); $transactions = $statements[0]->getTransactions(); - $this->assertInstanceOf('Jejik\Tests\MT940\Fixture\Transaction', $transactions[0]); + $this->assertInstanceOf(\Jejik\Tests\MT940\Fixture\Transaction::class, $transactions[0]); } + /** + * @throws \Jejik\MT940\Exception\NoParserFoundException + */ public function testSkipStatement() { $reader = new Reader(); - $reader->setParsers(array('Generic' => 'Jejik\Tests\MT940\Fixture\Parser')); + $reader->setParsers(['Generic' => \Jejik\Tests\MT940\Fixture\Parser::class]); $reader->setStatementClass(function ($account, $number) { if ($number == '2') { return new Statement(); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index af82719..5118159 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,5 +1,6 @@