Skip to content

Commit

Permalink
Add CurrencyConverter::convertToRational()
Browse files Browse the repository at this point in the history
  • Loading branch information
BenMorel committed Jan 9, 2020
1 parent e5ce928 commit 20acd28
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 3 deletions.
22 changes: 21 additions & 1 deletion src/CurrencyConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@

/**
* Converts monies into different currencies, using an exchange rate provider.
*
* @todo Now that this class provides methods to convert to both Money and RationalMoney, it makes little sense to
* provide the context in the constructor, as this only applies to convert() and not convertToRational().
* This should probably be a parameter to convert().
*/
final class CurrencyConverter
{
Expand All @@ -33,6 +37,7 @@ final class CurrencyConverter
/**
* @param ExchangeRateProvider $exchangeRateProvider The exchange rate provider.
* @param Context|null $context A context to create the monies in, or null to use the default.
* The context only applies to convert(), not convertToRational().
*/
public function __construct(ExchangeRateProvider $exchangeRateProvider, Context $context = null)
{
Expand All @@ -57,6 +62,21 @@ public function __construct(ExchangeRateProvider $exchangeRateProvider, Context
* @throws RoundingNecessaryException If rounding is necessary and RoundingMode::UNNECESSARY is used.
*/
public function convert(MoneyContainer $moneyContainer, $currency, int $roundingMode = RoundingMode::UNNECESSARY) : Money
{
return $this->convertToRational($moneyContainer, $currency)->to($this->context, $roundingMode);
}

/**
* Converts the given money to the given currency, and returns the result as a RationalMoney with no rounding.
*
* @param MoneyContainer $moneyContainer The Money, RationalMoney or MoneyBag to convert.
* @param Currency|string|int $currency The Currency instance, ISO currency code or ISO numeric currency code.
*
* @return RationalMoney
*
* @throws CurrencyConversionException If the exchange rate is not available.
*/
public function convertToRational(MoneyContainer $moneyContainer, $currency) : RationalMoney
{
if (! $currency instanceof Currency) {
$currency = Currency::of($currency);
Expand All @@ -75,6 +95,6 @@ public function convert(MoneyContainer $moneyContainer, $currency, int $rounding
$total = $total->plus($amount);
}

return Money::create($total, $currency, $this->context, $roundingMode);
return new RationalMoney($total, $currency);
}
}
41 changes: 39 additions & 2 deletions tests/CurrencyConverterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public function providerConvertMoney()
* @param string $currency The target currency code.
* @param Context $context The target context.
* @param int $roundingMode The rounding mode to use.
* @param string $total The expected total
* @param string $total The expected total.
*/
public function testConvertMoneyBag(array $monies, $currency, Context $context, $roundingMode, $total)
{
Expand All @@ -108,7 +108,7 @@ public function testConvertMoneyBag(array $monies, $currency, Context $context,
/**
* @return array
*/
public function providerConvertMoneyBag()
public function providerConvertMoneyBag() : array
{
return [
[[['354.40005', 'EUR'], ['3.1234', 'JPY']], 'USD', new DefaultContext(), RoundingMode::DOWN, 'USD 437.56'],
Expand All @@ -119,6 +119,43 @@ public function providerConvertMoneyBag()
];
}

/**
* @dataProvider providerConvertMoneyBagToRational
*
* @param array $monies The mixed monies to add.
* @param string $currency The target currency code.
* @param string $expectedTotal The expected total.
*/
public function testConvertMoneyBagToRational(array $monies, string $currency, string $expectedTotal) : void
{
$exchangeRateProvider = new ConfigurableProvider();
$exchangeRateProvider->setExchangeRate('EUR', 'USD', '1.123456789');
$exchangeRateProvider->setExchangeRate('JPY', 'USD', '0.0098765432123456789');

$moneyBag = new MoneyBag();

foreach ($monies as $money) {
$money = Money::of($money[0], $money[1], new AutoContext());
$moneyBag->add($money);
}

$currencyConverter = new CurrencyConverter($exchangeRateProvider);
$actualTotal = $currencyConverter->convertToRational($moneyBag, $currency)->simplified();

$this->assertRationalMoneyEquals($expectedTotal, $actualTotal);
}

/**
* @return array
*/
public function providerConvertMoneyBagToRational() : array
{
return [
[[['354.40005', 'EUR'], ['3.1234', 'JPY']], 'USD', 'USD 19909199529475444524673813/50000000000000000000000'],
[[['1234.56', 'EUR'], ['31562', 'JPY']], 'USD', 'USD 8493491351479471587209/5000000000000000000']
];
}

/**
* @dataProvider providerConvertRationalMoney
*
Expand Down

0 comments on commit 20acd28

Please sign in to comment.