diff --git a/.env.example.dist b/.env.example.dist new file mode 100644 index 0000000..6e19a8c --- /dev/null +++ b/.env.example.dist @@ -0,0 +1,22 @@ +EASE_EMAILTO=info@vitexsoftware.cz +EASE_LOGGER=syslog|console +LANG=cs_CZ + +CERT_FILE=vendor/vitexsoftware/rbczpremiumapi/examples/test_cert.p12 +CERT_PASS=test12345678 +XIBMCLIENTID=FbboLD2r1WHDRcuKS4wWUbSRHxlDloWL +API_DEBUG=True +STATEMENT_LINE=MAIN + +ACCOUNT_NUMBER=640805006 +ACCOUNT_CURRENCY=CZK + + +POHODA_ICO=12345678 +POHODA_URL=http://77.87.240.111:10010 +POHODA_USERNAME=Admin +POHODA_PASSWORD=xxxxxxxx +POHODA_TIMEOUT=60 +POHODA_COMPRESS=false +POHODA_DEBUG=true +POHODA_BANK_IDS=KB diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..deb1579 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +.DS_Store +config.php +import.csv +output.xml +/nbproject/private/ +/nbproject/ +.phpdoc +/.phpunit.result.cache +.env +/RAIFF_MULTIFLEXI.p12 +/debian/debhelper-build-stamp +/debian/abraflexi-raiffeisenbank.debhelper.log +/debian/abraflexi-raiffeisenbank/ +/debian/.debhelper/ +/debian/abraflexi-raiffeisenbank.substvars +/debian/files +/statement.xml diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6f095ba --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Massimo Filippi, s.r.o. + +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/bin/pohoda-raiffeisenbank-setup b/bin/pohoda-raiffeisenbank-setup new file mode 100755 index 0000000..a079111 --- /dev/null +++ b/bin/pohoda-raiffeisenbank-setup @@ -0,0 +1,4 @@ +#!/bin/bash +php -f /usr/lib/pohoda-raiffeisenbank/setup.php $@ + + diff --git a/bin/pohoda-raiffeisenbank-statements b/bin/pohoda-raiffeisenbank-statements new file mode 100644 index 0000000..6c821c3 --- /dev/null +++ b/bin/pohoda-raiffeisenbank-statements @@ -0,0 +1,2 @@ +#!/bin/bash +php -f /usr/lib/pohoda-raiffeisenbank/statements.php $@ diff --git a/bin/pohoda-raiffeisenbank-transactions b/bin/pohoda-raiffeisenbank-transactions new file mode 100755 index 0000000..481bc48 --- /dev/null +++ b/bin/pohoda-raiffeisenbank-transactions @@ -0,0 +1,2 @@ +#!/bin/bash +php -f /usr/lib/pohoda-raiffeisenbank/transactions.php $@ diff --git a/bin/raiffeisenbank-balance b/bin/raiffeisenbank-balance new file mode 100644 index 0000000..c3e9235 --- /dev/null +++ b/bin/raiffeisenbank-balance @@ -0,0 +1,4 @@ +#!/bin/bash +php -f /usr/lib/pohoda-raiffeisenbank/balance.php $@ + + diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..0dadac2 --- /dev/null +++ b/composer.json @@ -0,0 +1,30 @@ +{ + "name": "vitexsoftware/pohoda-raiffeisenbank", + "description": "raiffeisenbank bank statement downloader for Stormware Pohoda", + "license": "MIT", + "authors": [ + { + "name": "Vítězslav Dvořák", + "email": "info@vitexsoftware.cz" + } + ], + "minimum-stability": "dev", + "require": { + "vitexsoftware/pohoda-connector": "dev-main", + "vitexsoftware/rbczpremiumapi": "dev-main" + }, + "autoload": { + "psr-4": { + "Pohoda\\RaiffeisenBank\\": "src/Pohoda/RaiffeisenBank/" + } + }, + "autoload-dev": { + "psr-4": { + "Test\\Pohoda\\": "vendor/spojenet/abraflexi/testing/src/Pohoda/", + "Test\\Pohoda\\RaiffeisenBank\\": "tests/Pohoda/RaiffeisenBank/" + } + }, + "require-dev": { + "phpunit/phpunit": "^9" + } +} diff --git a/src/Pohoda/RaiffeisenBank/PohodaBankClient.php b/src/Pohoda/RaiffeisenBank/PohodaBankClient.php new file mode 100644 index 0000000..5f4e0c4 --- /dev/null +++ b/src/Pohoda/RaiffeisenBank/PohodaBankClient.php @@ -0,0 +1,234 @@ + + * @copyright (C) 2023 Spoje.Net + */ + +namespace Pohoda\RaiffeisenBank; + +/** + * Description of ApiClient + * + * @author vitex + */ +abstract class PohodaBankClient extends \mServer\Bank +{ + protected $constantor; + + protected $constSymbols; + + /** + * + * @var \DateTime + */ + protected $since; + + /** + * + * @var \DateTime + */ + protected $until; + + /** + * DateTime Formating eg. 2021-08-01T10:00:00.0Z + * @var string + */ + public static $dateTimeFormat = 'Y-m-d\\TH:i:s.0\\Z'; + + /** + * DateTime Formating eg. 2021-08-01T10:00:00.0Z + * @var string + */ + public static $dateFormat = 'Y-m-d'; + + /** + * + * @var + */ + protected $bank; + + /** + * Transaction Handler + * + * @param string $bankAccount Account Number + * @param array $options + */ + public function __construct($bankAccount, $options = []) + { + parent::__construct(); + $this->setDataValue('account', $bankAccount); +// $this->constantor = new \Pohoda\RW(null, ['evidence' => 'konst-symbol']); +// $this->constSymbols = $this->constantor->getColumnsFromPohoda(['kod'], ['limit' => 0], 'kod'); + } + + /** + * Source Identifier + * + * @return string + */ + public function sourceString() + { + return substr(__FILE__ . '@' . gethostname(), -50); + } + + /** + * Try to check certificate readibilty + * + * @param string $certFile path to certificate + */ + public static function checkCertificatePresence($certFile) + { + if ((file_exists($certFile) === false) || (is_readable($certFile) === false)) { + fwrite(STDERR, 'Cannot read specified certificate file: ' . $certFile . PHP_EOL); + exit; + } + } + + /** + * Prepare processing interval + * + * @param string $scope + * + * @throws \Exception + */ + function setScope($scope) + { + switch ($scope) { + case 'today': + $this->since = (new \DateTime())->setTime(0, 0); + $this->until = (new \DateTime())->setTime(23, 59); + break; + case 'yesterday': + $this->since = (new \DateTime('yesterday'))->setTime(0, 0); + $this->until = (new \DateTime('yesterday'))->setTime(23, 59); + break; + case 'current_month': + $this->since = new \DateTime("first day of this month"); + $this->until = new \DateTime(); + break; + case 'last_month': + $this->since = new \DateTime("first day of last month"); + $this->until = new \DateTime("last day of last month"); + break; + case 'last_two_months': + $this->since = (new \DateTime("first day of last month"))->modify('-1 month'); + $this->until = (new \DateTime("last day of last month")); + break; + case 'previous_month': + $this->since = new \DateTime("first day of -2 month"); + $this->until = new \DateTime("last day of -2 month"); + break; + case 'two_months_ago': + $this->since = new \DateTime("first day of -3 month"); + $this->until = new \DateTime("last day of -3 month"); + break; + case 'this_year': + $this->since = new \DateTime('first day of January ' . date('Y')); + $this->until = new \DateTime("last day of December" . date('Y')); + break; + case 'January': //1 + case 'February': //2 + case 'March': //3 + case 'April': //4 + case 'May': //5 + case 'June': //6 + case 'July': //7 + case 'August': //8 + case 'September'://9 + case 'October': //10 + case 'November': //11 + case 'December': //12 + $this->since = new \DateTime('first day of ' . $scope . ' ' . date('Y')); + $this->until = new \DateTime('last day of ' . $scope . ' ' . date('Y')); + break; + case 'auto': + $latestRecord = $this->getColumnsFromPohoda(['id', 'lastUpdate'], ['limit' => 1, 'order' => 'lastUpdate@A', 'source' => $this->sourceString(), 'banka' => $this->bank]); + if (array_key_exists(0, $latestRecord) && array_key_exists('lastUpdate', $latestRecord[0])) { + $this->since = $latestRecord[0]['lastUpdate']; + } else { + $this->addStatusMessage('Previous record for "auto since" not found. Defaulting to today\'s 00:00', 'warning'); + $this->since = (new \DateTime())->setTime(0, 0); + } + $this->until = new \DateTime(); //Now + break; + default: + throw new \Exception('Unknown scope ' . $scope); + break; + } + if ($scope != 'auto' && $scope != 'today' && $scope != 'yesterday') { + $this->since = $this->since->setTime(0, 0); + $this->until = $this->until->setTime(0, 0); + } + } + + /** + * Request Identifier + * + * @return string + */ + public function getxRequestId() + { + return $this->getDataValue('account') . time(); + } + + /** + * Obtain Current Currency + * + * @return string + */ + public function getCurrencyCode() + { + return \Ease\Shared::cfg('ACCOUNT_CURRENCY', 'CZK'); + } + + /** + * Is Record with current remoteNumber already present in Pohoda ? + * + * @return bool + */ + public function checkForTransactionPresence() + { + return false; //!empty($this->getColumnsFromPohoda('id', ['cisDosle' => $this->getDataValue('cisDosle')])); + } + + /** + * + * @param string $conSym + */ + public function ensureKSExists($conSym) + { + if (!array_key_exists($conSym, $this->constSymbols)) { + $this->constantor->insertToPohoda(['kod' => $conSym, 'poznam' => 'Created by Raiffeisen Bank importer', 'nazev' => '?!?!? ' . $conSym]); + $this->constantor->addStatusMessage('New constant ' . $conSym . ' created in flexibee', 'warning'); + $this->constSymbols[$conSym] = $conSym; + } + } + + /** + * + * @param int $success + * + * @return int + */ + public function insertTransactionToPohoda($success) + { + if ($this->checkForTransactionPresence() === false) { + try { + $cache = $this->getData(); + $this->reset(); + //TODO: $result = $this->sync(); + $result = $this->addToPohoda($cache); + $this->commit(); + } catch (\Pohoda\Exception $exc) { + } + $this->addStatusMessage('New entry ', $result ? 'success' : 'error'); + $success++; + } else { + $this->addStatusMessage('Record with remoteNumber ' . 'TODO' . ' already present in Pohoda', 'warning'); + } + return $success; + } +} diff --git a/src/Pohoda/RaiffeisenBank/Statementor.php b/src/Pohoda/RaiffeisenBank/Statementor.php new file mode 100644 index 0000000..ad5000b --- /dev/null +++ b/src/Pohoda/RaiffeisenBank/Statementor.php @@ -0,0 +1,200 @@ + + * @copyright (C) 2023 Spoje.Net + */ + +namespace Pohoda\RaiffeisenBank; + +/** + * Description of Statementor + * + * @author vitex + */ +class Statementor extends PohodaBankClient +{ + /** + * Obtain Transactions from RB + * + * @return array + */ + public function getStatements() + { + $apiInstance = new \VitexSoftware\Raiffeisenbank\PremiumAPI\GetStatementListApi(); + $page = 1; + $statements = []; + $requestBody = new \VitexSoftware\Raiffeisenbank\Model\GetStatementsRequest(['accountNumber' => $this->bank->getDataValue('account'), 'currency' => $this->getCurrencyCode(), 'statementLine' => \Ease\Functions::cfg('STATEMENT_LINE', 'MAIN'), 'dateFrom' => $this->since->format(self::$dateFormat), 'dateTo' => $this->until->format(self::$dateFormat)]); + $this->addStatusMessage(sprintf(_('Request statements from %s to %s'), $this->since->format(self::$dateFormat), $this->until->format(self::$dateFormat)), 'debug'); + try { + do { + $result = $apiInstance->getStatements($this->getxRequestId(), $requestBody, $page); + if (empty($result)) { + $this->addStatusMessage(sprintf(_('No transactions from %s to %s'), $this->since->format(self::$dateFormat), $this->until->format(self::$dateFormat))); + $result['lastPage'] = true; + } + if (array_key_exists('statements', $result)) { + $statements = array_merge($statements, $result['statements']); + } + } while ($result['last'] === false); + } catch (Exception $e) { + echo 'Exception when calling GetTransactionListApi->getTransactionList: ', $e->getMessage(), PHP_EOL; + } + return $statements; + } + + public function import() + { + $statements = $this->getStatements(); + if ($statements) { + $apiInstance = new \VitexSoftware\Raiffeisenbank\PremiumAPI\DownloadStatementApi(); + $success = 0; + foreach ($statements as $statement) { + $requestBody = new \VitexSoftware\Raiffeisenbank\Model\DownloadStatementRequest(['accountNumber' => $this->bank->getDataValue('buc'), 'currency' => $this->getCurrencyCode(), 'statementId' => $statement->statementId, 'statementFormat' => 'xml']); + $xmlStatementRaw = $apiInstance->downloadStatement($this->getxRequestId(), 'cs', $requestBody); + $statementXML = new \SimpleXMLElement($xmlStatementRaw); + foreach ($statementXML->BkToCstmrStmt->Stmt->Ntry as $ntry) { + $this->dataReset(); + $this->ntryToPohoda($ntry); + $this->setDataValue('vypisCisDokl', $statementXML->BkToCstmrStmt->Stmt->Id); + $this->setDataValue('cisSouhrnne', $statementXML->BkToCstmrStmt->Stmt->LglSeqNb); + $success = $this->insertTransactionToPohoda($success); + } + $this->addStatusMessage('Import done. ' . $success . ' of ' . count($statements) . ' imported'); + } + } + } + + /** + * Parse Ntry element into \Pohoda\Banka data + * + * @param SimpleXMLElement $ntry + * + * @return array + */ + public function ntryToPohoda($ntry) + { + $this->setDataValue('typDokl', \Pohoda\RO::code(\Ease\Functions::cfg('TYP_DOKLADU', 'STANDARD'))); + $this->setDataValue('bezPolozek', true); + $this->setDataValue('stavUzivK', 'stavUziv.nactenoEl'); + $this->setDataValue('poznam', 'Import Job ' . \Ease\Functions::cfg('JOB_ID', 'n/a')); + if (trim($ntry->CdtDbtInd) == 'CRDT') { + $this->setDataValue('rada', \Pohoda\RO::code('BANKA+')); + } else { + $this->setDataValue('rada', \Pohoda\RO::code('BANKA-')); + } + + $moveTrans = ['DBIT' => 'typPohybu.vydej', 'CRDT' => 'typPohybu.prijem']; + $this->setDataValue('typPohybuK', $moveTrans[trim($ntry->CdtDbtInd)]); + $this->setDataValue('cisDosle', strval($ntry->NtryRef)); + $this->setDataValue('datVyst', \Pohoda\RO::dateToFlexiDate(new \DateTime($ntry->BookgDt->DtTm))); + $this->setDataValue('sumOsv', abs($ntry->Amt)); + $this->setDataValue('banka', $this->bank); + $this->setDataValue('mena', \Pohoda\RO::code($ntry->Amt->attributes()->Ccy)); + if (property_exists($ntry, 'NtryDtls')) { + if (property_exists($ntry->NtryDtls, 'TxDtls')) { + $conSym = $ntry->NtryDtls->TxDtls->Refs->InstrId; + if (intval($conSym)) { + $conSym = sprintf('%04d', $conSym); + $this->ensureKSExists($conSym); + $this->setDataValue('konSym', \Pohoda\RO::code($conSym)); + } + + if (property_exists($ntry->NtryDtls->TxDtls->Refs, 'EndToEndId')) { + $this->setDataValue('varSym', $ntry->NtryDtls->TxDtls->Refs->EndToEndId); + } + $transactionData['popis'] = $ntry->NtryDtls->TxDtls->AddtlTxInf; + if (property_exists($ntry->NtryDtls->TxDtls, 'RltdPties')) { + if (property_exists($ntry->NtryDtls->TxDtls->RltdPties, 'DbtrAcct')) { + $this->setDataValue('buc', $ntry->NtryDtls->TxDtls->RltdPties->DbtrAcct->Id->Othr->Id); + } + $this->setDataValue('nazFirmy', $ntry->NtryDtls->TxDtls->RltdPties->DbtrAcct->Nm); + } + + if (property_exists($ntry->NtryDtls->TxDtls, 'RltdAgts')) { + if (property_exists($ntry->NtryDtls->TxDtls->RltdAgts->DbtrAgt, 'FinInstnId')) { + $this->setDataValue('smerKod', \Pohoda\RO::code($ntry->NtryDtls->TxDtls->RltdAgts->DbtrAgt->FinInstnId->Othr->Id)); + } + } + } + } + + $this->setDataValue('source', $this->sourceString()); + return $transactionData; + } + + /** + * Prepare processing interval + * + * @param string $scope + * + * @throws \Exception + */ + function setScope($scope) + { + switch ($scope) { + case 'yesterday': + $this->since = (new \DateTime('yesterday'))->setTime(0, 0); + $this->until = (new \DateTime('yesterday'))->setTime(23, 59); + break; + case 'current_month': + $this->since = new \DateTime("first day of this month"); + $this->until = new \DateTime(); + break; + case 'last_month': + $this->since = new \DateTime("first day of last month"); + $this->until = new \DateTime("last day of last month"); + break; + case 'last_two_months': + $this->since = (new \DateTime("first day of last month"))->modify('-1 month'); + $this->until = (new \DateTime("last day of last month")); + break; + case 'previous_month': + $this->since = new \DateTime("first day of -2 month"); + $this->until = new \DateTime("last day of -2 month"); + break; + case 'two_months_ago': + $this->since = new \DateTime("first day of -3 month"); + $this->until = new \DateTime("last day of -3 month"); + break; + case 'this_year': + $this->since = new \DateTime('first day of January ' . date('Y')); + $this->until = new \DateTime("last day of December" . date('Y')); + break; + case 'January': //1 + case 'February': //2 + case 'March': //3 + case 'April': //4 + case 'May': //5 + case 'June': //6 + case 'July': //7 + case 'August': //8 + case 'September'://9 + case 'October': //10 + case 'November': //11 + case 'December': //12 + $this->since = new \DateTime('first day of ' . $scope . ' ' . date('Y')); + $this->until = new \DateTime('last day of ' . $scope . ' ' . date('Y')); + break; + case 'auto': + $latestRecord = $this->getColumnsFromPohoda(['id', 'lastUpdate'], ['limit' => 1, 'order' => 'lastUpdate@A', 'source' => $this->sourceString(), 'banka' => $this->bank]); + if (array_key_exists(0, $latestRecord) && array_key_exists('lastUpdate', $latestRecord[0])) { + $this->since = $latestRecord[0]['lastUpdate']; + } else { + $this->addStatusMessage('Previous record for "auto since" not found. Defaulting to today\'s 00:00', 'warning'); + $this->since = (new \DateTime())->setTime(0, 0); + } + $this->until = new \DateTime(); //Now + break; + default: + throw new \Exception('Unknown scope ' . $scope); + break; + } + if ($scope != 'auto' && $scope != 'today' && $scope != 'yesterday') { + $this->since = $this->since->setTime(0, 0); + $this->until = $this->until->setTime(0, 0); + } + } +} diff --git a/src/Pohoda/RaiffeisenBank/Transactor.php b/src/Pohoda/RaiffeisenBank/Transactor.php new file mode 100644 index 0000000..00f8873 --- /dev/null +++ b/src/Pohoda/RaiffeisenBank/Transactor.php @@ -0,0 +1,210 @@ + + * @copyright (C) 2023 Spoje.Net + */ + +namespace Pohoda\RaiffeisenBank; + +/** + * Handle bank transactions + * + * @author vitex + */ +class Transactor extends PohodaBankClient +{ + /** + * Transaction Handler + * + * @param null $init + * @param array $options + */ + public function __construct($bankAccount, $options = []) + { + parent::__construct($bankAccount, $options); + } + + /** + * Obtain Transactions from RB + * + * @return array + */ + public function getTransactions() + { + $apiInstance = new \VitexSoftware\Raiffeisenbank\PremiumAPI\GetTransactionListApi(); + $page = 1; + $transactions = []; + $this->addStatusMessage(sprintf(_('Request transactions from %s to %s'), $this->since->format(self::$dateTimeFormat), $this->until->format(self::$dateTimeFormat)), 'debug'); + try { + do { + $result = $apiInstance->getTransactionList($this->getxRequestId(), $this->getDataValue('account'), $this->getCurrencyCode(), $this->since->format(self::$dateTimeFormat), $this->until->format(self::$dateTimeFormat), $page); + if (empty($result)) { + $this->addStatusMessage(sprintf(_('No transactions from %s to %s'), $this->since->format(self::$dateTimeFormat), $this->until->format(self::$dateTimeFormat))); + $result['lastPage'] = true; + } + if (array_key_exists('transactions', $result)) { + $transactions = array_merge($transactions, $result['transactions']); + } + } while ($result['lastPage'] === false); + } catch (Exception $e) { + echo 'Exception when calling GetTransactionListApi->getTransactionList: ', $e->getMessage(), PHP_EOL; + } + return $transactions; + } + + /** + * Import process itself + */ + public function import() + { +// $allMoves = $this->getColumnsFromPohoda('id', ['limit' => 0, 'banka' => $this->bank]); + $allTransactions = $this->getTransactions(); + $this->addStatusMessage(count($allTransactions) . ' transactions obtained via API', 'debug'); + $success = 0; + foreach ($allTransactions as $transaction) { + //$this->dataReset(); + $this->takeTransactionData($transaction); + $success = $this->insertTransactionToPohoda($success); + $this->reset(); + } + $this->addStatusMessage('Import done. ' . $success . ' of ' . count($allTransactions) . ' imported'); + } + + /** + * Use Transaction data for Bank record + * + * @param array $transactionData + */ + public function takeTransactionData($transactionData) + { +// $this->setMyKey(\Pohoda\RO::code('RB' . $transactionData->entryReference)); + $moveTrans = [ + 'DBIT' => 'expense', + 'CRDT' => 'receipt' + ]; + $this->setDataValue('bankType', $moveTrans[$transactionData->creditDebitIndication]); + $this->setDataValue('account', \Ease\Shared::cfg('POHODA_BANK_IDS')); // KB + $this->setDataValue('datePayment', (new \DateTime($transactionData->valueDate))->format('Y-m-d')); + $this->setDataValue('intNote', _('Automatic Import') . ': ' . \Ease\Shared::appName() . ' ' . \Ease\Shared::appVersion() . ' ' . $transactionData->entryReference); + $this->setDataValue('statementNumber', ['statementNumber' => $transactionData->bankTransactionCode->code]); + $counterAccount = $transactionData->entryDetails->transactionDetails->relatedParties->counterParty; +//$bankRecord = [ +//// "MOSS" => ['ids' => 'AB'], +// 'account' => 'KB', +//// "accounting", +//// "accountingPeriodMOSS", +//// "activity" => 'testing', +// 'bankType' => 'receipt', +//// "centre", +//// "classificationKVDPH", +//// "classificationVAT", +// "contract" => 'n/a', +// "datePayment" => date('Y-m-d'), +// "dateStatement" => date('Y-m-d'), +//// "evidentiaryResourcesMOSS", +// "intNote" => 'Import works well', +//// "myIdentity", +// "note" => 'Automated import', +// 'partnerIdentity' => ['address' => ['street' => 'dlouha'], 'shipToAddress' => ['street' => 'kratka']], +// "paymentAccount" => ['accountNo' => '1234', 'bankCode' => '5500'], +// 'statementNumber' => [ +// 'statementNumber' => (string) time(), +// //'numberMovement' => (string) time() +// ], +//// "symConst" => 'XX', +//// ?"symPar", +// "symSpec" => '23', +// "symVar" => (string) time(), +// "text" => 'Testing income ' . time(), +// 'homeCurrency' => ['priceNone' => '1001'] +//]; +// $this->setDataValue('cisDosle', $transactionData->entryReference); + if (property_exists($transactionData->entryDetails->transactionDetails->remittanceInformation, 'creditorReferenceInformation')) { + if (property_exists($transactionData->entryDetails->transactionDetails->remittanceInformation->creditorReferenceInformation, 'variable')) { + $this->setDataValue('symVar', $transactionData->entryDetails->transactionDetails->remittanceInformation->creditorReferenceInformation->variable); + } +// if (property_exists($transactionData->entryDetails->transactionDetails->remittanceInformation->creditorReferenceInformation, 'constant')) { +// $conSym = $transactionData->entryDetails->transactionDetails->remittanceInformation->creditorReferenceInformation->constant; +// if (intval($conSym)) { +// $conSym = sprintf('%04d', $conSym); +// $this->ensureKSExists($conSym); +// $this->setDataValue('konSym', \Pohoda\RO::code($conSym)); +// } +// } + } + + +// $this->setDataValue('datVyst', $transactionData->bookingDate); + //$this->setDataValue('duzpPuv', $transactionData->valueDate); + if (property_exists($transactionData->entryDetails->transactionDetails->remittanceInformation, 'originatorMessage')) { + $this->setDataValue('text', $transactionData->entryDetails->transactionDetails->remittanceInformation->originatorMessage); + } + + $this->setDataValue('note', 'Import Job ' . \Ease\Functions::cfg('JOB_ID', 'n/a')); + if (property_exists($transactionData->entryDetails->transactionDetails->relatedParties, 'counterParty')) { + if (property_exists($transactionData->entryDetails->transactionDetails->relatedParties->counterParty, 'name')) { +//TODO $this->setDataValue('nazFirmy', $transactionData->entryDetails->transactionDetails->relatedParties->counterParty->name); + } + + + $counterAccountNumber = $counterAccount->account->accountNumber; + if (property_exists($counterAccount->account, 'accountNumberPrefix')) { + $accountNumber = $counterAccount->account->accountNumberPrefix . '-' . $counterAccountNumber; + } else { + $accountNumber = $counterAccountNumber; + } + $this->setDataValue('paymentAccount', ['accountNo' => $accountNumber, 'bankCode' => $counterAccount->organisationIdentification->bankCode]); + + $amount = strval(abs($transactionData->amount->value)); + if ($transactionData->amount->currency == 'CZK') { + $this->setDataValue('homeCurrency', ['priceNone' => $amount]); + } else { + $this->setDataValue('foreginCurrency', ['priceNone' => $amount]); //TODO: Not tested + } + } + +// $this->setDataValue('source', $this->sourceString()); +// echo $this->getJsonizedData() . "\n"; + } + + /** + * Prepare processing interval + * + * @param string $scope + * + * @throws \Exception + */ + function setScope($scope) + { + switch ($scope) { + case 'today': + $this->since = (new \DateTime())->setTime(0, 0); + $this->until = (new \DateTime())->setTime(23, 59); + break; + case 'yesterday': + $this->since = (new \DateTime('yesterday'))->setTime(0, 0); + $this->until = (new \DateTime('yesterday'))->setTime(23, 59, 59, 999); + break; + case 'auto': + $latestRecord = $this->getColumnsFromPohoda(['id', 'lastUpdate'], ['limit' => 1, 'order' => 'lastUpdate@A', 'source' => $this->sourceString(), 'banka' => $this->bank]); + if (array_key_exists(0, $latestRecord) && array_key_exists('lastUpdate', $latestRecord[0])) { + $this->since = $latestRecord[0]['lastUpdate']; + } else { + $this->addStatusMessage('Previous record for "auto since" not found. Defaulting to today\'s 00:00', 'warning'); + $this->since = (new \DateTime('yesterday'))->setTime(0, 0); + } + $this->until = (new \DateTime('two days ago'))->setTime(0, 0); //Now + break; + default: + throw new \Exception('Unknown scope ' . $scope); + break; + } + if ($scope != 'auto' && $scope != 'today' && $scope != 'yesterday') { + $this->since = $this->since->setTime(0, 0); + $this->until = $this->until->setTime(0, 0); + } + } +} diff --git a/src/balance.php b/src/balance.php new file mode 100644 index 0000000..d3d4f2e --- /dev/null +++ b/src/balance.php @@ -0,0 +1,27 @@ + + * @copyright (C) 2023 Spoje.Net + */ + +namespace Pohoda\RaiffeisenBank; + +require_once('../vendor/autoload.php'); + +const APP_NAME = 'RaiffeisenBankBalance'; +/** + * Get today's tramsactons list + */ +\Ease\Shared::init(['POHODA_URL', 'POHODA_LOGIN', 'POHODA_PASSWORD', 'POHODA_COMPANY', 'CERT_FILE', 'CERT_PASS', 'XIBMCLIENTID', 'ACCOUNT_NUMBER'], isset($argv[1]) ? $argv[1] : '../.env'); +Transactor::checkCertificatePresence(\Ease\Functions::cfg('CERT_FILE')); +$apiInstance = new \VitexSoftware\Raiffeisenbank\PremiumAPI\GetAccountBalanceApi(); +$xRequestId = time(); +try { + $result = $apiInstance->getBalance($xRequestId, \Ease\Functions::cfg('ACCOUNT_NUMBER')); + echo json_encode($result, JSON_PRETTY_PRINT); +} catch (Exception $e) { + echo 'Exception when calling GetAccountBalanceApi->getBalance: ', $e->getMessage(), PHP_EOL; +} diff --git a/src/setup.php b/src/setup.php new file mode 100644 index 0000000..4b3db3b --- /dev/null +++ b/src/setup.php @@ -0,0 +1,52 @@ + + * @copyright (C) 2023 Spoje.Net + */ + +namespace Pohoda\RaiffeisenBank; + +require_once('../vendor/autoload.php'); +/** + * Get List of bank accounts and import it into Pohoda + */ +\Ease\Shared::init(['POHODA_URL', 'POHODA_LOGIN', 'POHODA_PASSWORD', 'POHODA_COMPANY', 'CERT_FILE', 'CERT_PASS', 'XIBMCLIENTID'], isset($argv[1]) ? $argv[1] : '../.env'); +$apiInstance = new \VitexSoftware\Raiffeisenbank\PremiumAPI\GetAccountsApi(); +$x_request_id = time(); // string | Unique request id provided by consumer application for reference and auditing. + +Transactor::checkCertificatePresence(\Ease\Functions::cfg('CERT_FILE')); +try { + $result = $apiInstance->getAccounts($x_request_id); + if (array_key_exists('accounts', $result)) { + $banker = new \Pohoda\RW(null, ['evidence' => 'bankovni-ucet']); + if (\Ease\Functions::cfg('APP_DEBUG')) { + $banker->logBanner($apiInstance->getConfig()->getUserAgent()); + } + $currentAccounts = $banker->getColumnsFromPohoda(['id', 'kod', 'nazev', 'iban', 'bic', 'nazBanky', 'poznam'], ['limit' => 0], 'iban'); + foreach ($result['accounts'] as $account) { + if (array_key_exists($account->iban, $currentAccounts)) { + $banker->addStatusMessage(sprintf('Account %s already exists in flexibee as %s', $account->friendlyName, $currentAccounts[$account->iban]['kod'])); + } else { + $banker->dataReset(); + $banker->setDataValue('kod', 'RB' . $account->accountId); + $banker->setDataValue('nazev', $account->accountName); + $banker->setDataValue('buc', $account->accountNumber); + $banker->setDataValue('nazBanky', 'Raiffeisenbank'); + $banker->setDataValue('popis', $account->friendlyName); + $banker->setDataValue('iban', $account->iban); + $banker->setDataValue('smerKod', \Pohoda\RO::code($account->bankCode)); + $banker->setDataValue('bic', $account->bankBicCode); + $saved = $banker->sync(); + $banker->addStatusMessage( + sprintf('Account %s registered in flexibee as %s', $account->friendlyName, $banker->getRecordCode()), + ($saved ? 'success' : 'error') + ); + } + } + } +} catch (Exception $e) { + echo 'Exception when calling GetAccountsApi->getAccounts: ', $e->getMessage(), PHP_EOL; +} diff --git a/src/statements.php b/src/statements.php new file mode 100644 index 0000000..99dfc86 --- /dev/null +++ b/src/statements.php @@ -0,0 +1,20 @@ + + * @copyright (C) 2023 Spoje.Net + */ + +namespace Pohoda\RaiffeisenBank; + +require_once('../vendor/autoload.php'); +/** + * Get today's tramsactons list + */ +\Ease\Shared::init(['POHODA_URL', 'POHODA_USERNAME', 'POHODA_PASSWORD', 'POHODA_ICO', 'CERT_FILE', 'CERT_PASS', 'XIBMCLIENTID', 'ACCOUNT_NUMBER'], isset($argv[1]) ? $argv[1] : '../.env'); +PohodaBankClient::checkCertificatePresence(\Ease\Functions::cfg('CERT_FILE')); +$engine = new Statementor(\Ease\Functions::cfg('ACCOUNT_NUMBER')); +$engine->setScope(\Ease\Functions::cfg('STATEMENT_IMPORT_SCOPE', 'last_month')); +$engine->import(); diff --git a/src/transactions.php b/src/transactions.php new file mode 100644 index 0000000..731e4b7 --- /dev/null +++ b/src/transactions.php @@ -0,0 +1,20 @@ + + * @copyright (C) 2023 Spoje.Net + */ + +namespace Pohoda\RaiffeisenBank; + +require_once('../vendor/autoload.php'); +/** + * Get today's tramsactons list + */ +\Ease\Shared::init(['POHODA_URL', 'POHODA_USERNAME', 'POHODA_PASSWORD', 'POHODA_ICO', 'CERT_FILE', 'CERT_PASS', 'XIBMCLIENTID', 'ACCOUNT_NUMBER'], isset($argv[1]) ? $argv[1] : '../.env'); +Transactor::checkCertificatePresence(\Ease\Functions::cfg('CERT_FILE')); +$engine = new Transactor(\Ease\Functions::cfg('ACCOUNT_NUMBER')); +$engine->setScope(\Ease\Functions::cfg('TRANSACTION_IMPORT_SCOPE', 'yesterday')); +$engine->import();