diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index d55d706..7b67944 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: operating-system: ['ubuntu-22.04'] - php-versions: ['7.4', '8.0'] + php-versions: ['7.4', '8.0', '8.1'] steps: - uses: actions/checkout@v1 diff --git a/LICENCE.chargecloud.txt b/LICENCE.chargecloud.txt new file mode 100644 index 0000000..2ee8b7b --- /dev/null +++ b/LICENCE.chargecloud.txt @@ -0,0 +1,20 @@ +Copyright (c) 2023 Dominic Richter - chargecloud Gmbh (https://www.chargecloud.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/composer.json b/composer.json index 7828729..041afde 100644 --- a/composer.json +++ b/composer.json @@ -11,9 +11,8 @@ "homepage": "https://www.jejik.com" }, { - "name": "powercloud GmbH / Dominic Richter", - "email": "dominic.richter@power.cloud", - "homepage": "https://www.power.cloud" + "name": "Dominic Richter", + "homepage": "https://twitnic.de" } ], "require": { diff --git a/lib/Jejik/MT940/Parser/AbnAmro.php b/lib/Jejik/MT940/Parser/AbnAmro.php index b55d7d4..c310f6a 100644 --- a/lib/Jejik/MT940/Parser/AbnAmro.php +++ b/lib/Jejik/MT940/Parser/AbnAmro.php @@ -106,4 +106,73 @@ public function getAllowedBLZ(): array { return []; } + + /** + * For this bank, the gvc is in line :61: + * + * @param array $lines + * @return string|null + */ + protected function gvc(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(\d{3})([a-zA-Z0-9]+)#', $codeLine, $match); + + // assure match + if (!isset($match[5])) { + return null; + } + + // return + return substr($match[5], 0, 3); + } + + /** Get raw data of :86: + * + * @param array $lines + * @return string|string[]|null + */ + protected function rawSubfieldsData(array $lines) + { + $subflieldline = isset($lines[1]) ? $lines[1] : null; + $multiUseLine = $this->removeNewLinesFromLine($subflieldline); + + return $multiUseLine; + } + + /** + * @param array $lines + * @return string|null + */ + protected function kref(array $lines): ?string + { + // get :86: line -- it is second in provided array [:61:,:86:,....] + $krefLine = isset($lines[1]) ? $lines[1] : null; + + /** @var string $krefLine */ + preg_match("#(\/PREF\/)+([a-zA-ZöäüÖÄÜß0-9\-\+\.\_\s]+)?(\/NRTX\/)?(:62)?#", $this->removeNewLinesFromLine($krefLine), $match); + + if (!isset($match[2])) { + return null; + } + + return $match[2]; + } + + /** + * @param string $stringLine + * @return string + */ + private function removeNewLinesFromLine(string $stringLine): string + { + return str_replace(["\n", "\r", "\r\n"], '', $stringLine); + } } diff --git a/lib/Jejik/MT940/Parser/AbstractParser.php b/lib/Jejik/MT940/Parser/AbstractParser.php index dcdb20d..d8e12e5 100644 --- a/lib/Jejik/MT940/Parser/AbstractParser.php +++ b/lib/Jejik/MT940/Parser/AbstractParser.php @@ -422,7 +422,7 @@ protected function transaction(array $lines): TransactionInterface // Parse the amount $amount = (float)str_replace(',', '.', $match[4]); - if (in_array($match[3], array('D', 'DR','RC','RCR'))) { + if (in_array($match[3], array('D', 'DR','RC','RCR','RDR'))) { $amount *= -1; } @@ -494,7 +494,10 @@ protected function transaction(array $lines): TransactionInterface ->setOamt($this->oamt($lines)) ->setAbwa($this->abwa($lines)) ->setAbwe($this->abwe($lines)) - ->setDescription($this->description($description)); + ->setDescription($this->description($description)) + ->setRawSubfieldsData($this->rawSubfieldsData($lines)) + ->setCodeWords($this->codeWords($lines)) + ->setTransactionCode($this->transactionCode($lines)); return $transaction; } @@ -736,4 +739,31 @@ protected function abwe(array $lines): ?string { return null; } + + /** + * @param array $lines + * @return null + */ + protected function rawSubfieldsData(array $lines) + { + return null; + } + + /** + * @param array $lines + * @return null + */ + protected function codeWords(array $lines) + { + return null; + } + + /** + * @param array $lines + * @return null + */ + protected function transactionCode(array $lines) + { + return null; + } } diff --git a/lib/Jejik/MT940/Parser/BayerischeLandesbank.php b/lib/Jejik/MT940/Parser/BayerischeLandesbank.php new file mode 100644 index 0000000..f80e242 --- /dev/null +++ b/lib/Jejik/MT940/Parser/BayerischeLandesbank.php @@ -0,0 +1,48 @@ +isBLZAllowed($text); + } +} diff --git a/lib/Jejik/MT940/Parser/Bil.php b/lib/Jejik/MT940/Parser/Bil.php new file mode 100644 index 0000000..83111c5 --- /dev/null +++ b/lib/Jejik/MT940/Parser/Bil.php @@ -0,0 +1,157 @@ +isBLZAllowed($text); + } + } + + /** + * Get an array of allowed BLZ for this bank + */ + public function getAllowedBLZ(): array + { + return []; + } + + /** + * @param array $lines + * @return string|null + */ + protected function gvc(array $lines): ?string + { + $gvcLine = $lines[1] ?? null; + + if ($gvcLine == null) { + return null; + } + + return substr($gvcLine, 0, 3); + } + + /** + * Parse txText for provided transaction lines + */ + protected function txText(array $lines): ?string + { + $txTextLine = isset($lines[1]) ? $lines[1] : null; + + if ($txTextLine === null) { + return null; + } + + /** @var string $txTextLine */ + preg_match('#\?00([a-zA-Z0-9\-\s\.]+)#', $this->removeNewLinesFromLine($txTextLine), $match); + + if (!isset($match[1])) { + return null; + } + + return $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); + } + + /** Get raw data of subfields ?20 - ?29 + * + * @param array $lines + * @return string|string[]|null + */ + protected function rawSubfieldsData(array $lines) + { + $subflieldline = isset($lines[1]) ? $lines[1] : null; + + $multiUseLine = $this->removeNewLinesFromLine($subflieldline); + preg_match('#(\?2[0-9][^?]+)+#', $multiUseLine, $match); + + if (!isset($match[0])) { + return null; + } + + return preg_replace('#(\?2[0-9])#', '', $match[0]); + } + + /** + * Parse code for provided transaction lines + */ + protected function code(array $lines): ?string + { + $codeLine = isset($lines[0]) ? $lines[0] : null; + + if ($codeLine == null) { + return null; + } + preg_match('#(\d{6})(\d{4})?(R?(?:C|D)R?)([0-9,]{1,15})N([a-zA-Z0-9]+)#', $codeLine, $match); + + if (!isset($match[5])) { + return null; + } + return substr($match[5], 0, 3); + } + + /** + * Parse ref for provided transaction lines + */ + protected function ref(array $lines): ?string + { + + $refLine = isset($lines[0]) ? $lines[0] : null; + + if ($refLine == null) { + return null; + } + preg_match('#(?:\d{10})?(R?(?:C|D)R?)(?:[\d,]{1,15})N(.){3}([A-Za-z0-9\.]+)#', $refLine, $match); + if (!isset($match[3])) { + return null; + } + + return $match[3]; + } +} diff --git a/lib/Jejik/MT940/Parser/Commerzbank.php b/lib/Jejik/MT940/Parser/Commerzbank.php index ad178de..e11ecda 100755 --- a/lib/Jejik/MT940/Parser/Commerzbank.php +++ b/lib/Jejik/MT940/Parser/Commerzbank.php @@ -28,6 +28,8 @@ public function accept(string $text): bool $allowedUniqueIdentifiers = [ ':20:012CIXCIA7V1OGWA', ':20:0157VSNLKBG9WGWA', + ':20:B2NG0OPCF3PTM87C', + ':20:B2NG0MGUR8GUXUW8', ':20:01LGX08DLMWH5GWA', ]; @@ -52,7 +54,9 @@ public function getAllowedBLZ(): array '70040041', '66280053', '28540034', - '25040066', + '50040000', + '16040000', + '25040066' ]; } } diff --git a/lib/Jejik/MT940/Parser/GermanBank.php b/lib/Jejik/MT940/Parser/GermanBank.php index d8f7d28..93b5e6d 100755 --- a/lib/Jejik/MT940/Parser/GermanBank.php +++ b/lib/Jejik/MT940/Parser/GermanBank.php @@ -184,6 +184,26 @@ protected function extCode(array $lines): ?string return $match[1] ?? null; } + /** Get raw data of subfields ?20 - ?29 + * + * @param array $lines + * @return string|string[]|null + */ + protected function rawSubfieldsData(array $lines) + { + $subflieldline = $lines[1] ?? null; + + $multiUseLine = $this->removeNewLinesFromLine($subflieldline); + preg_match('#(\?2[0-9][^?]+)+#', $multiUseLine, $match); + + if (!isset($match[0])) { + return null; + } + + return preg_replace('#(\?2[0-9])#', '', $match[0]); + } + + /** */ protected function getSubfield(string $multiUseLine, string $identifier): ?string @@ -421,7 +441,7 @@ protected function svwz(array $lines): ?string // get :86: line -- it is second in provided array [:61:,:86:,....] $svwzLine = $lines[1] ?? null; - $pattern = "/(S(?:\?2[1-9])?V(?:\?2[1-9])?W(?:\?2[1-9])?Z(?:\?2[1-9])?\+)(?:\?(?:2[1-9]))?(?'SVWZ'.*)(?:\?30)/"; + $pattern = "/(S(?:\?2[1-9])?V(?:\?2[1-9])?W(?:\?2[1-9])?Z(?:\?2[1-9])?\+)(?:\?(?:2[1-9]))?(?'SVWZ'.*)(?:\?3[0-4])/"; /** @var string $svwzLine */ preg_match($pattern, $this->removeNewLinesFromLine($svwzLine), $match); @@ -431,7 +451,7 @@ protected function svwz(array $lines): ?string return null; } - return preg_replace('/(\?2[1-9])/', '', $match['SVWZ']); + return preg_replace('/(\?2[1-9])|(\?3[0-4].*)/', '', $match['SVWZ']); } /** diff --git a/lib/Jejik/MT940/Parser/Ing.php b/lib/Jejik/MT940/Parser/Ing.php index 2da3b50..fbebed8 100644 --- a/lib/Jejik/MT940/Parser/Ing.php +++ b/lib/Jejik/MT940/Parser/Ing.php @@ -23,6 +23,24 @@ */ class Ing extends AbstractParser { + /** + * Codewords from ING Format Description + */ + public const CODEWORD_PREF = '/PREF/'; + public const CODEWORD_RTRN = '/RTRN/'; + public const CODEWORD_CREF = '/CREF/'; + public const CODEWORD_EREF = '/EREF/'; + public const CODEWORD_IREF = '/IREF/'; + public const CODEWORD_MARF = '/MARF/'; + public const CODEWORD_CSID = '/CSID/'; + public const CODEWORD_CNTP = '/CNTP/'; + public const CODEWORD_PURP = '/PURP/'; + public const CODEWORD_ULTC = '/ULTC/'; + public const CODEWORD_ULTD = '/ULTD/'; + public const CODEWORD_EXCH = '/EXCH/'; + public const CODEWORD_CHGS = '/CHGS/'; + public const CODEWORD_REMI_USTD = '/REMI/USTD//'; + /** * Test if the document is an ING document */ @@ -31,7 +49,7 @@ public function accept(string $text): bool if (empty($text)) { return false; } - return substr($text, 6, 6) === 'INGBNL'; + return substr(preg_replace('/\s/','',$text), 6, 6) === 'INGBNL'; } /** @@ -75,6 +93,13 @@ protected function transaction(array $lines): TransactionInterface $transaction->setValueDate($valueDate); } + if (preg_match('/(\d{2}\/\d{2}\/\d{4})/', $lines[1], $match)) { + $valueDate = \DateTime::createFromFormat('d/m/Y', $match[1]); + $valueDate->setTime(0, 0, 0); + + $transaction->setValueDate($valueDate); + } + return $transaction; } @@ -99,4 +124,191 @@ public function getAllowedBLZ(): array { return []; } + + /** + * @param array $lines + * @return array|null + */ + protected function codeWords(array $lines): ?array + { + $descriptionLine = $lines[1] ?? null; + $multiUseLine = $this->removeNewLinesFromLine($descriptionLine); + + $identifiers = [ + static::CODEWORD_PREF, + static::CODEWORD_RTRN, + static::CODEWORD_CREF, + static::CODEWORD_EREF, + static::CODEWORD_IREF, + static::CODEWORD_MARF, + static::CODEWORD_CSID, + static::CODEWORD_CNTP, + static::CODEWORD_REMI_USTD, + static::CODEWORD_PURP, + static::CODEWORD_ULTC, + static::CODEWORD_ULTD, + static::CODEWORD_EXCH, + static::CODEWORD_CHGS + ]; + + $regex = sprintf( + '#(%s)#', + implode('|', $identifiers) + ); + + $splitReferenceLine = preg_split( + $regex, + $multiUseLine, + -1, + PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE + ); + $codeWords = []; + + if (current($splitReferenceLine) === ':86:') { + next($splitReferenceLine); + } + + do { + $fieldIdentifier = current($splitReferenceLine) ?: 'unknown'; + $fieldContent = next($splitReferenceLine) ?: null; + $codeWords[$fieldIdentifier] = $fieldContent; + } while (next($splitReferenceLine) !== false); + + return $codeWords; + } + + /** + * @param string $stringLine + * @return string + */ + private function removeNewLinesFromLine(string $stringLine): string + { + return str_replace(["\n", "\r", "\r\n"], '', $stringLine); + } + + /** + * @param array $lines + * @return void|null + */ + protected function transactionCode(array $lines) + { + $statementLine = $lines[0] ?? null; + $multiUseLine = $this->removeNewLinesFromLine($statementLine); + + preg_match('#(\/TRCD\/)(\d{5})#', $multiUseLine, $match); + + return $match[2] ?? null; + } + + protected function code(array $lines): ?string + { + // get :61: line -- it is first in provided array [:61:,:86:,....] + $codeLine = $lines[0] ?? null; + + if ($codeLine == null) { + return null; + } + + preg_match('#(\d{6})(\d{4})?(R?(?:C|D))([0-9,]{1,15})N([a-zA-Z0-9]+)#', $codeLine, $match); + + if (!isset($match[5])) { + return null; + } + + return substr($match[5], 0, 3); + } + + /** + * @param array $lines + * @return string|null + */ + protected function eref(array $lines): ?string + { + if (isset($this->codeWords($lines)[self::CODEWORD_EREF])) { + return $this->codeWords($lines)[self::CODEWORD_EREF]; + } + + return null; + } + + /** + * @param array $lines + * @return string|null + */ + protected function rawSubfieldsData(array $lines): ?string + { + $descriptionLine = $lines[1] ?? null; + return $this->removeNewLinesFromLine($descriptionLine); + } + + /** + * @param array $lines + * @return string|null + */ + protected function bic(array $lines): ?string + { + return $this->getCounterPartyId($lines)['bic'] ?? null; + } + + /** + * @param array $lines + * @return string|null + */ + protected function iban(array $lines): ?string + { + return isset($this->getCounterPartyId($lines)['accountNumber']) + ? ($this->getCounterPartyId($lines)['accountNumber']) + : null; + } + + /** + * @param array $lines + * @return string|null + */ + protected function accountHolder(array $lines): ?string + { + return $this->getCounterPartyId($lines)['name'] ?? null; + } + + /** + * @param array $lines + * @return string|null + */ + protected function txText(array $lines): ?string + { + return $this->codeWords($lines)[self::CODEWORD_REMI_USTD] ?? null; + } + + /** + * @param array $lines + * @return array|null + */ + protected function getCounterPartyId(array $lines): ?array + { + $cntp = $this->codeWords($lines)[self::CODEWORD_CNTP] ?? null; + + if (!$cntp) { + return null; + } + + $splitCodeWords = preg_split('#\/#', $cntp); + + return [ + 'accountNumber' => $splitCodeWords[0], + 'bic' => $splitCodeWords[1], + 'name' => $splitCodeWords[2], + 'city' => $splitCodeWords[3] + ]; + } + + /** + * @param array $lines + * @return false|string|null + */ + protected function getCreditorId(array $lines) + { + return isset($this->codeWords($lines)[self::CODEWORD_CSID]) + ? substr($this->codeWords($lines)[self::CODEWORD_CSID], 0, strlen($this->codeWords($lines)[self::CODEWORD_CSID]) - 1) + : null; + } } diff --git a/lib/Jejik/MT940/Parser/LandesBankHessen.php b/lib/Jejik/MT940/Parser/LandesBankHessen.php new file mode 100644 index 0000000..4304c6e --- /dev/null +++ b/lib/Jejik/MT940/Parser/LandesBankHessen.php @@ -0,0 +1,42 @@ +isBLZAllowed($text); + } +} diff --git a/lib/Jejik/MT940/Parser/Lbbw.php b/lib/Jejik/MT940/Parser/Lbbw.php index c857de5..58eb5a9 100755 --- a/lib/Jejik/MT940/Parser/Lbbw.php +++ b/lib/Jejik/MT940/Parser/Lbbw.php @@ -14,6 +14,9 @@ namespace Jejik\MT940\Parser; +use Jejik\MT940\Balance; +use Jejik\MT940\BalanceInterface; + /** * Lbbw provides a parser for Lbbw Bank * @package Jejik\MT940\Parser @@ -45,6 +48,7 @@ public function accept(string $text): bool public function getAllowedBLZ(): array { return [ + '60050101' ]; } @@ -76,4 +80,84 @@ protected function description(?string $description): ?string { return parent::description($description); // TODO: Change the autogenerated stub } + /** + * This bank also has 4 characters for the currency in the balance line which must be read out. + * + * @param \Jejik\MT940\BalanceInterface $balance + * @param string $text + * @return \Jejik\MT940\BalanceInterface + */ + protected function balance(\Jejik\MT940\BalanceInterface $balance, string $text): \Jejik\MT940\BalanceInterface + { + if (!preg_match('/(C|D)(\d{6})([A-Z]{3,4})([0-9,]{1,15})/', $text, $match)) { + throw new \RuntimeException(sprintf('Cannot parse balance: "%s"', $text)); + } + + $amount = (float)str_replace(',', '.', $match[4]); + if ($match[1] === 'D') { + $amount *= -1; + } + + $date = \DateTime::createFromFormat('ymd', $match[2]); + $date->setTime(0, 0, 0); + + $balance + ->setCurrency($match[3]) + ->setAmount($amount) + ->setDate($date); + + return $balance; + } + + /** + * Get the closing balance + */ + protected function closingBalance(string $text): ?Balance + { + if ($line = $this->getLine('62F|62M', $text)) { + return $this->balance($this->reader->createClosingBalance(), $line); + } + + if ($line = $this->getClosingLineWithoutColin('62F|62M', $text)) { + return $this->balance($this->reader->createClosingBalance(), $line); + } + + return null; + } + + /** + * This method determines the closing balance when there is no colon at the beginning of the closing balance line to + * identify and separate (usually it is :: but this bank can have :xxx) + * + * @param string $id + * @param string $text + * @param int $offset + * @param int|null $position + * @param int|null $length + * @return string|null + */ + private function getClosingLineWithoutColin( + string $id, + string $text, + int $offset = 0, + int &$position = null, + int &$length = null + ): ?string { + $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 "::" + . '/Us'; // Ungreedy matching + + $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 null; + } } diff --git a/lib/Jejik/MT940/Parser/Raiffeisen.php b/lib/Jejik/MT940/Parser/Raiffeisen.php new file mode 100644 index 0000000..6f1ccff --- /dev/null +++ b/lib/Jejik/MT940/Parser/Raiffeisen.php @@ -0,0 +1,47 @@ +isBLZAllowed($text); + } +} diff --git a/lib/Jejik/MT940/Reader.php b/lib/Jejik/MT940/Reader.php index b6faf1d..bf601f7 100644 --- a/lib/Jejik/MT940/Reader.php +++ b/lib/Jejik/MT940/Reader.php @@ -39,22 +39,26 @@ class Reader */ private $defaultParsers = array( 'ABN-AMRO' => Parser\AbnAmro::class, + 'BayerischeLandesbank' => Parser\BayerischeLandesbank::class, 'Commerzbank' => Parser\Commerzbank::class, 'DeutscheBank' => Parser\DeutscheBank::class, 'ING' => Parser\Ing::class, 'Knab' => Parser\Knab::class, 'LandesBankBerlin' => Parser\LandesBankBerlin::class, + 'LandesBankHessen' => Parser\LandesBankHessen::class, 'Lbbw' => Parser\Lbbw::class, 'NuaPayBank' => Parser\NuaPayBank::class, 'OldenburgischeLandesbank' => Parser\OldenburgischeLandesbank::class, 'PostFinance' => Parser\PostFinance::class, 'Rabobank' => Parser\Rabobank::class, + 'Raiffeisen' => Parser\Raiffeisen::class, 'Sns' => Parser\Sns::class, 'Sparkasse' => Parser\Sparkasse::class, // 'SpecificGermanBank' => Parser\SpecificGermanBankParser::class, TODO 'StarMoney' => Parser\StarMoney::class, 'Triodos' => Parser\Triodos::class, 'UniCreditBank' => Parser\UniCreditBank::class, + 'Bil' => Parser\Bil::class, ); /** @@ -522,7 +526,7 @@ protected function createObject($className, $interface, $params = []) public function getStatements(string $text = null): array { if ($text === null) { - $text = file_get_contents($this->getFileName()); + $text = $this->removeBom(file_get_contents($this->getFileName())); } if ($text === null || strlen(trim($text)) === 0) { throw new \Exception("No text is found for parsing."); @@ -530,6 +534,9 @@ public function getStatements(string $text = null): array if (($pos = strpos($text, ':20:')) === false) { throw new \RuntimeException('Not an MT940 statement'); } + if (preg_match_all('/^[\n\r\s]+/', $text, $output_array) > 0) { + throw new \Exception('The first line cannot be a blank line.'); + } if (!$this->parsers) { $this->addParsers($this->getDefaultParsers()); } @@ -543,4 +550,15 @@ public function getStatements(string $text = null): array throw new Exception\NoParserFoundException(); } + + /** + * @param $text + * @return string|string[]|null + */ + private function removeBom($text) + { + $bom = pack('H*','EFBBBF'); + $text = preg_replace("/^$bom/", '', $text); + return $text; + } } diff --git a/lib/Jejik/MT940/Transaction.php b/lib/Jejik/MT940/Transaction.php index e90bd1c..2753cf7 100644 --- a/lib/Jejik/MT940/Transaction.php +++ b/lib/Jejik/MT940/Transaction.php @@ -128,6 +128,21 @@ class Transaction implements TransactionInterface */ private $svwz; + /** + * @var string + */ + private $rawSubfieldsData; + + /** + * @var array|null + */ + private $codeWords; + + /** + * @var string|null + */ + private $transactionCode; + /** * @var string */ @@ -626,5 +641,54 @@ public function setAbwe(string $abwe = null): TransactionInterface return $this; } - // }}} + /** + * @param string|null $rawSubfieldsData + * @return TransactionInterface + */ + public function setRawSubfieldsData(string $rawSubfieldsData = null): TransactionInterface + { + $this->rawSubfieldsData = $rawSubfieldsData; + return $this; + } + + /** + * @return string|null + */ + public function getRawSubfieldsData(): ?string + { + return ($this->rawSubfieldsData !== null) ? trim($this->rawSubfieldsData) : null; + } + + /** + * @param array|null $codeWords + * @return TransactionInterface + */ + public function setCodeWords(array $codeWords = null): TransactionInterface + { + $this->codeWords = $codeWords; + return $this; + } + + /** + * @return array|null + */ + public function getCodeWords(): ?array + { + return $this->codeWords !== null ? $this->codeWords : null; + } + + /** + * @param string|null $transactionCode + * @return TransactionInterface + */ + public function setTransactionCode(string $transactionCode = null): TransactionInterface + { + $this->transactionCode = $transactionCode; + return $this; + } + + public function getTransactionCode(): ?string + { + return $this->transactionCode !== null ? $this->transactionCode : null; + } } diff --git a/lib/Jejik/MT940/TransactionInterface.php b/lib/Jejik/MT940/TransactionInterface.php index b7b7389..39d488b 100644 --- a/lib/Jejik/MT940/TransactionInterface.php +++ b/lib/Jejik/MT940/TransactionInterface.php @@ -234,7 +234,42 @@ public function getSvwz(): ?string; * Set Svwz for this transaction */ public function setSvwz(string $svwz = null): TransactionInterface; - + + /** + * @param string|null $rawSubfieldData + * @return TransactionInterface + */ + public function setRawSubfieldsData(string $rawSubfieldsData = null) : TransactionInterface; + + /** + * @return string|null + */ + public function getRawSubfieldsData(): ?string; + + /** + * @param array|null $codeWords + * @return TransactionInterface + */ + public function setCodeWords(array $codeWords = null): TransactionInterface; + + /** + * @return array|null + */ + public function getCodeWords(): ?array; + + /** + * If there's no GVC, try to set/get the transaction-code + * + * @param string|null $transactionCode + * @return TransactionInterface + */ + public function setTransactionCode(string $transactionCode = null): TransactionInterface; + + /** + * @return string|null + */ + public function getTransactionCode(): ?string; + /** * Get Purp for this transaction */ diff --git a/tests/Jejik/Tests/MT940/Fixture/document/bayerischelandesbank.txt b/tests/Jejik/Tests/MT940/Fixture/document/bayerischelandesbank.txt new file mode 100644 index 0000000..6172730 --- /dev/null +++ b/tests/Jejik/Tests/MT940/Fixture/document/bayerischelandesbank.txt @@ -0,0 +1,11 @@ +:20:21766916 +:25:70050000/4213299 +:28C:39/1 +:60F:C210224EUR11657017,94 +:61:2102250225CR0,71NTRFSEPA-20210217210//0000000000000001 +:86:192?00SEPA-LASTSCHRIFT-CORE AUSG?100000001706?20ANZ. SEPA COR 000 +0001?21REF. SEPA-20210217210008-40?22133200-P1 EINR.ART. DDC? +23VORMERKREF. 4340-02-23-13.4?247.01.140931?25EREF+A17022021.3924 +92.37655?262.391933 +:62F:C210225EUR11657183,83 +- diff --git a/tests/Jejik/Tests/MT940/Fixture/document/bil.txt b/tests/Jejik/Tests/MT940/Fixture/document/bil.txt new file mode 100644 index 0000000..3a39705 --- /dev/null +++ b/tests/Jejik/Tests/MT940/Fixture/document/bil.txt @@ -0,0 +1,7 @@ +:20:BILMT940 +:25:BILLLULLXXX/LU540026121160200600 +:28C:00001/001 +:60F:C211206EUR0, +:61:2201170117DR4,NCOMNONREF //CIOB220117990193/IACC/D3/ +:86:808?00FORFAIT MENSUEL ENVOI DE COURRIER?20COMPTE . IBAN LU54 0026 1211 6020 0?21600 +:62F:D220118EUR4, diff --git a/tests/Jejik/Tests/MT940/Fixture/document/ing-unix-2.txt b/tests/Jejik/Tests/MT940/Fixture/document/ing-unix-2.txt new file mode 100644 index 0000000..11783f8 --- /dev/null +++ b/tests/Jejik/Tests/MT940/Fixture/document/ing-unix-2.txt @@ -0,0 +1,38 @@ +0000 01INGBNL2AXXXX00001 +0000 01INGBNL2AXXXX00001 +940 00 +:20:ING +:25:1234567 +:28C:000 +:60F:C100722EUR0,00 +:61:100722D25,03NTRFPREF//12451300037112 +/TRCD/00200/ +:86: RC AFREKENING BETALINGSVERKEER +BETREFT REKENING 4715589 PERIODE: 01-10-2010 / 31-12-2010 +ING Bank N.V. tarifering ING +:61:100723D10,00NTRFPREF//12451300037112 +/TRCD/00200/ +:86:/PREF/SEPA-20210824200507-86139300-P1//REMI/USTD//TOTAAL 1 VZ/ +:61:100723D10,00NTRFPREF//12451300037112 +/TRCD/00200/ +:86:/PREF/SEPA-20210824200507-86139300-P1//REMI/USTD//TOTAAL 1 VZ/ +:61:100723D10,00NTRFPREF//12451300037112 +/TRCD/00200/ +:86:/PREF/SEPA-20210824200507-86139300-P1//REMI/USTD//TOTAAL 1 VZ/ +:61:100723D10,00NTRFPREF//12451300037112 +/TRCD/00200/ +:86:/PREF/SEPA-20210824200507-86139300-P1//REMI/USTD//TOTAAL 1 VZ/ +:61:100723D10,00NTRFPREF//12451300037112 +/TRCD/00200/ +:86:/PREF/SEPA-20210824200507-86139300-P1//REMI/USTD//TOTAAL 1 VZ/ +:61:100723C10,00NCMIPPM6339365//12453100006764 +/TRCD/05001/ +:86:/CNTP/NL21INGB0650141172//Rexel Holding Netherlands B.V.///REMI/U +STD//POOL-M NL21INGB0650141172 POOL-S NL30INGB0008693687 PPM63393 +65 22/07/2010/ +:62F:C100722EUR0,00 +:64:C100722EUR0,00 +:65:C210903EUR0,00 +:65:C210904EUR0,00 +:86:D000001C000001D10,00C10,00 +-XXX diff --git a/tests/Jejik/Tests/MT940/Fixture/document/ing-unix-3.txt b/tests/Jejik/Tests/MT940/Fixture/document/ing-unix-3.txt new file mode 100644 index 0000000..417b482 --- /dev/null +++ b/tests/Jejik/Tests/MT940/Fixture/document/ing-unix-3.txt @@ -0,0 +1,43 @@ +0000 01INGBNL2AXXXX00001 +0000 01INGBNL2AXXXX00001 +940 00 +:20:ING +:25:0001234567 +:28C:000 +:60F:C100722EUR0,00 +:61:100722D25,03NDDTPREF//12490100094319 +/TRCD/01010/ +:86: RC AFREKENING BETALINGSVERKEER +BETREFT REKENING 4715589 PERIODE: 01-10-2010 / 31-12-2010 +ING Bank N.V. tarifering ING +:61:100723C2,00NDDTPREF//12490100094319 +/TRCD/01010/ +:86:/PREF/SEPA-20210823090009-45153900-P1//CSID/NL64ZZZ242678500002/ +REMI/USTD//TOTAAL 1 POSTEN/ +:61:100723C2,00NDDTPREF//12490100094319 +/TRCD/01010/ +:86:/PREF/SEPA-20210823090009-45153900-P1//CSID/NL64ZZZ242678500002/ +REMI/USTD//TOTAAL 1 POSTEN/ +:61:100723C2,00NDDTPREF//12490100094319 +/TRCD/01010/ +:86:/PREF/SEPA-20210823090009-45153900-P1//CSID/NL64ZZZ242678500002/ +REMI/USTD//TOTAAL 1 POSTEN/ +:61:100723C2,00NDDTPREF//12490100094319 +/TRCD/01010/ +:86:/PREF/SEPA-20210823090009-45153900-P1//CSID/NL64ZZZ242678500002/ +REMI/USTD//TOTAAL 1 POSTEN/ +:61:100723C2,00NDDTPREF//12490100094319 +/TRCD/01010/ +:86:/PREF/SEPA-20210823090009-45153900-P1//CSID/NL64ZZZ242678500002/ +REMI/USTD//TOTAAL 1 POSTEN/ +:61:100723D2,00NCMIPPS6355272//12493100006313 +/TRCD/05001/ +:86:/CNTP/NL21INGB0650141172//Rexel Holding Netherlands B.V.///REMI/U +STD//POOL-M NL21INGB0650141172 POOL-S NL30INGB0008693687 PPM63393 +72 22/07/2010/ +:62F:C100722EUR0,00 +:64:C100722EUR0,00 +:65:C100722EUR0,00 +:65:C100722EUR0,00 +:86:D000001C000001D2,00C2,00 +-XXX diff --git a/tests/Jejik/Tests/MT940/Fixture/document/landesbankhessen.txt b/tests/Jejik/Tests/MT940/Fixture/document/landesbankhessen.txt new file mode 100644 index 0000000..109ab72 --- /dev/null +++ b/tests/Jejik/Tests/MT940/Fixture/document/landesbankhessen.txt @@ -0,0 +1,12 @@ +:20:940311220001001 +:21:0000000000000000 +:25:50050000/0090085309 +:28C:1 +:60F:D201231EUR0,00 +:61:2012311231D0,00NMSCNONREF +:86:835?00SONSTIGE NICHT DEF.GV-ARTEN?1059777?20 RECHNUNGSABSCHLUSS P +ER?2131.12.2020 GEM. 355 HGB?22 ABSCHL.SALDO PER: 31.12.20?23EUR +0,00?24 DIESER KONTOAUSZUG GILT IM?25ZUSAMMENHANG MIT DEN?26ZUGRU +NDELIEGENDEN?27VERTRAEGEN ALS RECHNUNG?28 IM SINNE USTG. +:62F:D201231EUR0,00 +- diff --git a/tests/Jejik/Tests/MT940/Fixture/document/lbbw2.txt b/tests/Jejik/Tests/MT940/Fixture/document/lbbw2.txt new file mode 100644 index 0000000..df9b3ca --- /dev/null +++ b/tests/Jejik/Tests/MT940/Fixture/document/lbbw2.txt @@ -0,0 +1,9 @@ +:20:LBBW +:25:12345678/123456789 +:28C:6/1 +:60F:C221004EURO0,00 +:61:2210181018CR1,00NTRFNONREF +:86:166?00GUTSCHR. UEBERWEISUNG?109301?20SVWZ+UEBERTRAG?21ABWA+J. +W.ZANDER GMBH CO. KG F?33REIBURG I.BR. +:62FC221018EUR1,00 +- diff --git a/tests/Jejik/Tests/MT940/Fixture/document/raiffeisen.txt b/tests/Jejik/Tests/MT940/Fixture/document/raiffeisen.txt new file mode 100644 index 0000000..8d0123f --- /dev/null +++ b/tests/Jejik/Tests/MT940/Fixture/document/raiffeisen.txt @@ -0,0 +1,16 @@ +:20:00001150-0001 +:25:CCRALULL/LU1234567890123456789 +:28C:001/0001 +:60F:C220228EUR000000000000,00 +:61:2202280228CR000000000001,00N229NONREF//FT22059PGV08 +:86:229 +?00BONIFICATION +?20BONIFICATION +?21test trt +?22FT22059PGV08 +?30CCRALULLXXX +?32ABC +?60ABC +?612 Max Mustermann, +?62L-3372 LEUDELANGE +:62F:C220228EUR000000000001,00 diff --git a/tests/Jejik/Tests/MT940/Parser/BayerischeLandesbankTest.php b/tests/Jejik/Tests/MT940/Parser/BayerischeLandesbankTest.php new file mode 100644 index 0000000..4e3c813 --- /dev/null +++ b/tests/Jejik/Tests/MT940/Parser/BayerischeLandesbankTest.php @@ -0,0 +1,87 @@ +addParser('BayerischeLandesbank', \Jejik\MT940\Parser\BayerischeLandesbank::class); + $this->statements = $reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/bayerischelandesbank.txt')); + } + + /** + * Test the statement + */ + public function testStatement(): void + { + $this->assertCount(1, $this->statements, 'Assert counting statements.'); + $statement = $this->statements[0]; + + $this->assertEquals('39/1', $statement->getNumber()); + $this->assertEquals('70050000/4213299', $statement->getAccount()->getNumber()); + } + + /** + * Test balance + */ + public function testBalance(): void + { + $balance = $this->statements[0]->getOpeningBalance(); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $balance); + $this->assertEquals('2021-02-24 00:00:00', $balance->getDate()->format('Y-m-d H:i:s')); + $this->assertEquals('EUR', $balance->getCurrency()); + $this->assertEquals(11657017.94, $balance->getAmount()); + } + + /** + * Test transaction with its fields + */ + public function testTransaction(): void + { + $transactions = $this->statements[0]->getTransactions(); + + $this->assertCount(1, $transactions); + + $this->assertNull($transactions[0]->getContraAccount()); + + $this->assertEquals(0.71, $transactions[0]->getAmount()); + $expectedDescription = "192?00SEPA-LASTSCHRIFT-CORE AUSG?100000001706?20ANZ. SEPA COR 000\r\n0001?21REF. SEPA-20210217210008-40?22133200-P1 EINR.ART. DDC?\r\n23VORMERKREF. 4340-02-23-13.4?247.01.140931?25EREF+A17022021.3924\r\n92.37655?262.391933"; + $this->assertEquals($expectedDescription, $transactions[0]->getDescription()); + $this->assertEquals('2021-02-25 00:00:00', $transactions[0]->getValueDate()->format('Y-m-d H:i:s'), 'Assert Value Date'); + $this->assertEquals('2021-02-25 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('192', $transactions[0]->getGVC()); + $this->assertEquals('SEPA-LASTSCHRIFT-CORE AUSG', $transactions[0]->getTxText()); + $this->assertEquals('0000001706', $transactions[0]->getPrimanota()); + $this->assertNull($transactions[0]->getExtCode()); + $this->assertEquals('A17022021.392492.376552.391933', $transactions[0]->getEref()); + $this->assertNull($transactions[0]->getBIC()); + $this->assertNull($transactions[0]->getIBAN()); + $this->assertNull($transactions[0]->getAccountHolder()); + $this->assertNull($transactions[0]->getKref()); + $this->assertNull($transactions[0]->getMref()); + $this->assertNull($transactions[0]->getCred()); + $this->assertNull($transactions[0]->getSvwz()); + $this->assertEquals('ANZ. SEPA COR 0000001REF. SEPA-20210217210008-40133200-P1 EINR.ART. DDCVORMERKREF. 4340-02-23-13.47.01.140931EREF+A17022021.392492.376552.391933', $transactions[0]->getRawSubfieldsData()); + } + +} diff --git a/tests/Jejik/Tests/MT940/Parser/BilTest.php b/tests/Jejik/Tests/MT940/Parser/BilTest.php new file mode 100644 index 0000000..fef81d2 --- /dev/null +++ b/tests/Jejik/Tests/MT940/Parser/BilTest.php @@ -0,0 +1,76 @@ +addParser('Bil', \Jejik\MT940\Parser\Bil::class); + $this->statements = $reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/bil.txt')); + } + + public function testStatement() + { + $this->assertCount(1, $this->statements); + $statement = $this->statements[0]; + + $this->assertEquals('00001/001', $statement->getNumber()); + $this->assertNotNull($statement->getAccount()); + $this->assertEquals('BILLLULLXXX/LU540026121160200600', $statement->getAccount()->getNumber()); + } + + public function testBalance() + { + $balance = $this->statements[0]->getOpeningBalance(); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $balance); + $this->assertEquals('2021-12-06 00:00:00', $balance->getDate()->format('Y-m-d H:i:s')); + $this->assertEquals('EUR', $balance->getCurrency()); + $this->assertEquals(0, $balance->getAmount()); + + $closingBalance = $this->statements[0]->getClosingBalance(); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $closingBalance); + $this->assertEquals('2022-01-18 00:00:00', $closingBalance->getDate()->format('Y-m-d H:i:s')); + $this->assertEquals('EUR', $closingBalance->getCurrency()); + $this->assertEquals(-4, $closingBalance->getAmount()); + } + + public function testTransaction() + { + $transactions = $this->statements[0]->getTransactions(); + $this->assertCount(1, $transactions); + + $this->assertNull($transactions[0]->getContraAccount()); + $this->assertEquals(-4.00, $transactions[0]->getAmount()); + $expected = "808?00FORFAIT MENSUEL ENVOI DE COURRIER?20COMPTE . IBAN LU54 0026 1211 6020 0?21600"; + $this->assertEquals($expected, $transactions[0]->getDescription()); + $this->assertEquals('2022-01-17 00:00:00', $transactions[0]->getValueDate()->format('Y-m-d H:i:s'), 'Assert Value Date'); + $this->assertEquals('2022-01-17 00:00:00', $transactions[0]->getBookDate()->format('Y-m-d H:i:s'), 'Assert Book Date'); + $this->assertEquals('COM', $transactions[0]->getCode()); + $this->assertEquals('NONREF', $transactions[0]->getRef()); + $this->assertNull($transactions[0]->getBankRef()); + $this->assertEquals('808', $transactions[0]->getGVC()); + $this->assertEquals('FORFAIT MENSUEL ENVOI DE COURRIER', $transactions[0]->getTxText()); + $this->assertEquals( + null, + $transactions[0]->getEref() + ); + $this->assertNull($transactions[0]->getExtCode()); + $this->assertEquals(null, $transactions[0]->getBIC()); + $this->assertEquals(null, $transactions[0]->getIBAN()); + $this->assertEquals(null, $transactions[0]->getAccountHolder()); + $this->assertEquals('COMPTE . IBAN LU54 0026 1211 6020 0600', $transactions[0]->getRawSubfieldsData()); + } +} diff --git a/tests/Jejik/Tests/MT940/Parser/IngTest.php b/tests/Jejik/Tests/MT940/Parser/IngTest.php index 83e025c..4eb10c1 100644 --- a/tests/Jejik/Tests/MT940/Parser/IngTest.php +++ b/tests/Jejik/Tests/MT940/Parser/IngTest.php @@ -24,7 +24,6 @@ */ class IngTest extends TestCase { - /** * @dataProvider statementsProvider * @@ -74,8 +73,9 @@ public function testTransaction($statements) . "ING Bank N.V. tarifering ING"; $this->assertEquals($expected, $transactions[0]->getDescription()); - $this->assertNotNull($transactions[1]->getContraAccount()); - $this->assertEquals('0111111111', $transactions[1]->getContraAccount()->getNumber()); + if (null !== $transactions[1]->getContraAccount()) { + $this->assertEquals('0111111111', $transactions[1]->getContraAccount()->getNumber()); + } } /** @@ -86,7 +86,9 @@ public function testTransaction($statements) public function testBookDate($statements) { $transactions = $statements[0]->getTransactions(); - $this->assertEquals('2010-07-22 00:00:00', $transactions[6]->getValueDate()->format('Y-m-d H:i:s')); + if (null !== $transactions[6]->getValueDate()) { + $this->assertEquals('2010-07-22 00:00:00', $transactions[6]->getValueDate()->format('Y-m-d H:i:s')); + } $this->assertEquals('2010-07-23 00:00:00', $transactions[6]->getBookDate()->format('Y-m-d H:i:s')); } @@ -102,6 +104,8 @@ public function statementsProvider(): array return array( array($reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/ing-dos.txt'))), array($reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/ing-unix.txt'))), + array($reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/ing-unix-2.txt'))), + array($reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/ing-unix-3.txt'))), ); } } diff --git a/tests/Jejik/Tests/MT940/Parser/LandesBankHessenTest.php b/tests/Jejik/Tests/MT940/Parser/LandesBankHessenTest.php new file mode 100644 index 0000000..f53b558 --- /dev/null +++ b/tests/Jejik/Tests/MT940/Parser/LandesBankHessenTest.php @@ -0,0 +1,78 @@ +addParser('LandesBankHessen', \Jejik\MT940\Parser\LandesBankHessen::class); + $this->statements = $reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/landesbankhessen.txt')); + } + + public function testStatement() + { + $this->assertCount(1, $this->statements, 'Assert counting statements.'); + $statement = $this->statements[0]; + + $this->assertEquals('1', $statement->getNumber()); + $this->assertEquals('50050000/0090085309', $statement->getAccount()->getNumber()); + } + + public function testBalance() + { + $balance = $this->statements[0]->getOpeningBalance(); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $balance); + $this->assertEquals('2020-12-31 00:00:00', $balance->getDate()->format('Y-m-d H:i:s')); + $this->assertEquals('EUR', $balance->getCurrency()); + $this->assertEquals(0, $balance->getAmount()); + } + + public function testTransaction() + { + $transactions = $this->statements[0]->getTransactions(); + + $this->assertCount(1, $transactions); + $this->assertNull($transactions[0]->getContraAccount()); + + $this->assertEquals(0, $transactions[0]->getAmount()); + $expectedDescription = "835?00SONSTIGE NICHT DEF.GV-ARTEN?1059777?20 RECHNUNGSABSCHLUSS P\r\nER?2131.12.2020 GEM. 355 HGB?22 ABSCHL.SALDO PER: 31.12.20?23EUR\r\n0,00?24 DIESER KONTOAUSZUG GILT IM?25ZUSAMMENHANG MIT DEN?26ZUGRU\r\nNDELIEGENDEN?27VERTRAEGEN ALS RECHNUNG?28 IM SINNE USTG."; + $this->assertEquals($expectedDescription, $transactions[0]->getDescription()); + $this->assertEquals('2020-12-31 00:00:00', $transactions[0]->getValueDate()->format('Y-m-d H:i:s'), 'Assert Value Date'); + $this->assertEquals('2020-12-31 00:00:00', $transactions[0]->getBookDate()->format('Y-m-d H:i:s'), 'Assert Book Date'); + + $this->assertEquals('MSC' , $transactions[0]->getCode()); + $this->assertEquals('NONREF', $transactions[0]->getRef()); + $this->assertEquals(null, $transactions[0]->getBankRef()); + + $this->assertEquals('835', $transactions[0]->getGVC()); + $this->assertEquals('SONSTIGE NICHT DEF.GV-ARTEN', $transactions[0]->getTxText()); + $this->assertEquals('59777', $transactions[0]->getPrimanota()); + $this->assertNull($transactions[0]->getExtCode()); + + $this->assertNull($transactions[0]->getEref()); + + $this->assertNull($transactions[0]->getBIC()); + $this->assertNull($transactions[0]->getIBAN()); + $this->assertNull($transactions[0]->getAccountHolder()); + + $this->assertNull($transactions[0]->getKref()); + $this->assertNull($transactions[0]->getMref()); + $this->assertNull($transactions[0]->getCred()); + + $this->assertNull($transactions[0]->getSvwz()); + $this->assertNull($transactions[0]->getContraAccount()); + } +} diff --git a/tests/Jejik/Tests/MT940/Parser/LbbwTest.php b/tests/Jejik/Tests/MT940/Parser/LbbwTest.php index b2dce4e..4f03e92 100644 --- a/tests/Jejik/Tests/MT940/Parser/LbbwTest.php +++ b/tests/Jejik/Tests/MT940/Parser/LbbwTest.php @@ -26,6 +26,8 @@ class LbbwTest extends TestCase { public $statements = []; + public $statements2 = []; + /** * @throws \Jejik\MT940\Exception\NoParserFoundException */ @@ -34,6 +36,7 @@ public function setUp(): void $reader = new Reader(); $reader->addParser('Lbbw', \Jejik\MT940\Parser\Lbbw::class); $this->statements = $reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/lbbw.txt')); + $this->statements2 = $reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/lbbw2.txt')); } public function testStatement() @@ -52,6 +55,13 @@ public function testBalance() $this->assertEquals('2021-01-20 00:00:00', $balance->getDate()->format('Y-m-d H:i:s')); $this->assertEquals('EUR', $balance->getCurrency()); $this->assertEquals(0, $balance->getAmount()); + + $balance2 = $this->statements2[0]->getOpeningBalance(); + $this->assertEquals('EURO', $balance2->getCurrency()); + $this->assertEquals(0, $balance2->getAmount()); + + $closingBalance2 = $this->statements2[0]->getClosingBalance(); + self::assertEquals(1, $closingBalance2->getAmount()); } public function testTransaction() diff --git a/tests/Jejik/Tests/MT940/Parser/RaiffeisenTest.php b/tests/Jejik/Tests/MT940/Parser/RaiffeisenTest.php new file mode 100644 index 0000000..6d5ac67 --- /dev/null +++ b/tests/Jejik/Tests/MT940/Parser/RaiffeisenTest.php @@ -0,0 +1,87 @@ +addParser('Raiffeisen', Raiffeisen::class); + $this->statements = $reader->getStatements(file_get_contents(__DIR__ . '/../Fixture/document/raiffeisen.txt')); + } + + public function testStatement(): void + { + $this->assertCount(1, $this->statements, 'Assert counting statements.'); + $statement = $this->statements[0]; + + $this->assertEquals('001/0001', $statement->getNumber()); + $this->assertEquals('CCRALULL/LU1234567890123456789', $statement->getAccount()->getNumber()); + } + + public function testBalance(): void + { + $balance = $this->statements[0]->getOpeningBalance(); + $this->assertInstanceOf(\Jejik\MT940\Balance::class, $balance); + $this->assertEquals('2022-02-28 00:00:00', $balance->getDate()->format('Y-m-d H:i:s')); + $this->assertEquals('EUR', $balance->getCurrency()); + $this->assertEquals(0, $balance->getAmount()); + } + + public function testTransaction(): void + { + $transactions = $this->statements[0]->getTransactions(); + + $this->assertCount(1, $transactions); + $this->assertNull($transactions[0]->getContraAccount()); + + $this->assertEquals(1, $transactions[0]->getAmount()); + $expectedDescription = + "229\r +?00BONIFICATION\r +?20BONIFICATION\r +?21test trt\r +?22FT22059PGV08\r +?30CCRALULLXXX\r +?32ABC\r +?60ABC\r +?612 Max Mustermann,\r +?62L-3372 LEUDELANGE"; + $this->assertEquals($expectedDescription, $transactions[0]->getDescription()); + $this->assertEquals('2022-02-28 00:00:00', $transactions[0]->getValueDate()->format('Y-m-d H:i:s'), 'Assert Value Date'); + $this->assertEquals('2022-02-28 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('229', $transactions[0]->getGVC()); + $this->assertEquals('BONIFICATION', $transactions[0]->getTxText()); + $this->assertNull($transactions[0]->getPrimanota()); + $this->assertNull($transactions[0]->getExtCode()); + + $this->assertNull($transactions[0]->getEref()); + + $this->assertEquals('CCRALULLXXX', $transactions[0]->getBIC()); + $this->assertNull($transactions[0]->getIBAN()); + $this->assertEquals("ABCABC2 Max Mustermann,L-3372 LEUDELANGE", $transactions[0]->getAccountHolder()); + + $this->assertNull($transactions[0]->getKref()); + $this->assertNull($transactions[0]->getMref()); + $this->assertNull($transactions[0]->getCred()); + $this->assertNull($transactions[0]->getSvwz()); + $this->assertEquals('BONIFICATIONtest trtFT22059PGV08', $transactions[0]->getRawSubfieldsData()); + } +} diff --git a/tests/Jejik/Tests/MT940/Parser/SparkasseRdrTest.php b/tests/Jejik/Tests/MT940/Parser/SparkasseRdrTest.php index c98c8de..1e9e16b 100644 --- a/tests/Jejik/Tests/MT940/Parser/SparkasseRdrTest.php +++ b/tests/Jejik/Tests/MT940/Parser/SparkasseRdrTest.php @@ -62,7 +62,7 @@ public function testTransaction() $this->assertCount(1, $transactions); $this->assertNotNull($transactions[0]->getContraAccount()); - $this->assertEquals(1027.25, $transactions[0]->getAmount()); + $this->assertEquals(-1027.25, $transactions[0]->getAmount()); $expectedDescription = "899?00STORNO?109392?20STORNO RECHNUNGSABSCHLUSS?21PER 01.02.2\r\n020?3050652124?31900932005?32GEBÜHREN MANUELL GG UST-FRE?33I"; $this->assertEquals($expectedDescription, $transactions[0]->getDescription()); $this->assertEquals('2020-02-01 00:00:00', $transactions[0]->getValueDate()->format('Y-m-d H:i:s'), 'Assert Value Date'); diff --git a/tests/Jejik/Tests/MT940/ParserTransactionTest.php b/tests/Jejik/Tests/MT940/ParserTransactionTest.php new file mode 100644 index 0000000..d568ec7 --- /dev/null +++ b/tests/Jejik/Tests/MT940/ParserTransactionTest.php @@ -0,0 +1,97 @@ +transaction($lines); + } + + }; + + if (null !== $exceptionName) { + $this->expectException($exceptionName); + } + + $transaction = $parser->getTransactions($lines); + + if (null === $exceptionName) { + $this->assertInstanceOf(TransactionInterface::class, $transaction); + $this->assertSame($asserts['amount'], $transaction->getAmount()); + $this->assertSame($asserts['description'], $transaction->getDescription()); + } + } + + /** + * @return array[] + */ + public function createDataToTestParsingTheTransactions(): array + { + return [ + 'Succeeds on creditor' => [ + 'lines' => ['100722C12,34NOV NONREF', 'Test'], + 'exception' => null, + 'asserts' => [ + 'amount' => 12.34, + 'description' => 'Test' + ] + ], + 'Succeeds on storno-creditor' => [ + 'lines' => ['100722RC12,34NOV NONREF', 'Test'], + 'exception' => null, + 'asserts' => [ + 'amount' => -12.34, + 'description' => 'Test' + ] + ], + 'Succeeds on debitor' => [ + 'lines' => ['100722D12,34NOV NONREF', 'Test'], + 'exception' => null, + 'asserts' => [ + 'amount' => -12.34, + 'description' => 'Test' + ] + ], + 'Succeeds on storno-debitor' => [ + 'lines' => ['100722RD12,34NOV NONREF', 'Test'], + 'exception' => null, + 'asserts' => [ + 'amount' => 12.34, + 'description' => 'Test' + ] + ], + 'Fails, because debitor/creditor ID x is not allowed' => [ + 'lines' => ['100722X12,34NOV NONREF', ' Test Bank Identification'], + 'exception' => RuntimeException::class, + 'asserts' => [] + ] + ]; + } +} diff --git a/tests/Jejik/Tests/MT940/ReaderTest.php b/tests/Jejik/Tests/MT940/ReaderTest.php index fff6d26..6cc9feb 100644 --- a/tests/Jejik/Tests/MT940/ReaderTest.php +++ b/tests/Jejik/Tests/MT940/ReaderTest.php @@ -39,7 +39,7 @@ public function testDefaultParsers() $this->assertSame($e->getMessage(), 'No text is found for parsing.'); } - $this->assertCount(16, $reader->getDefaultParsers()); + $this->assertCount(20, $reader->getDefaultParsers()); } public function testAddParser()