Skip to content

Instantly share code, notes, and snippets.

@cometofsky
Last active December 9, 2024 16:11
Show Gist options
  • Save cometofsky/80a7b004abd3ab092bc07fef8167f600 to your computer and use it in GitHub Desktop.
Save cometofsky/80a7b004abd3ab092bc07fef8167f600 to your computer and use it in GitHub Desktop.
<?php
declare(strict_types=1);
namespace Rafi\Commission;
use Rafi\CurrencyExchangeRate\FetchContent;
class AmountCurrencyAware
{
private $fetchContent;
const FIXED_CURRENCY = 'EUR';
public function __construct(FetchContent $fetchContent)
{
$this->fetchContent = $fetchContent;
}
public function getAmountByCurrency($currency, $amount)
{
if ($currency == self::FIXED_CURRENCY) {
return $amount;
}
$rate = $this->fetchContent->getContents()[$currency];
if ($rate == 0) {
return $amount;
}
if ($rate > 0) {
return ($amount / $rate);
}
}
}
<?php
declare(strict_types=1);
$loader = require __DIR__ . "/vendor/autoload.php";
$config = require __DIR__ . "/config.php";
use GuzzleHttp\Client;
use Rafi\BankIDProvider\BINApi;
use Rafi\BankIDProvider\FetchBIN;
use Rafi\Commission\AmountCurrencyAware;
use Rafi\Commission\CalculateCommission;
use Rafi\CurrencyExchangeRate\CurrencyExchangeRate;
use Rafi\CurrencyExchangeRate\FetchExchangeRate;
use Rafi\PaymentTransaction\TransactionAPI;
use Rafi\PaymentTransaction\TransactionData;
$fetchExchangeRate = new FetchExchangeRate($config['uriExchangeRateIO']);
$fetchContent = new CurrencyExchangeRate($fetchExchangeRate);
$client = new Client();
$binApi = new BINApi($client, $config['uriBINLookup']);
$binProvider = new FetchBIN($binApi);
$currencyAwareAmount = new AmountCurrencyAware($fetchContent);
$commission = new CalculateCommission($binProvider, $currencyAwareAmount);
$transactionAPI = new TransactionAPI();
$transactions = new TransactionData($transactionAPI);
foreach($transactions->getData($argv[1]) as $trans) {
print $commission->getCommission(
$trans['currency'],
$trans['amount'],
$trans['bin'],
$config['euCountries']
) . "\n";
}
<?php
declare(strict_types=1);
namespace Rafi\BankIDProvider;
use GuzzleHttp\Client;
class BINApi
{
private $apiKey;
private $client;
public function __construct(Client $client, string $apiKey)
{
$this->apiKey = $apiKey;
$this->client = $client;
}
public function logIn()
{
/** Implement Login if required **/
}
public function getDataByBIN($bin)
{
try {
return $this->client->get($this->apiKey . $bin)->getBody()->getContents();
} catch (\Exception $e) {
echo $e->getMessage();
}
}
}
<?php
declare(strict_types=1);
namespace Rafi\BankIDProvider;
class BINLookup implements BINProvider
{
public function getDetails(string $uri)
{
try {
return file_get_contents($uri);
} catch (\Exception $e) {
echo $e->getMessage();
}
}
}
<?php
declare(strict_types=1);
namespace Rafi\BankIDProvider;
interface BINProvider
{
public function getDetails(string $uri);
}
<?php
declare(strict_types=1);
namespace Rafi\Commission;
use Rafi\BankIDProvider\BINProvider;
class CalculateCommission
{
private $binProvider;
private $currencyAwareAmount;
const COMMISSION_RATE_EU = 0.01;
const COMMISSION_RATE_NON_EU = 0.02;
public function __construct(
BINProvider $binProvider,
AmountCurrencyAware $currencyAwareAmount
)
{
$this->binProvider = $binProvider;
$this->currencyAwareAmount = $currencyAwareAmount;
}
public function getCommission($currency, $amount, $bin, $euCountries): float
{
try {
$amount = $this->currencyAwareAmount->getAmountByCurrency($currency, $amount);
$card = $this->binProvider->getDetails($bin);
$rate = in_array($card['country']['alpha2'], $euCountries) ? self::COMMISSION_RATE_EU : self::COMMISSION_RATE_NON_EU;
$commission = $amount * $rate;
return round($commission, 2);
} catch (\Exception $e) {
echo $e->getMessage();
}
}
}
<?php
declare(strict_types=1);
namespace Rafi\Tests;
use PHPUnit\Framework\TestCase;
use Rafi\Commission\CalculateCommission;
class CalculateCommissionTest extends TestCase
{
/**
* @var \PHPUnit\Framework\MockObject
*/
private $commission;
public function setUp(): void
{
$this->commission = $this->createMock(CalculateCommission::class);
}
public function dummyData()
{
return [
['USD', 50.00, '516793', ['LT']],
['EUR', 100.00, '45717360', ['DK']],
];
}
/**
* @dataProvider dummyData
*/
public function testCommissionReturnsFloat($currency, $amount, $bin, $euCountries)
{
$this->assertIsFloat($this->commission->getCommission($currency, $amount, $bin, $euCountries));
}
/**
* @dataProvider dummyData
*/
public function testCommissionValue($currency, $amount, $bin, $euCountries)
{
$this->commission->expects($this->exactly(1))
->method('getCommission')
->with(
$currency,
$amount,
$bin,
$euCountries
);
$this->commission->getCommission($currency, $amount, $bin, $euCountries);
}
}
<?php
return [
'uriExchangeRateIO' => 'https://api.exchangeratesapi.io/latest',
'uriBINLookup' => 'https://lookup.binlist.net/',
'euCountries' => [
'AT', 'BE', 'BG', 'CY', 'CZ', 'DE', 'DK', 'EE', 'ES', 'FI', 'FR', 'GR', 'HR', 'HU', 'IE', 'IT', 'LT', 'LU', 'LV', 'MT', 'NL', 'PO', 'PT', 'RO', 'SE', 'SI', 'SK',
],
];
<?php
declare(strict_types=1);
namespace Rafi\CurrencyExchangeRate;
class CurrencyExchangeRate implements FetchContent
{
private $fetchExchangeRate;
private $contents = null;
public function __construct(FetchExchangeRate $fetchExchangeRate)
{
$this->fetchExchangeRate = $fetchExchangeRate;
}
public function getContents()
{
try {
if ($this->contents === null) {
$this->contents = json_decode($this->fetchExchangeRate->getContents(), true);
}
return $this->contents['rates'];
} catch (\Exception $e) {
echo $e->getMessage();
}
}
}
<?php
declare(strict_types=1);
namespace Rafi\BankIDProvider;
class FetchBIN implements BINProvider
{
private $binApi;
public function __construct(BINApi $binApi)
{
$this->binApi = $binApi;
}
public function getDetails(string $bin)
{
try {
return json_decode($this->binApi->getDataByBIN($bin), true);
} catch (\Exception $e) {
echo $e->getMessage();
}
}
}
<?php
declare(strict_types=1);
namespace Rafi\CurrencyExchangeRate;
interface FetchContent
{
public function getContents();
}
<?php
declare(strict_types=1);
namespace Rafi\CurrencyExchangeRate;
class FetchExchangeRate implements FetchContent
{
private $uri;
public function __construct(string $uri)
{
$this->uri = $uri;
}
public function getContents()
{
try {
return file_get_contents($this->uri);
} catch (\Exception $e) {
echo $e->getMessage();
}
}
}
{"bin":"45717360","amount":"100.00","currency":"EUR"}
{"bin":"516793","amount":"50.00","currency":"USD"}
{"bin":"45417360","amount":"10000.00","currency":"JPY"}
{"bin":"41417360","amount":"130.00","currency":"USD"}
{"bin":"4745030","amount":"2000.00","currency":"GBP"}
<?php
declare(strict_types=1);
namespace Rafi\PaymentTransaction;
interface Transaction
{
public function getData(string $file);
}
<?php
declare(strict_types=1);
namespace Rafi\PaymentTransaction;
class TransactionAPI
{
public function getDataFromFile(string $file)
{
try {
$lines = [];
$handle = fopen($file, 'r');
while ($line = fgets($handle)) {
array_push($lines, $line);
}
fclose($handle);
return $lines;
} catch (\Exception $e) {
echo $e->getMessage();
}
}
}
<?php
declare(strict_types=1);
namespace Rafi\PaymentTransaction;
class TransactionData implements Transaction
{
private $transactionApi;
public function __construct(TransactionAPI $transactionApi)
{
$this->transactionApi = $transactionApi;
}
public function getData(string $file): array
{
try {
$transactions = [];
$lines = $this->transactionApi->getDataFromFile($file);
foreach($lines as $line) {
array_push($transactions, json_decode($line, true));
}
return $transactions;
} catch (\Exception $e) {
echo $e->getMessage();
}
}
}
<?php
declare(strict_types=1);
namespace Rafi\PaymentTransaction;
class TransactionFromFile implements Transaction
{
public function getData(string $file)
{
try {
return explode("\n", file_get_contents($file));
} catch (\Exception $e) {
echo $e->getMessage();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment