Skip to content

Commit

Permalink
[Currency] Converter based on currency pairs instead of currency field
Browse files Browse the repository at this point in the history
  • Loading branch information
lchrusciel committed Nov 24, 2016
1 parent e972f2b commit 173a7b1
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 139 deletions.
36 changes: 1 addition & 35 deletions src/Sylius/Behat/Context/Setup/CurrencyContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,16 +118,6 @@ public function theStoreHasDisabledCurrency($currencyCode)
$this->saveCurrency($currency);
}

/**
* @Given the store has currency :currencyCode with exchange rate :exchangeRate
*/
public function theStoreHasCurrencyWithExchangeRate($currencyCode, $exchangeRate)
{
$currency = $this->createCurrency($currencyCode, (float) $exchangeRate);

$this->saveCurrency($currency);
}

/**
* @Given /^(that channel)(?: also|) allows to shop using the "([^"]+)" currency$/
* @Given /^(that channel)(?: also|) allows to shop using "([^"]+)" and "([^"]+)" currencies$/
Expand All @@ -142,28 +132,6 @@ public function thatChannelAllowsToShopUsingAndCurrencies(ChannelInterface $chan
$this->channelManager->flush();
}

/**
* @Given /^(that channel)(?: also|) allows to shop using the "([^"]+)" currency with exchange rate ([0-9\.]+)$/
*/
public function thatChannelAllowsToShopUsingCurrency(ChannelInterface $channel, $currencyCode, $exchangeRate = 1.0)
{
$currency = $this->createCurrency($currencyCode, $exchangeRate);
$channel->addCurrency($currency);
$this->saveCurrency($currency);

$this->channelManager->flush();
}

/**
* @Given /^the exchange rate for (currency "[^"]+") was changed to ([0-9\.]+)$/
* @Given /^the ("[^"]+" currency) has an exchange rate of ([0-9\.]+)$/
*/
public function theExchangeRateForWasChangedTo(CurrencyInterface $currency, $exchangeRate)
{
$currency->setExchangeRate($exchangeRate);
$this->saveCurrency($currency);
}

/**
* @param CurrencyInterface $currency
*/
Expand All @@ -175,16 +143,14 @@ private function saveCurrency(CurrencyInterface $currency)

