Skip to content

Commit

Permalink
First real commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ariselseng committed Feb 2, 2020
1 parent 8456d08 commit b4cc5f1
Show file tree
Hide file tree
Showing 6 changed files with 282 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
composer.phar
composer.lock
vendor
22 changes: 22 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "ariselseng/norwegianbanks",
"autoload": {
"psr-4": {
"Ariselseng\\NorwegianBanks\\": "src/"
}
},
"require": {
"phpoffice/phpspreadsheet": "^1.9",
"komakino/modulus11": "^1.0",
"desarrolla2/cache": "^3.0",
"guzzlehttp/guzzle": "^6.5"
},
"require-dev": {
"phpunit/phpunit": "4.*"
},
"autoload-dev": {
"psr-4": {
"Ariselseng\\NorwegianBanks\\Tests\\": "tests/"
}
}
}
19 changes: 19 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
bootstrap="vendor/autoload.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
verbose="true"
>
<testsuites>
<testsuite name="Package Test Suite">
<directory suffix=".php">./tests/</directory>
</testsuite>
</testsuites>
</phpunit>
21 changes: 21 additions & 0 deletions src/NorwegianBank.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

namespace Ariselseng\NorwegianBanks;


class NorwegianBank
{
public $bankCode;
public $bankName;
public $prefixes;

function __construct(string $bankCode, string $bankName, array $prefixes = [])
{
$this->bankCode = $bankCode;
$this->bankName = $bankName;
$this->prefixes = $prefixes;
}
public function addPrefix(string $prefix) {
$this->prefixes[] = $prefix;
}
}
139 changes: 139 additions & 0 deletions src/NorwegianBanks.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php

namespace Ariselseng\NorwegianBanks;

use Komakino\Modulus11\Modulus11;
use Desarrolla2\Cache\File as FileCache;

class NorwegianBanks
{
private const XlsFileUrl = 'https://www.finansnorge.no/contentassets/cc4fabf26cea4569aa447aa9ae671efa/norwegian-iban-bic-table.xls';
private const xlsFileTtl = 1440;

private $xlsFilePath;
private $banks;
private $prefixToBankCode;

public function __construct()
{
$this->xlsFilePath = sys_get_temp_dir() . '/.cache-norwegianbanks-norwegian-iban-bic-table.xls';
$this->processData();
}

private function downloadData()
{

$xlsFileExists = file_exists($this->xlsFilePath);
if ($xlsFileExists && filemtime($this->xlsFilePath) <= (time() - self::xlsFileTtl)) {
$headers = [
'If-Modified-Since' => gmdate('D, d M Y H:i:s T', filemtime($this->xlsFilePath)),
];
} else if (!$xlsFileExists) {
$headers = null;

} else {
return;
}

$response = (new \GuzzleHttp\Client())->get(self::XlsFileUrl, [
'headers' => $headers,
]);

if ($response->getStatusCode() === 200 && $response->getBody()->getSize() > 0) {
file_put_contents($this->xlsFilePath, $response->getBody()->getContents(), LOCK_EX);
}
}

private function processData()
{
$this->downloadData();
$cacheDir = sys_get_temp_dir() . '/phpcache-norwegianbanks-' . filemtime($this->xlsFilePath);
$hasCacheDir = file_exists($cacheDir);
if (!$hasCacheDir) {
$hasCacheDir = mkdir($cacheDir);
}

if ($hasCacheDir) {
$cache = new FileCache($cacheDir);
$banks = $cache->get('banks');
}

if (!$hasCacheDir || !isset($banks)) {
$banks = [];
$prefixToBankCode = [];
$reader = \PhpOffice\PhpSpreadsheet\IOFactory::createReader("Xls");
$reader->setReadDataOnly(true);

$spreadsheet = $reader->load($this->xlsFilePath);
$worksheet = $spreadsheet->getActiveSheet();
$rows = $worksheet->toArray(null, false, false, false);

for ($i = 0; $i < count($rows); $i++) {
if (is_null($rows[$i][1])) {
continue;
}
if (!isset($banks[$rows[$i][1]])) {
$banks[$rows[$i][1]] = new NorwegianBank($rows[$i][1], $rows[$i][2], [$rows[$i][0]]);
} else {
$banks[$rows[$i][1]]->addPrefix($rows[$i][0]);
}
$prefixToBankCode[$rows[$i][0]] = $rows[$i][1];
}

if ($hasCacheDir) {
$cache->set('banks', $banks, self::xlsFileTtl);
$cache->set('prefixToBankCode', $prefixToBankCode, self::xlsFileTtl);
}

$this->banks = $banks;
$this->prefixToBankCode = $prefixToBankCode;
} else {
$this->banks = $banks;
$this->prefixToBankCode = $cache->get('prefixToBankCode');
}
}
public function getBankCodeByPrefix(string $prefix)
{

if (!isset($this->prefixToBankCode[$prefix])) {
return null;
}
return $this->prefixToBankCode[$prefix];
}

public function getBankByAccountNumber(string $account)
{
$prefix = substr($account, 0, 4);
$bankCode = $this->getBankCodeByPrefix($prefix);
if (is_null($bankCode)) {
return null;
}
return $this->banks[$this->getBankCodeByPrefix($prefix)];
}

public function getFormattedAccountNumber(string $unformattedAccount, string $delimiter = '.')
{
$onlyDigits = preg_replace('/[^0-9]/', '', $unformattedAccount);
return substr($onlyDigits, 0, 4) . $delimiter . substr($onlyDigits, 4, 2) . $delimiter . substr($onlyDigits, 6);
}

public function validateAccountNumber(string $account)
{
$mod11 = Modulus11::validate($account);

if (!$mod11) {
return false;
}

return !is_null($this->getBankByAccountNumber(substr($account, 0, 4)));
}
}

