From 00418e390bfcf0b3cf9a11a0f0054ad1a91db3aa Mon Sep 17 00:00:00 2001 From: Philippe Sampont Date: Thu, 14 Jun 2018 16:58:09 +0200 Subject: [PATCH] Issue #5 : Convert NBAN to IBAN in importer --- CRM/Banking/PluginImpl/Importer/CODA.php | 14 ++ README.md | 18 ++- .../BankingAccountReference/Convertnban.php | 53 +++++++ coda.civix.php | 142 ++++++++++++++++-- phpunit.xml.dist | 18 +++ .../ConvertnbanTest.php | 49 ++++++ tests/phpunit/bootstrap.php | 62 ++++++++ 7 files changed, 334 insertions(+), 22 deletions(-) create mode 100644 api/v3/BankingAccountReference/Convertnban.php create mode 100644 phpunit.xml.dist create mode 100644 tests/phpunit/api/v3/BankingAccountReference/ConvertnbanTest.php create mode 100644 tests/phpunit/bootstrap.php diff --git a/CRM/Banking/PluginImpl/Importer/CODA.php b/CRM/Banking/PluginImpl/Importer/CODA.php index 92095ef..cce498e 100644 --- a/CRM/Banking/PluginImpl/Importer/CODA.php +++ b/CRM/Banking/PluginImpl/Importer/CODA.php @@ -133,6 +133,20 @@ function import_file( $file_path, $params ) // look up the bank accounts // TODO: move to abstract class foreach ($transaction_data as $key => $value) { + // Convert NBAN to IBAN + if (preg_match('/^_party_NBAN_(..)$/', $key, $matches)) { + $country = $matches[1]; + $result = civicrm_api('BankingAccountReference', 'convertnban', array('version' => 3, 'nban' => $value), $country); + if (!$result['is_error']) { + $party_iban = $result['values'][0]; + $transaction_data['_party_IBAN'] = $party_iban; + + $result = civicrm_api3('Bic', 'findbyiban', array( + 'iban' => $party_iban, + )); + $transaction_data['_party_BIC'] = $result['bic']; + } + } // check for NBAN_?? or IBAN endings if (preg_match('/^_.*NBAN_..$/', $key) || preg_match('/^_.*IBAN$/', $key)) { // this is a *BAN entry -> look it up diff --git a/README.md b/README.md index 9eb5241..ad25179 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,17 @@ # CiviBanking CODA Importer -CiviBanking CODA importer is an [CiviBanking](https://github.com/Project60/org.project60.banking) extension for importing CODA files. +CiviBanking CODA importer is a [CiviBanking](https://github.com/Project60/org.project60.banking) extension for importing CODA files. Development Installation ======================== -Clone repository into you CiviCRM extensions folder, e.g. like this: -``` -> cd /var/www/drupal/sites/default/files/extensions/ -> git clone https://github.com/Project60/org.project60.banking.git -> cd org.project60.coda -> composer install +1. Install [Little BIC extension](https://github.com/Project60/org.project60.bic) + +2. Clone repository into you CiviCRM extensions folder + > cd /var/www/drupal/sites/default/files/extensions/ + > git clone https://github.com/Project60/org.project60.banking.git + > cd org.project60.coda + + +3. Install 3rd party libraries + > composer install diff --git a/api/v3/BankingAccountReference/Convertnban.php b/api/v3/BankingAccountReference/Convertnban.php new file mode 100644 index 0000000..1a69e72 --- /dev/null +++ b/api/v3/BankingAccountReference/Convertnban.php @@ -0,0 +1,53 @@ +getUrl(self::LONG_NAME), '/'); + } + return CRM_Core_Resources::singleton()->getUrl(self::LONG_NAME, $file); + } + + /** + * Get the path of a resource file (in this extension). + * + * @param string|NULL $file + * Ex: NULL. + * Ex: 'css/foo.css'. + * @return string + * Ex: '/var/www/example.org/sites/default/ext/org.example.foo'. + * Ex: '/var/www/example.org/sites/default/ext/org.example.foo/css/foo.css'. + */ + public static function path($file = NULL) { + // return CRM_Core_Resources::singleton()->getPath(self::LONG_NAME, $file); + return __DIR__ . ($file === NULL ? '' : (DIRECTORY_SEPARATOR . $file)); + } + + /** + * Get the name of a class within this extension. + * + * @param string $suffix + * Ex: 'Page_HelloWorld' or 'Page\\HelloWorld'. + * @return string + * Ex: 'CRM_Foo_Page_HelloWorld'. + */ + public static function findClass($suffix) { + return self::CLASS_PREFIX . '_' . str_replace('\\', '_', $suffix); + } + +} + +use CRM_Coda_ExtensionUtil as E; + /** * (Delegated) Implements hook_civicrm_config(). * @@ -19,14 +96,14 @@ function _coda_civix_civicrm_config(&$config = NULL) { $extRoot = dirname(__FILE__) . DIRECTORY_SEPARATOR; $extDir = $extRoot . 'templates'; - if ( is_array( $template->template_dir ) ) { - array_unshift( $template->template_dir, $extDir ); + if (is_array($template->template_dir)) { + array_unshift($template->template_dir, $extDir); } else { - $template->template_dir = array( $extDir, $template->template_dir ); + $template->template_dir = array($extDir, $template->template_dir); } - $include_path = $extRoot . PATH_SEPARATOR . get_include_path( ); + $include_path = $extRoot . PATH_SEPARATOR . get_include_path(); set_include_path($include_path); } @@ -55,6 +132,20 @@ function _coda_civix_civicrm_install() { } } +/** + * Implements hook_civicrm_postInstall(). + * + * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_postInstall + */ +function _coda_civix_civicrm_postInstall() { + _coda_civix_civicrm_config(); + if ($upgrader = _coda_civix_upgrader()) { + if (is_callable(array($upgrader, 'onPostInstall'))) { + $upgrader->onPostInstall(); + } + } +} + /** * Implements hook_civicrm_uninstall(). * @@ -117,7 +208,7 @@ function _coda_civix_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) { * @return CRM_Coda_Upgrader */ function _coda_civix_upgrader() { - if (!file_exists(__DIR__.'/CRM/Coda/Upgrader.php')) { + if (!file_exists(__DIR__ . '/CRM/Coda/Upgrader.php')) { return NULL; } else { @@ -153,7 +244,8 @@ function _coda_civix_find_files($dir, $pattern) { while (FALSE !== ($entry = readdir($dh))) { $path = $subdir . DIRECTORY_SEPARATOR . $entry; if ($entry{0} == '.') { - } elseif (is_dir($path)) { + } + elseif (is_dir($path)) { $todos[] = $path; } } @@ -175,7 +267,10 @@ function _coda_civix_civicrm_managed(&$entities) { $es = include $file; foreach ($es as $e) { if (empty($e['module'])) { - $e['module'] = 'org.project60.coda'; + $e['module'] = E::LONG_NAME; + } + if (empty($e['params']['version'])) { + $e['params']['version'] = '3'; } $entities[] = $e; } @@ -204,7 +299,7 @@ function _coda_civix_civicrm_caseTypes(&$caseTypes) { // throw new CRM_Core_Exception($errorMessage); } $caseTypes[$name] = array( - 'module' => 'org.project60.coda', + 'module' => E::LONG_NAME, 'name' => $name, 'file' => $file, ); @@ -230,7 +325,7 @@ function _coda_civix_civicrm_angularModules(&$angularModules) { $name = preg_replace(':\.ang\.php$:', '', basename($file)); $module = include $file; if (empty($module['ext'])) { - $module['ext'] = 'org.project60.coda'; + $module['ext'] = E::LONG_NAME; } $angularModules[$name] = $module; } @@ -257,8 +352,10 @@ function _coda_civix_glob($pattern) { * Inserts a navigation menu item at a given place in the hierarchy. * * @param array $menu - menu hierarchy - * @param string $path - path where insertion should happen (ie. Administer/System Settings) - * @param array $item - menu you need to insert (parent/child attributes will be filled for you) + * @param string $path - path to parent of this item, e.g. 'my_extension/submenu' + * 'Mailing', or 'Administer/System Settings' + * @param array $item - the item to insert (parent/child attributes will be + * filled for you) */ function _coda_civix_insert_navigation_menu(&$menu, $path, $item) { // If we are done going down the path, insert menu @@ -273,12 +370,14 @@ function _coda_civix_insert_navigation_menu(&$menu, $path, $item) { } else { // Find an recurse into the next level down - $found = false; + $found = FALSE; $path = explode('/', $path); $first = array_shift($path); foreach ($menu as $key => &$entry) { if ($entry['attributes']['name'] == $first) { - if (!$entry['child']) $entry['child'] = array(); + if (!isset($entry['child'])) { + $entry['child'] = array(); + } $found = _coda_civix_insert_navigation_menu($entry['child'], implode('/', $path), $item, $key); } } @@ -305,7 +404,7 @@ function _coda_civix_fixNavigationMenu(&$nodes) { if ($key === 'navID') { $maxNavID = max($maxNavID, $item); } - }); + }); _coda_civix_fixNavigationMenuItems($nodes, $maxNavID, NULL); } @@ -342,7 +441,20 @@ function _coda_civix_civicrm_alterSettingsFolders(&$metaDataFolders = NULL) { $configured = TRUE; $settingsDir = __DIR__ . DIRECTORY_SEPARATOR . 'settings'; - if(is_dir($settingsDir) && !in_array($settingsDir, $metaDataFolders)) { + if (is_dir($settingsDir) && !in_array($settingsDir, $metaDataFolders)) { $metaDataFolders[] = $settingsDir; } } + +/** + * (Delegated) Implements hook_civicrm_entityTypes(). + * + * Find any *.entityType.php files, merge their content, and return. + * + * @link http://wiki.civicrm.org/confluence/display/CRMDOC/hook_civicrm_entityTypes + */ + +function _coda_civix_civicrm_entityTypes(&$entityTypes) { + $entityTypes = array_merge($entityTypes, array ( + )); +} diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..0f9f25d --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,18 @@ + + + + + ./tests/phpunit + + + + + ./ + + + + + + + + diff --git a/tests/phpunit/api/v3/BankingAccountReference/ConvertnbanTest.php b/tests/phpunit/api/v3/BankingAccountReference/ConvertnbanTest.php new file mode 100644 index 0000000..6501b08 --- /dev/null +++ b/tests/phpunit/api/v3/BankingAccountReference/ConvertnbanTest.php @@ -0,0 +1,49 @@ +installMe(__DIR__) + ->apply(); + } + + /** + * The setup() method is executed before the test is executed (optional). + */ + public function setUp() { + parent::setUp(); + } + + /** + * The tearDown() method is executed after the test was executed (optional) + * This can be used for cleanup. + */ + public function tearDown() { + parent::tearDown(); + } + + /** + * Simple example test case. + * + * Note how the function name begins with the word "test". + */ + public function testApiExample() { + $result = civicrm_api3('BankingAccountReference', 'Convertnban', array('nban' => '000170326946', 'country' => 'BE')); + $this->assertEquals('BE33000170326946', $result['values']); + } + +} diff --git a/tests/phpunit/bootstrap.php b/tests/phpunit/bootstrap.php new file mode 100644 index 0000000..afa827e --- /dev/null +++ b/tests/phpunit/bootstrap.php @@ -0,0 +1,62 @@ +add('CRM_', __DIR__); +$loader->add('Civi\\', __DIR__); +$loader->add('api_', __DIR__); +$loader->add('api\\', __DIR__); +$loader->register(); + +/** + * Call the "cv" command. + * + * @param string $cmd + * The rest of the command to send. + * @param string $decode + * Ex: 'json' or 'phpcode'. + * @return string + * Response output (if the command executed normally). + * @throws \RuntimeException + * If the command terminates abnormally. + */ +function cv($cmd, $decode = 'json') { + $cmd = 'cv ' . $cmd; + $descriptorSpec = array(0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => STDERR); + $oldOutput = getenv('CV_OUTPUT'); + putenv("CV_OUTPUT=json"); + + // Execute `cv` in the original folder. This is a work-around for + // phpunit/codeception, which seem to manipulate PWD. + $cmd = sprintf('cd %s; %s', escapeshellarg(getenv('PWD')), $cmd); + + $process = proc_open($cmd, $descriptorSpec, $pipes, __DIR__); + putenv("CV_OUTPUT=$oldOutput"); + fclose($pipes[0]); + $result = stream_get_contents($pipes[1]); + fclose($pipes[1]); + if (proc_close($process) !== 0) { + throw new RuntimeException("Command failed ($cmd):\n$result"); + } + switch ($decode) { + case 'raw': + return $result; + + case 'phpcode': + // If the last output is /*PHPCODE*/, then we managed to complete execution. + if (substr(trim($result), 0, 12) !== "/*BEGINPHP*/" || substr(trim($result), -10) !== "/*ENDPHP*/") { + throw new \RuntimeException("Command failed ($cmd):\n$result"); + } + return $result; + + case 'json': + return json_decode($result, 1); + + default: + throw new RuntimeException("Bad decoder format ($decode)"); + } +}