Review fixes of exchange rate

This commit is contained in:
Jan Goralski 2016-11-21 16:31:09 +01:00
parent fd29900232
commit 17149b081b
19 changed files with 180 additions and 86 deletions

View file

@ -1,12 +1,12 @@
@managing_exchange_rates
Feature: Adding a new exchange rate
In order for the customer to view my goods in different prices according to currency
In order to specify exchange rates between different currencies in my store
As an Administrator
I want to add a new exchange rate to the store
Background:
Given I am logged in as an administrator
And the store has currency "US Dollar", "British Pound"
Given the store has currency "US Dollar" and "British Pound"
And I am logged in as an administrator
@ui
Scenario: Adding a new exchange rate
@ -16,4 +16,4 @@ Feature: Adding a new exchange rate
And I choose "British Pound" as the counter currency
And I add it
Then I should be notified that it has been successfully created
And the exchange rate between "US Dollar" and "British Pound" should appear in the store
And the exchange rate with ratio 1.20 between "US Dollar" and "British Pound" should appear in the store

View file

@ -5,14 +5,13 @@ Feature: Browsing exchange rates
I want to browse exchange rates
Background:
Given the store has currency "Euro", "British Pound"
And the store has currency "Bhutanese Ngultrum"
Given the store has currency "Euro", "British Pound" and "Bhutanese Ngultrum"
And the store has an exchange rate 1.2 with base currency "Euro" and counter currency "British Pound"
And the store also has an exchange rate 2.37 with base currency "British Pound" and counter currency "Bhutanese Ngultrum"
And I am logged in as an administrator
@ui
Scenario: Browsing store's exchange rates
When I want to browse exchange rates of the store
When I am browsing exchange rates of the store
Then I should see 2 exchange rates on the list
And I should see an exchange rate between "British Pound" and "Bhutanese Ngultrum" on the list

View file

@ -5,7 +5,7 @@ Feature: Deleting exchange rates
I want to be able to delete an exchange rate
Background:
Given the store has currency "US Dollar", "British Pound"
Given the store has currency "US Dollar", "British Pound" and "Bhutanese Ngultrum"
And I am logged in as an administrator
@ui
@ -14,10 +14,3 @@ Feature: Deleting exchange rates
When I delete the exchange rate between "US Dollar" and "British Pound"
Then I should be notified that it has been successfully deleted
And this exchange rate should no longer be on the list
@ui
Scenario: Deleting a currency deletes related exchange rates
Given the store has an exchange rate 1.2 with base currency "US Dollar" and counter currency "British Pound"
And the store has an exchange rate 0.8 with base currency "British Pound" and counter currency "US Dollar"
When the currency "US Dollar" gets deleted
Then there should be no exchange rates on the list

View file

@ -5,13 +5,13 @@ Feature: Editing exchange rate
I want to be able to edit an exchange rate
Background:
Given the store has currency "US Dollar", "British Pound"
Given the store has currency "US Dollar" and "British Pound"
And I am logged in as an administrator
@ui
Scenario: Change exchange rate's ratio
Given the store has an exchange rate 1.30 with base currency "US Dollar" and counter currency "British Pound"
And I want to edit this exchange rate
And I am editing this exchange rate
When I change ratio to 3.21
And I save my changes
Then I should be notified that it has been successfully edited
@ -20,6 +20,6 @@ Feature: Editing exchange rate
@ui
Scenario: Being unable to change currencies
Given the store has an exchange rate 1.30 with base currency "US Dollar" and counter currency "British Pound"
When I am editing this exchange rate
When I want to edit this exchange rate
Then I should see that the base currency is disabled
And I should see that the counter currency is disabled

View file

@ -5,7 +5,7 @@ Feature: Exchange rate validation
I want to be prevented from adding exchange rates without specifying required fields
Background:
Given the store has currency "US Dollar", "British Pound"
Given the store has currency "US Dollar" and "British Pound"
And I am logged in as an administrator
@ui

View file