/**
* @param $currencyCode
* @param float $exchangeRate
*
* @return CurrencyInterface
*/
private function createCurrency($currencyCode, $exchangeRate = 1.0)
private function createCurrency($currencyCode)
{
/** @var CurrencyInterface $currency */
$currency = $this->currencyFactory->createNew();
$currency->setCode($currencyCode);
$currency->setExchangeRate($exchangeRate);

return $currency;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ public function __construct(CurrencyConverterInterface $currencyConverter)
/**
* {@inheritdoc}
*/
public function convertAmount($amount, $sourceCurrencyCode)
public function convertAmount($amount, $sourceCurrencyCode, $targetCurrencyCode)
{
return $this->currencyConverter->convertFromBase($amount, $sourceCurrencyCode);
return $this->currencyConverter->convert($amount, $sourceCurrencyCode, $targetCurrencyCode);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@ interface ConvertMoneyHelperInterface
/**
* @param int $amount
* @param string|null $sourceCurrencyCode
* @param string|null $targetCurrencyCode
*
* @return string
*
* @throws \InvalidArgumentException
*/
public function convertAmount($amount, $sourceCurrencyCode);
public function convertAmount($amount, $sourceCurrencyCode, $targetCurrencyCode);
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ function it_is_a_convert_money_price_helper()
function it_converts_and_formats_money_using_default_locale_if_not_given(
CurrencyConverterInterface $currencyConverter
) {
$currencyConverter->convertFromBase(500, 'USD')->willReturn(250);
$currencyConverter->convert(500, 'USD', 'CAD')->willReturn(250);

$this->convertAmount(500, 'USD')->shouldReturn(250);
$this->convertAmount(500, 'USD', 'CAD')->shouldReturn(250);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
{% macro convertAndFormat(amount) %}
{% import _self as macro %}

{{ macro.format(amount|sylius_convert_money(shopperContext.currencyCode), shopperContext.currencyCode) }}
{{ macro.format(amount|sylius_convert_money(shopperContext.currencyCode), shopperContext.channel.currencyCode, shopperContext.currencyCode) }}
{% endmacro %}
52 changes: 20 additions & 32 deletions src/Sylius/Component/Currency/Converter/CurrencyConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,71 +11,59 @@

namespace Sylius\Component\Currency\Converter;

use Sylius\Component\Currency\Model\CurrencyInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
use Sylius\Component\Currency\Model\ExchangeRateInterface;
use Sylius\Component\Currency\Repository\ExchangeRateRepositoryInterface;

/**
* @author Paweł Jędrzejewski <pawel@sylius.org>
*/
class CurrencyConverter implements CurrencyConverterInterface
{
/**
* @var RepositoryInterface
* @var ExchangeRateRepositoryInterface
*/
protected $currencyRepository;
protected $exchangeRateRepository;

/**
* @var array
*/
private $cache;

/**
* @param RepositoryInterface $currencyRepository
* @param ExchangeRateRepositoryInterface $exchangeRateRepository
*/
public function __construct(RepositoryInterface $currencyRepository)
public function __construct(ExchangeRateRepositoryInterface $exchangeRateRepository)
{
$this->currencyRepository = $currencyRepository;
$this->exchangeRateRepository = $exchangeRateRepository;
}

/**
* {@inheritdoc}
*/
public function convertFromBase($amount, $targetCurrencyCode)
public function convert($amount, $sourceCurrencyCode, $targetCurrencyCode)
{
$currency = $this->getCurrency($targetCurrencyCode);
$exchangeRate = $this->getExchangeRate($sourceCurrencyCode, $targetCurrencyCode);

if (null === $currency) {
throw new UnavailableCurrencyException($targetCurrencyCode);
if (null === $exchangeRate) {
return $amount;
}

return (int) round($amount * $currency->getExchangeRate());
return (int) round($amount * $exchangeRate->getRatio());
}

/**
* {@inheritdoc}
*/
public function convertToBase($amount, $sourceCurrencyCode)
{
$currency = $this->getCurrency($sourceCurrencyCode);

if (null === $currency) {
throw new UnavailableCurrencyException($sourceCurrencyCode);
}

return (int) round($amount / $currency->getExchangeRate());
}

/**
* @param string $code
* @param string $sourceCode
* @param string $targetCode
*
* @return CurrencyInterface
* @return ExchangeRateInterface
*/
private function getCurrency($code)
private function getExchangeRate($sourceCode, $targetCode)
{
if (isset($this->cache[$code])) {
return $this->cache[$code];
$cacheIndex = $sourceCode . $targetCode;
if (isset($this->cache[$cacheIndex])) {
return $this->cache[$cacheIndex];
}

return $this->cache[$code] = $this->currencyRepository->findOneBy(['code' => $code]);
return $this->cache[$cacheIndex] = $this->exchangeRateRepository->findOneWithCurrencyPair($sourceCode, $targetCode);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,12 @@
*/
interface CurrencyConverterInterface
{
/**
* @param int $value
* @param string $targetCurrencyCode
*
* @return int
*
* @throws UnavailableCurrencyException
*/
public function convertFromBase($value, $targetCurrencyCode);

/**
* @param int $value
* @param string $sourceCurrencyCode
* @param string $targetCurrencyCode
*
* @return int
*
* @throws UnavailableCurrencyException
*/
public function convertToBase($value, $sourceCurrencyCode);
public function convert($value, $sourceCurrencyCode, $targetCurrencyCode);
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@
use PhpSpec\ObjectBehavior;
use Sylius\Component\Currency\Converter\CurrencyConverter;
use Sylius\Component\Currency\Converter\CurrencyConverterInterface;
use Sylius\Component\Currency\Converter\UnavailableCurrencyException;
use Sylius\Component\Currency\Model\CurrencyInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
use Sylius\Component\Currency\Model\ExchangeRateInterface;
use Sylius\Component\Currency\Repository\ExchangeRateRepositoryInterface;

/**
* @mixin CurrencyConverter
*
* @author Łukasz Chruściel <lchrusciel@gmail.com>
*/
final class CurrencyConverterSpec extends ObjectBehavior
{
function let(RepositoryInterface $currencyRepository)
function let(ExchangeRateRepositoryInterface $exchangeRateRepository)
{
$this->beConstructedWith($currencyRepository);
$this->beConstructedWith($exchangeRateRepository);
}

function it_is_initializable()
Expand All @@ -35,33 +39,21 @@ function it_implements_a_currency_converter_interface()
$this->shouldImplement(CurrencyConverterInterface::class);
}

function it_converts_to_any_currency(
RepositoryInterface $currencyRepository,
CurrencyInterface $currency
function it_converts_with_ratio_based_on_currency_pair_exchange_rate(
ExchangeRateRepositoryInterface $exchangeRateRepository,
ExchangeRateInterface $exchangeRate
) {
$currencyRepository->findOneBy(['code' => 'USD'])->willReturn($currency);
$currency->getExchangeRate()->willReturn(1.30);

$this->convertFromBase(6555, 'USD')->shouldReturn(8522);
}

function it_throws_exception_if_currency_is_not_found($currencyRepository)
{
$currencyRepository->findOneBy(['code' => 'EUR'])->willReturn(null);
$exchangeRateRepository->findOneWithCurrencyPair('GBP', 'USD')->willReturn($exchangeRate);
$exchangeRate->getRatio()->willReturn(1.30);

$this
->shouldThrow(new UnavailableCurrencyException('EUR'))
->duringConvertFromBase(6555, 'EUR')
;
$this->convert(666, 'GBP', 'USD')->shouldReturn(866);
}

function it_converts_to_base_currency(
RepositoryInterface $currencyRepository,
CurrencyInterface $currency
function it_return_given_value_if_exchange_rate_for_given_currency_pair_has_not_been_found(
ExchangeRateRepositoryInterface $exchangeRateRepository
) {
$currencyRepository->findOneBy(['code' => 'PLN'])->willReturn($currency);
$currency->getExchangeRate()->willReturn(0.25);
$exchangeRateRepository->findOneWithCurrencyPair('GBP', 'USD')->willReturn(null);

$this->convertToBase(10000, 'PLN')->shouldReturn(40000);
$this->convert(666, 'GBP', 'USD')->shouldReturn(666);
}
}

0 comments on commit 173a7b1

Please sign in to comment.