Switch currency

This commit is contained in:
umpirsky 2013-06-05 19:52:08 +02:00
parent cc32af55b6
commit 21472d7e00
14 changed files with 169 additions and 15 deletions

View file

@ -0,0 +1,38 @@
Feature: Currencies
In order to buy products paying in different currencies
As a visitor or as a logged in user
I need to be able to switch between multiple currencies
Background:
Given there are following taxonomies defined:
| name |
| Category |
And taxonomy "Category" has following taxons:
| Clothing > PHP T-Shirts |
And the following products exist:
| name | price | taxons |
| PHP Top | 5.99 | PHP T-Shirts |
And there are following exchange rates:
| currency | rate |
| EUR | 1 |
| USD | 0.76496 |
| GBP | 1.13986 |
Scenario: Switching currency as visitor
Given I am on the store homepage
When I follow "$"
Then I should see product prices in "$"
When I follow ""
Then I should see product prices in ""
When I follow "£"
Then I should see product prices in "£"
Scenario: Switching currency as logged in user
Given I am logged in user
And I am on the store homepage
When I follow "$"
Then I should see product prices in "$"
When I follow ""
Then I should see product prices in ""
When I follow "£"
Then I should see product prices in "£"

View file

@ -14,25 +14,46 @@ namespace Sylius\Bundle\CoreBundle\Context;
use Sylius\Bundle\MoneyBundle\Context\CurrencyContext as BaseCurrencyContext;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Doctrine\Common\Persistence\ObjectManager;
class CurrencyContext extends BaseCurrencyContext
{
protected $securityContext;
protected $userManager;
public function __construct(SecurityContextInterface $securityContext, SessionInterface $session, $defaultCurrency)
public function __construct(SecurityContextInterface $securityContext, SessionInterface $session, ObjectManager $userManager, $defaultCurrency)
{
$this->securityContext = $securityContext;
$this->userManager = $userManager;
parent::__construct($session, $defaultCurrency);
}
public function getCurrency()
{
if ((null !== $token = $this->securityContext->getToken()) && is_object($user = $token->getUser())) {
return $user->getCurrency();
if (null === $user = $this->getUser()) {
return parent::getCurrency();
}
return $user->getCurrency();
}
return parent::getCurrency();
public function setCurrency($currency)
{
if (null === $user = $this->getUser()) {
return parent::setCurrency($currency);
}
$user->setCurrency($currency);
$this->userManager->persist($user);
$this->userManager->flush();
}
protected function getUser()
{
if ((null !== $token = $this->securityContext->getToken()) && is_object($user = $token->getUser())) {
return $user;
}
}
}

View file

@ -12,7 +12,6 @@
namespace Sylius\Bundle\CoreBundle\DataFixtures\ORM;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\Intl\Intl;
/**
* Default exchange rate fixtures.
@ -28,10 +27,10 @@ class LoadExchangeRatesData extends DataFixture
{
$exchangeRateRepository = $this->getExchangeRateRepository();
foreach (Intl::getCurrencyBundle()->getCurrencyNames() as $name => $iso) {
foreach (array('EUR', 'USD', 'GBP') as $currency) {
$exchangeRate = $exchangeRateRepository->createNew();
$exchangeRate->setCurrency($name);
$exchangeRate->setCurrency($currency);
$exchangeRate->setRate($this->faker->randomFloat(null, 0, 100));
$manager->persist($exchangeRate);

View file

@ -220,6 +220,7 @@
<service id="sylius.currency_context" class="%sylius.currency_context.class%">
<argument type="service" id="security.context" />
<argument type="service" id="session" />
<argument type="service" id="sylius.manager.user" />
<argument>%sylius.money.currency%</argument>
</service>
</services>

View file

@ -18,10 +18,11 @@ class CurrencyContext extends ObjectBehavior
/**
* @param Symfony\Component\Security\Core\SecurityContextInterface $securityContext
* @param Symfony\Component\HttpFoundation\Session\SessionInterface $session
* @param use Doctrine\Common\Persistence\ObjectManager $userManager
*/
function let($securityContext, $session)
function let($securityContext, $session, $userManager)
{
$this->beConstructedWith($securityContext, $session, 'EUR');
$this->beConstructedWith($securityContext, $session, $userManager, 'EUR');
}
function it_is_initializable()
@ -58,4 +59,29 @@ class CurrencyContext extends ObjectBehavior
$this->getCurrency()->shouldReturn('PLN');
}
/**
* @param Symfony\Component\Security\Core\Authentication\Token\TokenInterface $token
*/
function it_sets_currency_to_session_if_there_is_no_user($token, $securityContext, $session)
{
$securityContext->getToken()->shouldBeCalled()->willReturn($token);
$token->getUser()->shouldBeCalled()->willReturn(null);
$session->set('currency', 'PLN')->shouldBeCalled();
$this->setCurrency('PLN');
}
/**
* @param Sylius\Bundle\CoreBundle\Entity\User $user
* @param Symfony\Component\Security\Core\Authentication\Token\TokenInterface $token
*/
function it_sets_currency_to_user_if_authenticated($user, $token, $securityContext)
{
$securityContext->getToken()->shouldBeCalled()->willReturn($token);
$token->getUser()->shouldBeCalled()->willReturn($user);
$user->setCurrency('PLN')->shouldBeCalled();
$this->setCurrency('PLN');
}
}