@ -5,13 +5,13 @@ Feature: Inability of adding exchange rates with the same currency pair
I want to be prevented from adding an exchange rate with same base-counter currency pair
Background:
Given the store has currency "Euro", "British Pound"
Given the store has currency "Euro" and "British Pound"
And the store has an exchange rate 1.2 with base currency "Euro" and counter currency "British Pound"
And I am logged in as an administrator
@ui
Scenario: Being prevented from adding an exchange rate for the same currency pair
Given the store has an exchange rate 1.2 with base currency "Euro" and counter currency "British Pound"
And I want to add a new exchange rate
Given I want to add a new exchange rate
When I specify its ratio as 3.20
And I choose "Euro" as the base currency
And I choose "British Pound" as the counter currency
@ -19,3 +19,14 @@ Feature: Inability of adding exchange rates with the same currency pair
Then I should be notified that the currency pair must be unique
And I should still see one exchange rate on the list
And this exchange rate should have a ratio of 1.2
@ui
Scenario: Being prevented from adding an exchange rate for a reversed currency pair
Given I want to add a new exchange rate
When I specify its ratio as 3.20
And I choose "British Pound" as the base currency
And I choose "Euro" as the counter currency
And I try to add it
Then I should be notified that the currency pair must be unique
And I should still see one exchange rate on the list
And this exchange rate should have a ratio of 1.2

View file

@ -93,11 +93,17 @@ final class CurrencyContext implements Context
/**
* @Given the store has currency :currencyCode, :secondCurrencyCode
* @Given the store has currency :currencyCode and :secondCurrencyCode
* @Given the store has currency :currencyCode, :secondCurrencyCode and :thirdCurrencyCode
*/
public function theStoreHasCurrencyAnd($currencyCode, $secondCurrencyCode)
public function theStoreHasCurrencyAnd($currencyCode, $secondCurrencyCode, $thirdCurrencyCode = null)
{
$this->saveCurrency($this->createCurrency($currencyCode));
$this->saveCurrency($this->createCurrency($secondCurrencyCode));
if (null !== $thirdCurrencyCode) {
$this->saveCurrency($this->createCurrency($thirdCurrencyCode));
}
}
/**
@ -165,14 +171,6 @@ final class CurrencyContext implements Context
$this->saveCurrency($currency);
}
/**
* @When /^the (currency "[^"]+") gets deleted$/
*/
public function theCurrencyGetsDeleted(CurrencyInterface $currency)
{
$this->currencyRepository->remove($currency);
}
/**
* @param CurrencyInterface $currency
*/

View file