class NorwegianBanksStatic
{
public static function __callStatic($method, $args)
{
$obj = new NorwegianBanks();
return $obj->$method(...$args);
}
}
78 changes: 78 additions & 0 deletions tests/NorwegianBanksTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

namespace Ariselseng\NorwegianBanks\Tests;

use Ariselseng\NorwegianBanks\NorwegianBanks;
use Ariselseng\NorwegianBanks\NorwegianBanksStatic;

class NorwegianBanksTest extends \PHPUnit_Framework_TestCase
{
protected $accounts = [
[
'bankCode' => 'DNBANOKK',
'number' => '1594 22 87248'
],
[
'bankCode' => 'NDEANOKK',
'number' => '61050659274'
],
[
'bankCode' => 'SPSONO22',
'number' => '3000.27.79419'
],
];
protected $notRealAccountNumber = '1234.56.78903';
protected $notRealAccountNumberWithSpaces = '1234 56 78903';
protected $notRealAccountNumberUnformatted = '12345678903';

private $norwegianBanks;

public function __construct()
{
$this->norwegianBanks = new NorwegianBanks();
}

public function testGetFormattedAccountNumber()
{
$this->assertEquals($this->notRealAccountNumber, $this->norwegianBanks->getFormattedAccountNumber($this->notRealAccountNumberUnformatted));
$this->assertEquals($this->notRealAccountNumber, NorwegianBanksStatic::getFormattedAccountNumber($this->notRealAccountNumberUnformatted));
$this->assertEquals($this->notRealAccountNumberWithSpaces, $this->norwegianBanks->getFormattedAccountNumber($this->notRealAccountNumberUnformatted, ' '));
$this->assertEquals($this->notRealAccountNumberWithSpaces, NorwegianBanksStatic::getFormattedAccountNumber($this->notRealAccountNumberUnformatted, ' '));
}

public function testGetBankCodeByPrefix()
{
foreach ($this->accounts as $account) {
$this->assertEquals($account['bankCode'], $this->norwegianBanks->getBankCodeByPrefix(substr($account['number'], 0, 4)));
$this->assertEquals($account['bankCode'], NorwegianBanksStatic::getBankCodeByPrefix(substr($account['number'], 0, 4)));
}
$this->assertEquals(null, $this->norwegianBanks->getBankCodeByPrefix('0000'));
$this->assertEquals(null, NorwegianBanksStatic::getBankCodeByPrefix('0000'));
}

public function testGetBankByAccountNumber()
{

foreach ($this->accounts as $account) {
$this->assertAttributeEquals($account['bankCode'], 'bankCode', $this->norwegianBanks->getBankByAccountNumber($account['number']));
$this->assertAttributeEquals($account['bankCode'], 'bankCode', NorwegianBanksStatic::getBankByAccountNumber($account['number']));
}

$this->assertEquals(null, $this->norwegianBanks->getBankByAccountNumber($this->notRealAccountNumber));
$this->assertEquals(null, NorwegianBanksStatic::getBankByAccountNumber($this->notRealAccountNumber));
}

public function testValidate()
{

foreach ($this->accounts as $account) {
$this->assertTrue($this->norwegianBanks->validateAccountNumber($account['number']));
$this->assertTrue(NorwegianBanksStatic::validateAccountNumber($account['number']));

}

$this->assertFalse($this->norwegianBanks->validateAccountNumber($this->notRealAccountNumber));
$this->assertFalse(NorwegianBanksStatic::validateAccountNumber($this->notRealAccountNumber));

}
}

0 comments on commit b4cc5f1

Please # to comment.