View file

@ -156,6 +156,7 @@ class DataContext extends BehatContext implements KernelAwareInterface
$user->setEmail($email);
$user->setEnabled('yes' === $enabled);
$user->setPlainPassword($password);
$user->setCurrency('EUR');
if (null !== $address) {
$user->setShippingAddress($this->createAddress($address));

View file

@ -467,6 +467,14 @@ class WebUser extends MinkContext implements KernelAwareInterface
));
}
/**
* @Then /^I should see product prices in "([^"]*)"$/
*/
public function iShouldSeeProductPricesIn($currency)
{
$this->assertSession()->elementExists('css', sprintf('span.label:contains("%s")', $currency));
}
/**
* @Given /^I leave "([^"]*)" empty$/
* @Given /^I leave "([^"]*)" field blank/

View file

@ -20,6 +20,7 @@ use Sylius\Bundle\TaxonomiesBundle\Model\TaxonInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Intl\Intl;
/**
* Frontend menu builder.
@ -28,6 +29,12 @@ use Symfony\Component\Translation\TranslatorInterface;
*/
class FrontendMenuBuilder extends MenuBuilder
{
/**
* Currency repository.
*
* @var RepositoryInterface
*/
protected $exchangeRateRepository;
/**
* Taxonomy repository.
*
@ -62,6 +69,7 @@ class FrontendMenuBuilder extends MenuBuilder
FactoryInterface $factory,
SecurityContextInterface $securityContext,
TranslatorInterface $translator,
RepositoryInterface $exchangeRateRepository,
RepositoryInterface $taxonomyRepository,
CartProviderInterface $cartProvider,
SyliusMoneyExtension $moneyExtension
@ -69,6 +77,7 @@ class FrontendMenuBuilder extends MenuBuilder
{
parent::__construct($factory, $securityContext, $translator);
$this->exchangeRateRepository = $exchangeRateRepository;
$this->taxonomyRepository = $taxonomyRepository;
$this->cartProvider = $cartProvider;
$this->moneyExtension = $moneyExtension;
@ -85,7 +94,7 @@ class FrontendMenuBuilder extends MenuBuilder
{
$menu = $this->factory->createItem('root', array(
'childrenAttributes' => array(
'class' => 'nav nav-pills pull-right'
'class' => 'nav nav-pills'
)
));
@ -96,14 +105,14 @@ class FrontendMenuBuilder extends MenuBuilder
$menu->addChild('cart', array(
'route' => 'sylius_cart_summary',
'linkAttributes' => array('title' => $this->translate('sylius.frontend.menu.main.cart', array(
'%items%' => $cart->getTotalItems(),
'%total%' => $this->moneyExtension->formatMoney($cart->getTotal())
'%items%' => $cart->getTotalItems(),
'%total%' => $this->moneyExtension->formatMoney($cart->getTotal())
))),
'labelAttributes' => array('icon' => 'icon-shopping-cart icon-large')
))->setLabel($this->translate('sylius.frontend.menu.main.cart', array(
'%items%' => $cart->getTotalItems(),
'%total%' => $this->moneyExtension->formatMoney($cart->getTotal())
)));
'%items%' => $cart->getTotalItems(),
'%total%' => $this->moneyExtension->formatMoney($cart->getTotal())
)));
if ($this->securityContext->isGranted('ROLE_USER')) {
$menu->addChild('account', array(
@ -140,6 +149,31 @@ class FrontendMenuBuilder extends MenuBuilder
return $menu;
}
/**
* Builds frontend currency menu.
*
* @return ItemInterface
*/
public function createCurrencyMenu()
{
$menu = $this->factory->createItem('root', array(
'childrenAttributes' => array(
'class' => 'nav nav-pills'
)
));
foreach ($this->exchangeRateRepository->findAll() as $exchangeRate)
{
$menu->addChild($exchangeRate->getCurrency(), array(
'route' => 'sylius_currency_change',
'routeParameters' => array('currency' => $exchangeRate->getCurrency()),
'linkAttributes' => array('title' => $this->translate('sylius.frontend.menu.currency', array('%currency%' => $exchangeRate->getCurrency()))),
))->setLabel(Intl::getCurrencyBundle()->getCurrencySymbol($exchangeRate->getCurrency()));
}
return $menu;
}
/**
* Builds frontend taxonomies menu.
*

View file

@ -121,3 +121,7 @@ div.footer ul li a {
float: none;
margin-right: 0;
}
div.currency-menu {
margin-right: 50px;
}

View file

@ -0,0 +1,7 @@
# This file is part of the Sylius package.
# (c) Paweł Jędrzejewski
sylius_currency_change:
pattern: /change/{currency}
defaults:
_controller: sylius.controller.currency:changeAction

View file

@ -5,6 +5,10 @@ sylius_homepage:
pattern: /
defaults: { _controller: sylius.controller.frontend.homepage:mainAction }
sylius_currency:
resource: @SyliusWebBundle/Resources/config/routing/frontend/currency.yml
prefix: /currency
sylius_product:
resource: @SyliusWebBundle/Resources/config/routing/frontend/product.yml

View file

@ -44,6 +44,7 @@
<argument type="service" id="knp_menu.factory" />
<argument type="service" id="security.context" />
<argument type="service" id="translator" />
<argument type="service" id="sylius.repository.exchange_rate" />
<argument type="service" id="sylius.repository.taxonomy" />
<argument type="service" id="sylius.cart_provider" />
<argument type="service" id="sylius.twig.money" />
@ -58,6 +59,9 @@
<argument type="service" id="request" />
<tag name="knp_menu.menu" alias="sylius.frontend.main" />
</service>
<service id="sylius.menu.frontend.currency" class="Knp\Menu\MenuItem" factory-service="sylius.menu_builder.frontend" factory-method="createCurrencyMenu">
<tag name="knp_menu.menu" alias="sylius.frontend.currency" />
</service>
<service id="sylius.menu.frontend.taxonomies" class="Knp\Menu\MenuItem" factory-service="sylius.menu_builder.frontend" factory-method="createTaxonomiesMenu" scope="request">
<argument type="service" id="request" />
<tag name="knp_menu.menu" alias="sylius.frontend.taxonomies" />

View file

@ -230,6 +230,10 @@
<source>sylius.frontend.menu.main.administration</source>
<target>Administration</target>
</trans-unit>
<trans-unit id="72a1c20506c99bf710d871e649d73b7a" resname="sylius.frontend.menu.currency">
<source>sylius.frontend.menu.currency</source>
<target>Show prices in %currency%</target>
</trans-unit>
<trans-unit id="f3c562d05786e3056e97da27f1fac4d3" resname="sylius.frontend.menu.main.cart">
<source>sylius.frontend.menu.main.cart</source>
<target>View cart (%items%) %total%</target>

View file

@ -36,6 +36,9 @@
<div class="masthead pull-right">
{{ knp_menu_render('sylius.frontend.main', {'template': 'SyliusWebBundle:Frontend:menu.html.twig'}) }}
</div>
<div class="currency-menu masthead pull-right">
{{ knp_menu_render('sylius.frontend.currency', {'template': 'SyliusWebBundle:Frontend:menu.html.twig'}) }}
</div>
<h1 class="logo"><a href="{{ path('sylius_homepage') }}" title="{{ 'sylius.logo'|trans }}"><img src="{{ asset('assets/img/logo.png') }}" alt="{{ 'sylius.logo'|trans }}"><span>{{ 'sylius.logo'|trans }}</span></a></h1>
{% endblock %}