@ -61,8 +61,8 @@ final class CurrencyContext implements Context
/**
* @Transform :currencyCode
* @Transform :firstCurrencyCode
* @Transform :secondCurrencyCode
* @Transform :thirdCurrencyCode
*/
public function getCurrencyCodeByName($currencyName)
{

View file

@ -71,7 +71,7 @@ final class ManagingExchangeRatesContext implements Context
}
/**
* @When I want to browse exchange rates of the store
* @When I am browsing exchange rates of the store
*/
public function iWantToBrowseExchangeRatesOfTheStore()
{
@ -84,9 +84,7 @@ final class ManagingExchangeRatesContext implements Context
*/
public function iSpecifyItsRatioAs($ratio = null)
{
if (null !== $ratio) {
$this->createPage->specifyRatio($ratio);
}
$this->createPage->specifyRatio($ratio);
}
/**
@ -162,13 +160,13 @@ final class ManagingExchangeRatesContext implements Context
}
/**
* @Then the exchange rate between :baseCurrency and :counterCurrency should appear in the store
* @Then the exchange rate with ratio :ratio between :baseCurrency and :counterCurrency should appear in the store
*/
public function theExchangeRateBetweenAndShouldAppearInTheStore($baseCurrency, $counterCurrency)
public function theExchangeRateBetweenAndShouldAppearInTheStore($ratio, $baseCurrency, $counterCurrency)
{
$this->indexPage->open();
$this->assertExchangeRateIsOnList($baseCurrency, $counterCurrency);
$this->assertExchangeRateWithRatioIsOnTheList($ratio, $baseCurrency, $counterCurrency);
}
/**
@ -222,19 +220,7 @@ final class ManagingExchangeRatesContext implements Context
$baseCurrencyName = $exchangeRate->getBaseCurrency()->getName();
$counterCurrencyName = $exchangeRate->getCounterCurrency()->getName();
Assert::true(
$this->indexPage->isSingleResourceOnPage([
'ratio' => $ratio,
'baseCurrency' => $baseCurrencyName,
'counterCurrency' => $counterCurrencyName,
]),
sprintf(
'An exchange rate between %s and %s with a ratio of %s has not been found on the list.',
$baseCurrencyName,
$counterCurrencyName,
$ratio
)
);
$this->assertExchangeRateWithRatioIsOnTheList($ratio, $baseCurrencyName, $counterCurrencyName);
}
/**
@ -264,7 +250,10 @@ final class ManagingExchangeRatesContext implements Context
*/
public function iShouldBeNotifiedThatIsRequired($element)
{
Assert::same($this->createPage->getValidationMessage($element), sprintf('Please enter exchange rate %s.', $element));
Assert::same(
$this->createPage->getValidationMessage($element),
sprintf('Please enter exchange rate %s.', $element)
);
}
/**
@ -306,7 +295,7 @@ final class ManagingExchangeRatesContext implements Context
Assert::true(
$this->indexPage->isSingleResourceOnPage([
'baseCurrency' => $baseCurrencyName,
'counterCurrency' => $counterCurrencyName
'counterCurrency' => $counterCurrencyName,
]),
sprintf(
'An exchange rate with base currency %s and counter currency %s was not found on the list.',
@ -316,6 +305,30 @@ final class ManagingExchangeRatesContext implements Context
);
}
/**
* @param float $ratio
* @param string $baseCurrencyName
* @param string $counterCurrencyName
*
* @throws \InvalidArgumentException
*/
private function assertExchangeRateWithRatioIsOnTheList($ratio, $baseCurrencyName, $counterCurrencyName)
{
Assert::true(
$this->indexPage->isSingleResourceOnPage([
'ratio' => $ratio,
'baseCurrency' => $baseCurrencyName,
'counterCurrency' => $counterCurrencyName,
]),
sprintf(
'An exchange rate between %s and %s with a ratio of %s has not been found on the list.',
$baseCurrencyName,
$counterCurrencyName,
$ratio
)
);
}
/**
* @param string $baseCurrencyName
* @param string $counterCurrencyName

View file

@ -6,11 +6,11 @@ sylius_grid:
options:
class: "%sylius.model.exchange_rate.class%"
sorting:
ratio: desc
id: desc
fields:
ratio:
id:
type: string
label: sylius.ui.ratio
enabled: false
sortable: ~
baseCurrency:
type: twig
@ -24,10 +24,10 @@ sylius_grid:
path: .
options:
template: "@SyliusAdmin/ExchangeRate/Grid/Field/counterCurrencyName.html.twig"
filters:
ratio:
type: string
label: sylius.ui.ratio
sortable: ~
actions:
main:
create:

View file

@ -11,6 +11,7 @@
namespace Sylius\Bundle\CurrencyBundle\DependencyInjection;
use Sylius\Bundle\CurrencyBundle\Doctrine\ORM\ExchangeRateRepository;
use Sylius\Bundle\CurrencyBundle\Form\Type\CurrencyType;
use Sylius\Bundle\CurrencyBundle\Form\Type\ExchangeRateType;
use Sylius\Bundle\ResourceBundle\Controller\ResourceController;
@ -40,7 +41,7 @@ final class Configuration implements ConfigurationInterface
$rootNode
->children()
->scalarNode('driver')->defaultValue(SyliusResourceBundle::DRIVER_DOCTRINE_ORM)->end()
->scalarNode('driver')->defaultValue(SyliusResourceBundle::DRIVER_DOCTRINE_ORM)->cannotBeEmpty()->end()
->scalarNode('currency')->defaultValue('USD')->cannotBeEmpty()->end()
->end()
;
@ -71,7 +72,7 @@ final class Configuration implements ConfigurationInterface
->scalarNode('interface')->defaultValue(CurrencyInterface::class)->cannotBeEmpty()->end()
->scalarNode('controller')->defaultValue(ResourceController::class)->cannotBeEmpty()->end()
->scalarNode('repository')->cannotBeEmpty()->end()
->scalarNode('factory')->defaultValue(Factory::class)->end()
->scalarNode('factory')->defaultValue(Factory::class)->cannotBeEmpty()->end()
->arrayNode('form')
->addDefaultsIfNotSet()
->children()
@ -102,8 +103,8 @@ final class Configuration implements ConfigurationInterface
->scalarNode('model')->defaultValue(ExchangeRate::class)->cannotBeEmpty()->end()
->scalarNode('interface')->defaultValue(ExchangeRateInterface::class)->cannotBeEmpty()->end()
->scalarNode('controller')->defaultValue(ResourceController::class)->cannotBeEmpty()->end()
->scalarNode('repository')->cannotBeEmpty()->end()
->scalarNode('factory')->defaultValue(Factory::class)->end()
->scalarNode('repository')->defaultValue(ExchangeRateRepository::class)->cannotBeEmpty()->end()
->scalarNode('factory')->defaultValue(Factory::class)->cannotBeEmpty()->end()
->arrayNode('form')
->addDefaultsIfNotSet()
->children()

View file

@ -0,0 +1,52 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Bundle\CurrencyBundle\Doctrine\ORM;
use Doctrine\ORM\NonUniqueResultException;
use Sylius\Bundle\ResourceBundle\Doctrine\ORM\EntityRepository;
use Sylius\Component\Currency\Model\CurrencyInterface;
use Sylius\Component\Currency\Model\ExchangeRateInterface;
use Sylius\Component\Currency\Repository\ExchangeRateRepositoryInterface;
/**
* @author Jan Góralski <jan.goralski@lakion.com>
*/
class ExchangeRateRepository extends EntityRepository implements ExchangeRateRepositoryInterface
{
/**
* @param CurrencyInterface $firstCurrency
* @param CurrencyInterface $secondCurrency
*
* @return ExchangeRateInterface|null
*
* @throws NonUniqueResultException
*/
public function findOneWithCurrencyPair(CurrencyInterface $firstCurrency, CurrencyInterface $secondCurrency)
{
$queryBuilder = $this->createQueryBuilder('o');
return $queryBuilder
->where(
$queryBuilder->expr()->andX(
$queryBuilder->expr()->eq('o.baseCurrency', $firstCurrency->getId()),
$queryBuilder->expr()->eq('o.counterCurrency', $secondCurrency->getId())
))
->orWhere(
$queryBuilder->expr()->andX(
$queryBuilder->expr()->eq('o.baseCurrency', $secondCurrency->getId()),
$queryBuilder->expr()->eq('o.counterCurrency', $firstCurrency->getId())
))
->getQuery()
->getOneOrNullResult()
;
}
}

View file

@ -45,9 +45,7 @@ class ExchangeRateType extends AbstractResourceType
$exchangeRate = $event->getData();
$form = $event->getForm();
$disabled = null !== $exchangeRate->getBaseCurrency() &&
null !== $exchangeRate->getCounterCurrency()
;
$disabled = null !== $exchangeRate->getBaseCurrency() && null !== $exchangeRate->getCounterCurrency();
$form
->add('baseCurrency', 'sylius_currency_choice', [

View file

@ -13,6 +13,10 @@
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<mapped-superclass name="Sylius\Component\Currency\Model\ExchangeRate" table="sylius_exchange_rate">
<unique-constraints>
<unique-constraint columns="base_currency,counter_currency"/>
</unique-constraints>
<id name="id" column="id" type="integer">
<generator strategy="AUTO" />
</id>

View file

@ -9,8 +9,8 @@ Sylius\Component\Currency\Model\ExchangeRate:
ratio:
expose: true
type: float
virtual_properties:
getFromCurrency:
serialized_name: base_currency
getToCurrency:
serialized_name: counter_currency
baseCurrency:
expose: true
counterCurrency:
expose: true

View file

@ -13,7 +13,7 @@ namespace Sylius\Bundle\CurrencyBundle\Validator\Constraints;
use Sylius\Component\Currency\Model\CurrencyInterface;
use Sylius\Component\Currency\Model\ExchangeRateInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
use Sylius\Component\Currency\Repository\ExchangeRateRepositoryInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Exception\UnexpectedTypeException;
@ -24,14 +24,14 @@ use Symfony\Component\Validator\Exception\UnexpectedTypeException;
class UniqueCurrencyPairValidator extends ConstraintValidator
{
/**
* @var RepositoryInterface
* @var ExchangeRateRepositoryInterface
*/
private $exchangeRateRepository;
/**
* @param RepositoryInterface $exchangeRateRepository
* @param ExchangeRateRepositoryInterface $exchangeRateRepository
*/
public function __construct(RepositoryInterface $exchangeRateRepository)
public function __construct(ExchangeRateRepositoryInterface $exchangeRateRepository)
{
$this->exchangeRateRepository = $exchangeRateRepository;
}
@ -62,11 +62,8 @@ class UniqueCurrencyPairValidator extends ConstraintValidator
*/
private function isCurrencyPairUnique(CurrencyInterface $baseCurrency, CurrencyInterface $counterCurrency)
{
$exchangeRate = $this->exchangeRateRepository->findBy([
'baseCurrency' => $baseCurrency,
'counterCurrency' => $counterCurrency,
]);
$exchangeRate = $this->exchangeRateRepository->findOneWithCurrencyPair($baseCurrency, $counterCurrency);
return [] === $exchangeRate;
return null === $exchangeRate;
}
}

View file

@ -11,6 +11,8 @@
namespace Sylius\Component\Currency\Model;
use Webmozart\Assert\Assert;
/**
* @author Jan Góralski <jan.goralski@lakion.com>
*/
@ -59,13 +61,9 @@ class ExchangeRate implements ExchangeRateInterface
*/
public function setRatio($ratio)
{
if (is_float($ratio)) {
$this->ratio = $ratio;
Assert::float($ratio);
return;
}
throw new \InvalidArgumentException('The ratio must be a float.');
$this->ratio = $ratio;
}
/**

View file

@ -0,0 +1,30 @@
<?php
/*
* This file is part of the Sylius package.
*
* (c) Paweł Jędrzejewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Sylius\Component\Currency\Repository;
use Sylius\Component\Currency\Model\CurrencyInterface;
use Sylius\Component\Currency\Model\ExchangeRateInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
/**
* @author Jan Góralski <jan.goralski@lakion.com>
*/
interface ExchangeRateRepositoryInterface extends RepositoryInterface
{
/**
* @param CurrencyInterface $firstCurrency
* @param CurrencyInterface $secondCurrency
*
* @return ExchangeRateInterface|null
*/
public function findOneWithCurrencyPair(CurrencyInterface $firstCurrency, CurrencyInterface $secondCurrency);
}

View file

@ -31,7 +31,7 @@ final class ExchangeRateSpec extends ObjectBehavior
$this->shouldImplement(ExchangeRateInterface::class);
}
function it_throws_invalid_argument_exception_when_adding_non_float_ratio()
function it_throws_an_invalid_argument_exception_when_adding_non_float_ratio()
{
$this->shouldThrow(\InvalidArgumentException::class)->during('setRatio', ['1.01']);
$this->shouldThrow(\InvalidArgumentException::class)->during('setRatio', ['asd']);