mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 09:02:12 +00:00
reports correct sum with currencies and label
This commit is contained in:
parent
90ccc116dd
commit
069ead1e76
17 changed files with 179 additions and 14 deletions
|
|
@ -226,6 +226,7 @@ class BookController extends ResourceController
|
|||
* Removed ``Address`` relations to ``Country`` and ``Province`` objects, their unique ``code`` is used instead;
|
||||
* Removed specific ``ZoneMembers`` i.e. ``ProvinceZoneMember`` in favor of a dynamic ``ZoneMember``;
|
||||
* https://github.com/Sylius/Sylius/pull/3696
|
||||
* ``exchangeRate`` is now recorded for ``Order`` at time of purchase for accurate cross-currency reporting.
|
||||
|
||||
### Order and SyliusOrderBundle
|
||||
|
||||
|
|
|
|||
34
app/migrations/Version20160118140609.php
Normal file
34
app/migrations/Version20160118140609.php
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Sylius\Migrations;
|
||||
|
||||
use Doctrine\DBAL\Migrations\AbstractMigration;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
class Version20160118140609 extends AbstractMigration
|
||||
{
|
||||
/**
|
||||
* @param Schema $schema
|
||||
*/
|
||||
public function up(Schema $schema)
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');
|
||||
|
||||
$this->addSql('ALTER TABLE sylius_order ADD exchange_rate NUMERIC(10, 5) NOT NULL');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Schema $schema
|
||||
*/
|
||||
public function down(Schema $schema)
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');
|
||||
|
||||
$this->addSql('ALTER TABLE sylius_order DROP exchange_rate');
|
||||
}
|
||||
}
|
||||
|
|
@ -250,6 +250,7 @@ default:
|
|||
- Behat\MinkExtension\Context\MinkContext
|
||||
- Sylius\Bundle\CoreBundle\Behat\HookContext
|
||||
- Sylius\Bundle\AddressingBundle\Behat\AddressingContext
|
||||
- Sylius\Bundle\ShippingBundle\Behat\ShippingContext
|
||||
- Sylius\Bundle\CoreBundle\Behat\CoreContext
|
||||
- Sylius\Bundle\PaymentBundle\Behat\PaymentContext
|
||||
- Sylius\Bundle\ProductBundle\Behat\ProductContext
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ Feature: Reports
|
|||
And there are following reports configured:
|
||||
| code | name | description | renderer | renderer_configuration | data_fetcher | data_fetcher_configuration |
|
||||
| table_report | TableReport | Lorem ipsum | table | Template:SyliusReportBundle:Table:default.html.twig | user_registration | Period:day,Start:2010-01-01,End:2010-04-01 |
|
||||
| sales_report | SalesReport | Lorem ipsum | table | Template:SyliusReportBundle:Table:default.html.twig | sales_total | Period:day,Start:2010-01-01,End:2010-01-05 |
|
||||
| bar_chart_report | BarChartReport | Lorem ipsum | chart | Type:bar,Template:SyliusReportBundle:Chart:default.html.twig | user_registration | Period:month,Start:2010-01-01,End:2010-04-01 |
|
||||
And there are following users:
|
||||
| email | enabled | created at |
|
||||
|
|
@ -20,7 +21,7 @@ Feature: Reports
|
|||
Scenario: Seeing created reports it the list
|
||||
Given I am on the dashboard page
|
||||
When I follow "Reports"
|
||||
Then I should see 2 reports in the list
|
||||
Then I should see 3 reports in the list
|
||||
|
||||
Scenario: Adding new report with default options
|
||||
Given I am on the report creation page
|
||||
|
|
@ -140,3 +141,44 @@ Feature: Reports
|
|||
And I press "Create"
|
||||
Then I should still be on the report creation page
|
||||
And I should see "Report code cannot be blank"
|
||||
|
||||
Scenario: Getting the correct sum with exchange rate
|
||||
Given the following zones are defined:
|
||||
| name | type | members |
|
||||
| Scandinavia | country | Norway, Sweden, Finland |
|
||||
| France | country | France |
|
||||
And there are following shipping categories:
|
||||
| code | name |
|
||||
| SC1 | Regular |
|
||||
| SC2 | Heavy |
|
||||
And the following shipping methods exist:
|
||||
| code | category | zone | name |
|
||||
| SM1 | Regular | Scandinavia | DHL |
|
||||
| SM2 | Heavy | France | UPS |
|
||||
And the following products exist:
|
||||
| name | price | sku |
|
||||
| Mug | 10 | 456 |
|
||||
| Book | 22 | 948 |
|
||||
And the following orders exist:
|
||||
| customer | shipment | address | currency | exchange_rate |
|
||||
| sylius@example.com | UPS, shipped, DTBHH380HG | Théophile Morel, 17 avenue Jean Portalis, 33000, Bordeaux, France | EUR | 1.00000 |
|
||||
| linustorvalds@linux.com | DHL, shipped, DTBHH380HH | Linus Torvalds, Väätäjänniementie 59, 00440, Helsinki, Finland | USD | 0.5 |
|
||||
| sylius@example.com | UPS, shipped, DTBHH380HI | Théophile Morel, 17 avenue Jean Portalis, 33000, Bordeaux, France | GBP | 1.25 |
|
||||
And order #000000001 has following items:
|
||||
| product | quantity |
|
||||
| Mug | 2 |
|
||||
| Book | 1 |
|
||||
And order #000000002 has following items:
|
||||
| product | quantity |
|
||||
| Mug | 2 |
|
||||
| Book | 1 |
|
||||
And order #000000003 has following items:
|
||||
| product | quantity |
|
||||
| Mug | 2 |
|
||||
| Book | 1 |
|
||||
And order #000000001 will be completed on "2010-01-01"
|
||||
And order #000000002 will be completed on "2010-01-02"
|
||||
And order #000000003 will be completed on "2010-01-02"
|
||||
When I am on the page of report "SalesReport"
|
||||
Then the report row for date "2010-01-01" will have a total amount of "42"
|
||||
Then the report row for date "2010-01-02" will have a total amount of "73.50"
|
||||
|
|
@ -149,7 +149,16 @@ class CoreContext extends DefaultContext
|
|||
|
||||
$this->createPayment($order, $paymentMethod);
|
||||
|
||||
if (isset($data['currency']) && '' !== trim($data['currency'])) {
|
||||
$order->setCurrency($data['currency']);
|
||||
} else {
|
||||
$order->setCurrency('EUR');
|
||||
}
|
||||
|
||||
if (isset($data['exchange_rate']) && '' !== trim($data['exchange_rate'])) {
|
||||
$order->setExchangeRate($data['exchange_rate']);
|
||||
}
|
||||
|
||||
$order->setPaymentState(PaymentInterface::STATE_COMPLETED);
|
||||
|
||||
$order->complete();
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ use Sylius\Component\Order\OrderTransitions;
|
|||
* Final checkout step.
|
||||
*
|
||||
* @author Paweł Jędrzejewski <pawel@sylius.org>
|
||||
* @author Fernando Caraballo Ortiz <caraballo.ortiz@gmail.com>
|
||||
*/
|
||||
class FinalizeStep extends CheckoutStep
|
||||
{
|
||||
|
|
@ -64,10 +65,18 @@ class FinalizeStep extends CheckoutStep
|
|||
protected function completeOrder(OrderInterface $order)
|
||||
{
|
||||
$this->get('session')->set('sylius_order_id', $order->getId());
|
||||
|
||||
$currencyProvider = $this->get('sylius.currency_provider');
|
||||
|
||||
$this->dispatchCheckoutEvent(SyliusOrderEvents::PRE_CREATE, $order);
|
||||
$this->dispatchCheckoutEvent(SyliusCheckoutEvents::FINALIZE_PRE_COMPLETE, $order);
|
||||
|
||||
$this->get('sm.factory')->get($order, OrderTransitions::GRAPH)->apply(OrderTransitions::SYLIUS_CREATE, true);
|
||||
if ($order->getCurrency() !== $currencyProvider->getBaseCurrency()) {
|
||||
$currencyRepository = $this->get('sylius.repository.currency');
|
||||
$currency = $currencyRepository->findOneBy(['code' => $order->getCurrency()]);
|
||||
$order->setExchangeRate($currency->getExchangeRate());
|
||||
}
|
||||
|
||||
$manager = $this->get('sylius.manager.order');
|
||||
$manager->persist($order);
|
||||
|
|
|
|||
|
|
@ -330,8 +330,9 @@ class OrderRepository extends CartRepository implements OrderRepositoryInterface
|
|||
$configuration['end'],
|
||||
$groupBy);
|
||||
|
||||
$baseCurrencyCode = $configuration['baseCurrency'] ? 'in ' . $configuration['baseCurrency']->getCode() : '';
|
||||
$queryBuilder
|
||||
->select('DATE(o.completed_at) as date', 'TRUNCATE(SUM(o.total)/ 100,2) as "total sum"')
|
||||
->select('DATE(o.completed_at) as date', 'TRUNCATE(SUM(o.total * o.exchange_rate)/ 100,2) as "total sum ' . $baseCurrencyCode . '"')
|
||||
;
|
||||
|
||||
return $queryBuilder
|
||||
|
|
|
|||
|
|
@ -23,8 +23,14 @@ use Symfony\Component\EventDispatcher\GenericEvent;
|
|||
*/
|
||||
class OrderCurrencyListener
|
||||
{
|
||||
/**
|
||||
* @var CurrencyContextInterface
|
||||
*/
|
||||
protected $currencyContext;
|
||||
|
||||
/**
|
||||
* @param CurrencyContextInterface $currencyContext
|
||||
*/
|
||||
public function __construct(CurrencyContextInterface $currencyContext)
|
||||
{
|
||||
$this->currencyContext = $currencyContext;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
<gedmo:versioned />
|
||||
</field>
|
||||
|
||||
<field name="exchangeRate" column="exchange_rate" type="decimal" precision="10" scale="5" />
|
||||
<field type="string" name="checkoutState" column="checkout_state" />
|
||||
<field type="string" name="paymentState" column="payment_state" />
|
||||
<field type="string" name="shippingState" column="shipping_state" />
|
||||
|
|
|
|||
|
|
@ -468,6 +468,7 @@
|
|||
|
||||
<service id="sylius.currency_provider" class="%sylius.currency_provider.class%">
|
||||
<argument type="service" id="sylius.context.channel" />
|
||||
<argument type="service" id="sylius.repository.currency" />
|
||||
</service>
|
||||
|
||||
<service id="sylius.channel_aware_locale_provider" class="%sylius.channel_aware_locale_provider.class%">
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ class SalesTotalDataFetcherSpec extends ObjectBehavior
|
|||
$this->fetch($configuration)->shouldBeLike($data);
|
||||
}
|
||||
|
||||
public function it_does_not_allowed_wrond_data_period($orderRepository, Data $data)
|
||||
public function it_does_not_allowed_wrond_data_period()
|
||||
{
|
||||
$configuration = array(
|
||||
'start' => new \DateTime('2010-01-01 00:00:00.000000'),
|
||||
|
|
|
|||
|
|
@ -40,6 +40,12 @@ class LoadOrdersData extends DataFixture
|
|||
'MOBILE',
|
||||
);
|
||||
|
||||
$currencyExchangeRates = array(
|
||||
'GBP' => 0.8,
|
||||
'USD' => 1.2,
|
||||
'EUR' => 1.0
|
||||
);
|
||||
|
||||
for ($i = 1; $i <= 50; $i++) {
|
||||
/* @var $order OrderInterface */
|
||||
$order = $orderFactory->createNew();
|
||||
|
|
@ -62,7 +68,8 @@ class LoadOrdersData extends DataFixture
|
|||
|
||||
$this->createShipment($order);
|
||||
|
||||
$order->setCurrency($this->faker->randomElement(array('EUR', 'USD', 'GBP')));
|
||||
$order->setCurrency($this->faker->randomElement(array_keys($currencyExchangeRates)));
|
||||
$order->setExchangeRate($currencyExchangeRates[$order->getCurrency()]);
|
||||
$order->setShippingAddress($this->createAddress());
|
||||
$order->setBillingAddress($this->createAddress());
|
||||
$order->setCreatedAt($this->faker->dateTimeBetween('1 year ago', 'now'));
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ use Sylius\Bundle\ResourceBundle\Behat\DefaultContext;
|
|||
* ReportContext for ReportBundle scenarios.
|
||||
*
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Fernando Caraballo Ortiz <caraballo.ortiz@gmail.com>
|
||||
*/
|
||||
class ReportContext extends DefaultContext
|
||||
{
|
||||
|
|
@ -96,4 +97,33 @@ class ReportContext extends DefaultContext
|
|||
|
||||
return $report;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then the report row for date :date will have a total amount of :total
|
||||
*/
|
||||
public function theReportRowForDateWillHaveATotalAmountOf($date, $total)
|
||||
{
|
||||
$page = $this->getSession()->getPage();
|
||||
$rows = $page->findAll('css', 'table tbody tr');
|
||||
foreach ($rows as $row) {
|
||||
$columns = $row->findAll('css', 'td');
|
||||
if ($columns[1]->getText() === $date) {
|
||||
\PHPUnit_Framework_Assert::assertEquals($columns[2]->getText(), $total);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Given order #:orderNumber will be completed on :date
|
||||
*/
|
||||
public function orderWillBeCompletedOn($orderNumber, $date)
|
||||
{
|
||||
$orderRepository = $this->getContainer()->get('sylius.repository.cart');
|
||||
$orderManager = $this->getContainer()->get('sylius.manager.cart');
|
||||
|
||||
$order = $orderRepository->findOneBy(['number' => $orderNumber]);
|
||||
$order->setCompletedAt(new \DateTime($date));
|
||||
|
||||
$orderManager->flush();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ use Symfony\Component\HttpFoundation\Response;
|
|||
/**
|
||||
* @author Mateusz Zalewski <mateusz.zalewski@lakion.com>
|
||||
* @author Łukasz Chruściel <lukasz.chrusciel@lakion.com>
|
||||
* @author Fernando Caraballo Ortiz <caraballo.ortiz@gmail.com>
|
||||
*/
|
||||
class ReportController extends ResourceController
|
||||
{
|
||||
|
|
@ -63,6 +64,8 @@ class ReportController extends ResourceController
|
|||
*/
|
||||
public function embedAction(Request $request, $report, array $configuration = array())
|
||||
{
|
||||
$currencyProvider = $this->get('sylius.currency_provider');
|
||||
|
||||
if (!$report instanceof ReportInterface) {
|
||||
$report = $this->getReportRepository()->findOneBy(array('code' => $report));
|
||||
}
|
||||
|
|
@ -72,6 +75,8 @@ class ReportController extends ResourceController
|
|||
}
|
||||
|
||||
$configuration = $request->query->get('configuration', $configuration);
|
||||
$configuration['baseCurrency'] = $currencyProvider->getBaseCurrency();
|
||||
|
||||
$data = $this->getReportDataFetcher()->fetch($report, $configuration);
|
||||
|
||||
return new Response($this->getReportRenderer()->render($report, $data));
|
||||
|
|
|
|||
|
|
@ -13,27 +13,30 @@ namespace Sylius\Component\Core\Currency;
|
|||
|
||||
use Sylius\Component\Channel\Context\ChannelContextInterface;
|
||||
use Sylius\Component\Currency\Model\CurrencyInterface;
|
||||
use Sylius\Component\Currency\Provider\CurrencyProviderInterface;
|
||||
use Sylius\Component\Currency\Provider\CurrencyProvider;
|
||||
use Sylius\Component\Resource\Repository\RepositoryInterface;
|
||||
|
||||
/**
|
||||
* Currency provider, which returns currencies enabled for this channel.
|
||||
*
|
||||
* @author Paweł Jędrzejewski <pawel@sylius.org>
|
||||
* @author Fernando Caraballo Ortiz <caraballo.ortiz@gmail.com>
|
||||
*/
|
||||
class ChannelAwareCurrencyProvider implements CurrencyProviderInterface
|
||||
class ChannelAwareCurrencyProvider extends CurrencyProvider
|
||||
{
|
||||
/**
|
||||
* Channel context.
|
||||
*
|
||||
* @var ChannelContextInterface
|
||||
*/
|
||||
protected $channelContext;
|
||||
|
||||
/**
|
||||
* @param ChannelContextInterface $channelContext
|
||||
* @param RepositoryInterface $currencyRepository
|
||||
*/
|
||||
public function __construct(ChannelContextInterface $channelContext)
|
||||
public function __construct(ChannelContextInterface $channelContext, RepositoryInterface $currencyRepository)
|
||||
{
|
||||
parent::__construct($currencyRepository);
|
||||
|
||||
$this->channelContext = $channelContext;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use Sylius\Component\Resource\Repository\RepositoryInterface;
|
|||
|
||||
/**
|
||||
* @author Paweł Jędrzejewski <pawel@sylius.org>
|
||||
* @author Fernando Caraballo Ortiz <caraballo.ortiz@gmail.com>
|
||||
*/
|
||||
class CurrencyProvider implements CurrencyProviderInterface
|
||||
{
|
||||
|
|
@ -38,4 +39,12 @@ class CurrencyProvider implements CurrencyProviderInterface
|
|||
{
|
||||
return $this->currencyRepository->findBy(array('enabled' => true));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getBaseCurrency()
|
||||
{
|
||||
return $this->currencyRepository->findOneBy(['base' => true]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use Sylius\Component\Currency\Model\CurrencyInterface;
|
|||
|
||||
/**
|
||||
* @author Paweł Jędrzejewski <pawel@sylius.org>
|
||||
* @author Fernando Caraballo Ortiz <caraballo.ortiz@gmail.com>
|
||||
*/
|
||||
interface CurrencyProviderInterface
|
||||
{
|
||||
|
|
@ -22,4 +23,9 @@ interface CurrencyProviderInterface
|
|||
* @return CurrencyInterface[]
|
||||
*/
|
||||
public function getAvailableCurrencies();
|
||||
|
||||
/**
|
||||
* @return CurrencyInterface
|
||||
*/
|
||||
public function getBaseCurrency();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue