From 4bde09a9399543f2bd446f0495ddce985e2d883b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20J=C4=99drzejewski?= Date: Thu, 3 Jan 2013 20:34:48 +0100 Subject: [PATCH] Initial taxation and adjustments integration --- composer.lock | 53 ++++---- sandbox/config/container/base.yml | 3 +- .../SandboxBundle/Builder/OrderBuilder.php | 17 ++- .../SandboxBundle/Builder/OrderBuilder.php | 58 +++++---- .../DataFixtures/ORM/LoadAddressesData.php | 2 +- .../ORM/LoadDefaultSettingsData.php | 8 +- .../DataFixtures/ORM/LoadOrdersData.php | 4 + .../DataFixtures/ORM/LoadTaxationData.php | 1 + .../Bundle/SandboxBundle/Entity/Order.php | 29 +++++ .../InventoryListener.php | 2 +- .../EventListener/OrderInventoryListener.php | 69 ++++++++++ .../EventListener/OrderTaxationListener.php | 122 ++++++++++++++++++ .../Bundle/SandboxBundle/Menu/Builder.php | 4 + .../Process/Step/FinalizeStep.php | 15 ++- .../Resources/config/doctrine/Order.orm.xml | 5 + .../config/doctrine/OrderItem.orm.xml | 5 + .../config/routing/backend/settings.yml | 7 + .../Resources/config/services.xml | 37 +++++- .../views/Backend/Order/show.html.twig | 43 +++++- .../Resources/views/Backend/Settings/:w | 23 ---- .../views/Backend/Settings/taxation.html.twig | 18 +++ .../Frontend/Checkout/Step/finalize.html.twig | 8 ++ .../Settings/GeneralSettingsSchema.php | 12 +- .../Settings/TaxationSettingsSchema.php | 45 +++++++ .../Taxation/TaxRateResolver.php | 41 ++++++ 25 files changed, 527 insertions(+), 104 deletions(-) mode change 100755 => 100644 src/Sylius/Bundle/SandboxBundle/Builder/OrderBuilder.php rename src/Sylius/Bundle/SandboxBundle/{EventDispatcher/Listener => EventListener}/InventoryListener.php (95%) create mode 100644 src/Sylius/Bundle/SandboxBundle/EventListener/OrderInventoryListener.php create mode 100644 src/Sylius/Bundle/SandboxBundle/EventListener/OrderTaxationListener.php delete mode 100644 src/Sylius/Bundle/SandboxBundle/Resources/views/Backend/Settings/:w create mode 100644 src/Sylius/Bundle/SandboxBundle/Resources/views/Backend/Settings/taxation.html.twig create mode 100644 src/Sylius/Bundle/SandboxBundle/Settings/TaxationSettingsSchema.php create mode 100644 src/Sylius/Bundle/SandboxBundle/Taxation/TaxRateResolver.php diff --git a/composer.lock b/composer.lock index b4e823fe..baf5e951 100644 --- a/composer.lock +++ b/composer.lock @@ -2295,12 +2295,12 @@ "source": { "type": "git", "url": "https://github.com/Sylius/SyliusAddressingBundle.git", - "reference": "743ff525ccedbf2dd6f99228fee245b1e46dec8d" + "reference": "7746aa4da7b080a969b7e3681c0b853d8670fffb" }, "dist": { "type": "zip", - "url": "https://github.com/Sylius/SyliusAddressingBundle/archive/743ff525ccedbf2dd6f99228fee245b1e46dec8d.zip", - "reference": "743ff525ccedbf2dd6f99228fee245b1e46dec8d", + "url": "https://github.com/Sylius/SyliusAddressingBundle/archive/7746aa4da7b080a969b7e3681c0b853d8670fffb.zip", + "reference": "7746aa4da7b080a969b7e3681c0b853d8670fffb", "shasum": "" }, "require": { @@ -2313,7 +2313,7 @@ "phpspec/phpspec2": "dev-develop", "doctrine/orm": "*" }, - "time": "2012-12-26 10:13:56", + "time": "2013-01-02 01:01:38", "type": "symfony-bundle", "installation-source": "source", "autoload": { @@ -2645,12 +2645,12 @@ "source": { "type": "git", "url": "https://github.com/Sylius/SyliusInventoryBundle.git", - "reference": "23b90111271d1e8ed1feffb10a328695dcee78da" + "reference": "b14d8d2679e9a7c8685bc4eb2450de857972e3f3" }, "dist": { "type": "zip", - "url": "https://github.com/Sylius/SyliusInventoryBundle/archive/23b90111271d1e8ed1feffb10a328695dcee78da.zip", - "reference": "23b90111271d1e8ed1feffb10a328695dcee78da", + "url": "https://github.com/Sylius/SyliusInventoryBundle/archive/b14d8d2679e9a7c8685bc4eb2450de857972e3f3.zip", + "reference": "b14d8d2679e9a7c8685bc4eb2450de857972e3f3", "shasum": "" }, "require": { @@ -2664,7 +2664,7 @@ "suggest": { "friendsofsymfony/rest-bundle": "*" }, - "time": "2012-12-18 16:45:06", + "time": "2013-01-02 02:10:58", "type": "symfony-bundle", "installation-source": "source", "autoload": { @@ -2703,12 +2703,12 @@ "source": { "type": "git", "url": "https://github.com/Sylius/SyliusResourceBundle.git", - "reference": "c20075c863c56bbcd36a7a97d3c17e0458d1ed36" + "reference": "d1f1b35916f6c6451fe8ea8ad4df7a9bac4cb7f3" }, "dist": { "type": "zip", - "url": "https://github.com/Sylius/SyliusResourceBundle/archive/c20075c863c56bbcd36a7a97d3c17e0458d1ed36.zip", - "reference": "c20075c863c56bbcd36a7a97d3c17e0458d1ed36", + "url": "https://github.com/Sylius/SyliusResourceBundle/archive/d1f1b35916f6c6451fe8ea8ad4df7a9bac4cb7f3.zip", + "reference": "d1f1b35916f6c6451fe8ea8ad4df7a9bac4cb7f3", "shasum": "" }, "require": { @@ -2727,7 +2727,7 @@ "doctrine/orm": "~2.3", "doctrine/mongodb-odm": "*" }, - "time": "2012-12-30 03:52:31", + "time": "2012-12-30 17:05:49", "type": "symfony-bundle", "installation-source": "source", "autoload": { @@ -2765,12 +2765,12 @@ "source": { "type": "git", "url": "https://github.com/Sylius/SyliusSalesBundle.git", - "reference": "99db6ec35f9390d054a36fbce896c44774ebf9fb" + "reference": "0e43e00917f85e7b0b4c811a35705e127da63e01" }, "dist": { "type": "zip", - "url": "https://github.com/Sylius/SyliusSalesBundle/archive/99db6ec35f9390d054a36fbce896c44774ebf9fb.zip", - "reference": "99db6ec35f9390d054a36fbce896c44774ebf9fb", + "url": "https://github.com/Sylius/SyliusSalesBundle/archive/0e43e00917f85e7b0b4c811a35705e127da63e01.zip", + "reference": "0e43e00917f85e7b0b4c811a35705e127da63e01", "shasum": "" }, "require": { @@ -2786,7 +2786,7 @@ "doctrine/orm": "*", "doctrine/doctrine-bundle": "*" }, - "time": "2012-12-13 23:03:21", + "time": "2012-12-30 23:15:12", "type": "symfony-bundle", "installation-source": "source", "autoload": { @@ -2826,26 +2826,27 @@ "source": { "type": "git", "url": "https://github.com/Sylius/SyliusSettingsBundle.git", - "reference": "8b11288c1590dc0c6f48c4f454b9a17ee35f86bd" + "reference": "41fb24653761b3d7f50aae4f9e7a9f23a1bf4b8a" }, "dist": { "type": "zip", - "url": "https://github.com/Sylius/SyliusSettingsBundle/archive/8b11288c1590dc0c6f48c4f454b9a17ee35f86bd.zip", - "reference": "8b11288c1590dc0c6f48c4f454b9a17ee35f86bd", + "url": "https://github.com/Sylius/SyliusSettingsBundle/archive/41fb24653761b3d7f50aae4f9e7a9f23a1bf4b8a.zip", + "reference": "41fb24653761b3d7f50aae4f9e7a9f23a1bf4b8a", "shasum": "" }, "require": { "php": ">=5.3.2", "symfony/framework-bundle": ">=2.1,<3.0", "sylius/resource-bundle": "*", - "stof/doctrine-extensions-bundle": "*" + "stof/doctrine-extensions-bundle": "*", + "liip/doctrine-cache-bundle": "dev-master" }, "require-dev": { "phpspec/phpspec2": "dev-develop", "symfony/form": ">=2.1,<3.0", "twig/twig": "*" }, - "time": "2012-12-27 16:21:27", + "time": "2013-01-03 17:46:56", "type": "symfony-bundle", "installation-source": "source", "autoload": { @@ -2868,7 +2869,7 @@ "homepage": "https://github.com/Sylius/SyliusSettingsBundle/contributors" } ], - "description": "Settings system for Symfony2 applications.", + "description": "Settings system for Symfony2 applications, editable via web user interface.", "homepage": "http://sylius.org", "keywords": [ "configuration", @@ -2943,12 +2944,12 @@ "source": { "type": "git", "url": "https://github.com/Sylius/SyliusTaxationBundle.git", - "reference": "0db6111ab6e269ae783adf49b839124f8c166b46" + "reference": "e24d7c707e6594e88f86ff653e6e51bda7989aa6" }, "dist": { "type": "zip", - "url": "https://github.com/Sylius/SyliusTaxationBundle/archive/0db6111ab6e269ae783adf49b839124f8c166b46.zip", - "reference": "0db6111ab6e269ae783adf49b839124f8c166b46", + "url": "https://github.com/Sylius/SyliusTaxationBundle/archive/e24d7c707e6594e88f86ff653e6e51bda7989aa6.zip", + "reference": "e24d7c707e6594e88f86ff653e6e51bda7989aa6", "shasum": "" }, "require": { @@ -2960,7 +2961,7 @@ "require-dev": { "phpspec/phpspec2": "dev-develop" }, - "time": "2012-12-23 19:26:35", + "time": "2013-01-03 16:33:51", "type": "symfony-bundle", "installation-source": "source", "autoload": { diff --git a/sandbox/config/container/base.yml b/sandbox/config/container/base.yml index bfaa66c0..cc66c517 100644 --- a/sandbox/config/container/base.yml +++ b/sandbox/config/container/base.yml @@ -158,7 +158,7 @@ sylius_addressing: sylius_inventory: driver: doctrine/orm - backorders: false + backorders: true classes: model: iu: Sylius\Bundle\SandboxBundle\Entity\InventoryUnit @@ -173,6 +173,7 @@ sylius_taxonomies: sylius_taxation: driver: doctrine/orm + rate_resolver: sylius_sandbox.tax_rate_resolver classes: rate: model: Sylius\Bundle\SandboxBundle\Entity\TaxRate diff --git a/spec/Sylius/Bundle/SandboxBundle/Builder/OrderBuilder.php b/spec/Sylius/Bundle/SandboxBundle/Builder/OrderBuilder.php index f1ee8f87..5102922a 100644 --- a/spec/Sylius/Bundle/SandboxBundle/Builder/OrderBuilder.php +++ b/spec/Sylius/Bundle/SandboxBundle/Builder/OrderBuilder.php @@ -11,13 +11,28 @@ */ class OrderBuilder extends ObjectBehavior { + /** + * @param Doctrine\Common\Persistence\ObjectRepository $orderItemRepository + * @param Sylius\Bundle\CartBundle\Provider\CartProviderInterface $cartProvider + * @param Symfony\Component\Security\Core\SecurityContextInterface $securityContext + */ + function let($orderItemRepository, $cartProvider, $securityContext) + { + $this->beConstructedWith($orderItemRepository, $cartProvider, $securityContext); + } + function it_should_be_initializable() { $this->shouldHaveType('Sylius\Bundle\SandboxBundle\Builder\OrderBuilder'); } - function it_should_be_Sylius_order_builder() + function it_should_be_a_Sylius_order_builder() { $this->shouldImplement('Sylius\Bundle\SalesBundle\Builder\OrderBuilderInterface'); } + + function it_should_extend_base_Sylius_order_builder() + { + $this->shouldHaveType('Sylius\Bundle\SalesBundle\Builder\OrderBuilder'); + } } diff --git a/src/Sylius/Bundle/SandboxBundle/Builder/OrderBuilder.php b/src/Sylius/Bundle/SandboxBundle/Builder/OrderBuilder.php old mode 100755 new mode 100644 index ce90061a..281ed62e --- a/src/Sylius/Bundle/SandboxBundle/Builder/OrderBuilder.php +++ b/src/Sylius/Bundle/SandboxBundle/Builder/OrderBuilder.php @@ -2,28 +2,48 @@ namespace Sylius\Bundle\SandboxBundle\Builder; -use Sylius\Bundle\SalesBundle\Builder\OrderBuilderInterface; +use Doctrine\Common\Persistence\ObjectRepository; +use Sylius\Bundle\SalesBundle\Builder\OrderBuilder as BaseOrderBuilder; use Sylius\Bundle\SalesBundle\Model\OrderInterface; -use Symfony\Component\DependencyInjection\ContainerAware; - -class OrderBuilder extends ContainerAware implements OrderBuilderInterface +use Sylius\Bundle\CartBundle\Provider\CartProviderInterface; +use Symfony\Component\Security\Core\SecurityContextInterface; + +/** + * Order builder. + * + * @author Paweł Jędrzejewski + */ +class OrderBuilder extends BaseOrderBuilder { + private $cartProvider; + private $securityContext; + + public function __construct(ObjectRepository $orderItemRepository, CartProviderInterface $cartProvider, SecurityContextInterface $securityContext) + { + $this->cartProvider = $cartProvider; + $this->securityContext = $securityContext; + + parent::__construct($orderItemRepository); + } + + /** + * {@inheritdoc} + */ public function build(OrderInterface $order) { $order->getItems()->clear(); - $cart = $this->container->get('sylius_cart.provider')->getCart(); + $cart = $this->cartProvider->getCart(); if ($cart->isEmpty()) { - throw new \LogicException('The cart must be not empty.'); + throw new \LogicException('The cart must not be empty.'); } - $order->setUser($this->container->get('security.context')->getToken()->getUser()); - - $orderItemRepository = $this->container->get('sylius_sales.repository.item'); + $order->setUser($this->securityContext->getToken()->getUser()); foreach ($cart->getItems() as $item) { - $orderItem = $orderItemRepository->createNew(); + $orderItem = $this->createNewItem(); + $orderItem->setVariant($item->getVariant()); $orderItem->setQuantity($item->getQuantity()); $orderItem->setUnitPrice($item->getVariant()->getPrice()); @@ -33,22 +53,4 @@ public function build(OrderInterface $order) $order->calculateTotal(); } - - public function finalize(OrderInterface $order) - { - $inventoryOperator = $this->container->get('sylius_inventory.operator'); - $variantManager = $this->container->get('sylius_assortment.manager.variant'); - - foreach ($order->getItems() as $item) { - $variant = $item->getVariant(); - - $inventoryUnits = $inventoryOperator->decrease($variant, $item->getQuantity()); - $order->setInventoryUnits($inventoryUnits); - - $variantManager->persist($variant); - $variantManager->flush($variant); - } - - $this->container->get('sylius_cart.provider')->abandonCart(); - } } diff --git a/src/Sylius/Bundle/SandboxBundle/DataFixtures/ORM/LoadAddressesData.php b/src/Sylius/Bundle/SandboxBundle/DataFixtures/ORM/LoadAddressesData.php index fbd3a988..0d441e81 100644 --- a/src/Sylius/Bundle/SandboxBundle/DataFixtures/ORM/LoadAddressesData.php +++ b/src/Sylius/Bundle/SandboxBundle/DataFixtures/ORM/LoadAddressesData.php @@ -60,7 +60,7 @@ public function load(ObjectManager $manager) */ public function getOrder() { - return 7; + return 5; } private function getAddressManager() diff --git a/src/Sylius/Bundle/SandboxBundle/DataFixtures/ORM/LoadDefaultSettingsData.php b/src/Sylius/Bundle/SandboxBundle/DataFixtures/ORM/LoadDefaultSettingsData.php index 21695f69..b9806cce 100644 --- a/src/Sylius/Bundle/SandboxBundle/DataFixtures/ORM/LoadDefaultSettingsData.php +++ b/src/Sylius/Bundle/SandboxBundle/DataFixtures/ORM/LoadDefaultSettingsData.php @@ -36,11 +36,17 @@ public function load(ObjectManager $manager) ); $manager->saveSettings('general', $general); + + $taxation = array( + 'defaultTaxZone' => $this->getReference('Zone-EU') + ); + + $manager->saveSettings('taxation', $taxation); } public function getOrder() { - return 1; + return 4; } private function getSettingsManager() diff --git a/src/Sylius/Bundle/SandboxBundle/DataFixtures/ORM/LoadOrdersData.php b/src/Sylius/Bundle/SandboxBundle/DataFixtures/ORM/LoadOrdersData.php index c85b5433..43ebc4d5 100644 --- a/src/Sylius/Bundle/SandboxBundle/DataFixtures/ORM/LoadOrdersData.php +++ b/src/Sylius/Bundle/SandboxBundle/DataFixtures/ORM/LoadOrdersData.php @@ -13,6 +13,7 @@ use Doctrine\Common\Persistence\ObjectManager; use Sylius\Bundle\SalesBundle\Model\OrderInterface; +use Symfony\Component\EventDispatcher\GenericEvent; /** * Builds some simple orders to play with Sylius sandbox. @@ -28,12 +29,15 @@ public function load(ObjectManager $manager) { $orderManager = $this->container->get('sylius_sales.manager.order'); $orderRepository = $this->container->get('sylius_sales.repository.order'); + $eventDispatcher = $this->container->get('event_dispatcher'); for ($i = 1; $i <= 100; $i++) { $order = $orderRepository->createNew(); $this->buildOrder($order); + $eventDispatcher->dispatch('sylius_sales.order.pre_create', new GenericEvent($order)); $orderManager->persist($order); + $eventDispatcher->dispatch('sylius_sales.order.post_create', new GenericEvent($order)); $this->setReference('Order-'.$i, $order); } diff --git a/src/Sylius/Bundle/SandboxBundle/DataFixtures/ORM/LoadTaxationData.php b/src/Sylius/Bundle/SandboxBundle/DataFixtures/ORM/LoadTaxationData.php index 2dfc62ca..f540767b 100644 --- a/src/Sylius/Bundle/SandboxBundle/DataFixtures/ORM/LoadTaxationData.php +++ b/src/Sylius/Bundle/SandboxBundle/DataFixtures/ORM/LoadTaxationData.php @@ -28,6 +28,7 @@ public function load(ObjectManager $manager) { $taxableGoods = $this->createTaxCategory('Taxable goods', 'Default taxation category', 'Default'); $this->createTaxRate($taxableGoods, 'Default Tax', 0.23, 'EU + USA GMT-8'); + $this->createTaxRate($taxableGoods, 'EU VAT', 0.23, 'EU'); $clothing = $this->createTaxCategory('Clothing', 'All clothing goods', 'Clothing'); $this->createTaxRate($clothing, 'Clothing US Tax', 0.20, 'USA GMT-8'); diff --git a/src/Sylius/Bundle/SandboxBundle/Entity/Order.php b/src/Sylius/Bundle/SandboxBundle/Entity/Order.php index a104b266..98abb352 100755 --- a/src/Sylius/Bundle/SandboxBundle/Entity/Order.php +++ b/src/Sylius/Bundle/SandboxBundle/Entity/Order.php @@ -16,10 +16,14 @@ use FOS\UserBundle\Model\UserInterface; use Sylius\Bundle\AddressingBundle\Model\AddressInterface; use Sylius\Bundle\SalesBundle\Entity\Order as BaseOrder; +use Sylius\Bundle\SalesBundle\Model\AdjustmentInterface; use Symfony\Component\Validator\Constraints as Assert; class Order extends BaseOrder { + // Label for tax adjustments. + const TAX_ADJUSTMENT = 'Tax'; + /** * Delivery address. * @@ -66,6 +70,31 @@ public function __construct() $this->addItem(new OrderItem()); } + public function getTaxTotal() + { + $taxTotal = 0; + + foreach ($this->getTaxAdjustments() as $adjustment) { + $taxTotal += $adjustment->getAmount(); + } + + return $taxTotal; + } + + public function getTaxAdjustments() + { + return $this->adjustments->filter(function (AdjustmentInterface $adjustment) { + return Order::TAX_ADJUSTMENT === $adjustment->getLabel(); + }); + } + + public function removeTaxAdjustments() + { + foreach ($this->getTaxAdjustments() as $adjustment) { + $this->removeAdjustment($adjustment); + } + } + public function getDeliveryAddress() { return $this->deliveryAddress; diff --git a/src/Sylius/Bundle/SandboxBundle/EventDispatcher/Listener/InventoryListener.php b/src/Sylius/Bundle/SandboxBundle/EventListener/InventoryListener.php similarity index 95% rename from src/Sylius/Bundle/SandboxBundle/EventDispatcher/Listener/InventoryListener.php rename to src/Sylius/Bundle/SandboxBundle/EventListener/InventoryListener.php index 23331cfb..5b73ad3f 100644 --- a/src/Sylius/Bundle/SandboxBundle/EventDispatcher/Listener/InventoryListener.php +++ b/src/Sylius/Bundle/SandboxBundle/EventListener/InventoryListener.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Sylius\Bundle\SandboxBundle\EventDispatcher\Listener; +namespace Sylius\Bundle\SandboxBundle\EventListener; use Sylius\Bundle\AssortmentBundle\EventDispatcher\Event\FilterProductEvent; use Sylius\Bundle\AssortmentBundle\EventDispatcher\Event\FilterVariantEvent; diff --git a/src/Sylius/Bundle/SandboxBundle/EventListener/OrderInventoryListener.php b/src/Sylius/Bundle/SandboxBundle/EventListener/OrderInventoryListener.php new file mode 100644 index 00000000..36558065 --- /dev/null +++ b/src/Sylius/Bundle/SandboxBundle/EventListener/OrderInventoryListener.php @@ -0,0 +1,69 @@ + + */ +class OrderInventoryListener +{ + protected $manager; + protected $inventoryOperator; + + /** + * Constructor. + * + * @param ObjectManager $manager + * @param InventoryOperatorInterface $inventoryOperator + */ + public function __construct( + ObjectManager $manager, + InventoryOperatorInterface $inventoryOperator + ) + { + $this->manager = $manager; + $this->inventoryOperator = $inventoryOperator; + } + + /** + * Process inventory based on order. + * + * @param FilterProductEvent $event + */ + public function processInventory(GenericEvent $event) + { + $order = $event->getSubject(); + $inventoryUnits = new ArrayCollection(); + + foreach ($order->getItems() as $item) { + $variant = $item->getVariant(); + + $units = $this->inventoryOperator->decrease($variant, $item->getQuantity()); + + foreach ($units as $unit) { + $inventoryUnits->add($unit); + } + + $this->manager->persist($variant); + } + + $order->setInventoryUnits($inventoryUnits); + } +} diff --git a/src/Sylius/Bundle/SandboxBundle/EventListener/OrderTaxationListener.php b/src/Sylius/Bundle/SandboxBundle/EventListener/OrderTaxationListener.php new file mode 100644 index 00000000..d883a0f2 --- /dev/null +++ b/src/Sylius/Bundle/SandboxBundle/EventListener/OrderTaxationListener.php @@ -0,0 +1,122 @@ + + */ +class OrderTaxationListener +{ + /** + * Zone matcher. + * + * @var ZoneMatcherInterface + */ + private $zoneMatcher; + + /** + * Tax rate resolver. + * + * @var TaxRateResolverInterface + */ + private $taxRateResolver; + + /** + * Tax calculator. + * + * @var TaxCalculatorInterface + */ + private $taxCalculator; + + /** + * Adjustment repository. + * + * @var ObjectRepository + */ + private $adjustmentRepository; + + /** + * Constructor. + * + * @param ZoneMatcherInterface $zoneMatcher + * @param TaxRateResolverInterface $taxRateResolver + * @param TaxCalculatorInterface $taxCalculator + * @param ObjectRepository $adjustmentRepository + * @param SettingsManagerInterface $settingsManager + */ + public function __construct( + ZoneMatcherInterface $zoneMatcher, + TaxRateResolverInterface $taxRateResolver, + TaxCalculatorInterface $taxCalculator, + ObjectRepository $adjustmentRepository, + SettingsManagerInterface $settingsManager + ) + { + $this->zoneMatcher = $zoneMatcher; + $this->taxRateResolver = $taxRateResolver; + $this->taxCalculator = $taxCalculator; + $this->adjustmentRepository = $adjustmentRepository; + $this->settingsManager = $settingsManager; + } + + /** + * Determine taxes. + * + * @param FilterProductEvent $event + */ + public function determineTaxes(GenericEvent $event) + { + $order = $event->getSubject(); + $order->removeTaxAdjustments(); // Remove all tax adjustments, we recalculate everything from scratch. + + $zone = $this->zoneMatcher->match($order->getDeliveryAddress()); + + if (null === $zone) { + $taxationSettings = $this->settingsManager->loadSettings('taxation'); + $zone = $taxationSettings['defaultTaxZone']; + } + + $taxTotal = 0; + + foreach ($order->getItems() as $item) { + $taxable = $item->getVariant()->getProduct(); + $rate = $this->taxRateResolver->resolve($taxable, array('zone' => $zone)); + + if (null === $rate) { + continue; + } + + $item->calculateTotal(); + + $taxTotal += $this->taxCalculator->calculate($item->getTotal(), $rate); + } + + $adjustment = $this->adjustmentRepository->createNew(); + + $adjustment->setLabel('Tax'); + $adjustment->setAmount($taxTotal); + + $order->addAdjustment($adjustment); + + $order->calculateTotal(); + } +} diff --git a/src/Sylius/Bundle/SandboxBundle/Menu/Builder.php b/src/Sylius/Bundle/SandboxBundle/Menu/Builder.php index e8bdb4a5..b0d0925f 100644 --- a/src/Sylius/Bundle/SandboxBundle/Menu/Builder.php +++ b/src/Sylius/Bundle/SandboxBundle/Menu/Builder.php @@ -391,6 +391,10 @@ protected function addConfigurationMenu(ItemInterface $menu, array $childOptions $this->addDivider($child); + $child->addChild('Configure taxation', array( + 'route' => 'sylius_sandbox_backend_settings_taxation_configure', + 'labelAttributes' => array('icon' => 'icon-cogs') + )); $child->addChild('Taxation categories', array( 'route' => 'sylius_sandbox_backend_tax_category_list', 'labelAttributes' => array('icon' => 'icon-tasks') diff --git a/src/Sylius/Bundle/SandboxBundle/Process/Step/FinalizeStep.php b/src/Sylius/Bundle/SandboxBundle/Process/Step/FinalizeStep.php index 1be470bb..d787aa0e 100644 --- a/src/Sylius/Bundle/SandboxBundle/Process/Step/FinalizeStep.php +++ b/src/Sylius/Bundle/SandboxBundle/Process/Step/FinalizeStep.php @@ -2,6 +2,7 @@ namespace Sylius\Bundle\SandboxBundle\Process\Step; +use Symfony\Component\EventDispatcher\GenericEvent; use Sylius\Bundle\FlowBundle\Process\Context\ProcessContextInterface; use Sylius\Bundle\FlowBundle\Process\Step\ContainerAwareStep; use Sylius\Bundle\SalesBundle\Model\OrderInterface; @@ -32,21 +33,19 @@ public function displayAction(ProcessContextInterface $context) public function forwardAction(ProcessContextInterface $context) { $order = $this->prepareOrder($context); - - $this->container->get('sylius_sales.manager.order')->persist($order); - $this->container->get('sylius_sales.manager.order')->persist($order); - - $orderBuilder = $this->container->get('sylius_sales.builder'); - $orderBuilder->finalize($order); + $this->save($order); $this->container->get('session')->setFlash('success', 'Your order has been saved, thank you!'); + $this->container->get('sylius_cart.provider')->abandonCart(); + return $this->complete(); } public function save(OrderInterface $order) { - $manager = $this->get('sylius_sales.manager.order'); + $manager = $this->container->get('sylius_sales.manager.order'); + $manager->persist($order); $manager->flush(); } @@ -71,6 +70,8 @@ private function prepareOrder(ProcessContextInterface $context) $orderBuilder = $this->container->get('sylius_sales.builder'); $orderBuilder->build($order); + $this->container->get('event_dispatcher')->dispatch('sylius_sales.order.pre_create', new GenericEvent($order)); + return $order; } diff --git a/src/Sylius/Bundle/SandboxBundle/Resources/config/doctrine/Order.orm.xml b/src/Sylius/Bundle/SandboxBundle/Resources/config/doctrine/Order.orm.xml index 7cc9aefb..fcb977fa 100755 --- a/src/Sylius/Bundle/SandboxBundle/Resources/config/doctrine/Order.orm.xml +++ b/src/Sylius/Bundle/SandboxBundle/Resources/config/doctrine/Order.orm.xml @@ -14,6 +14,11 @@ + + + + + diff --git a/src/Sylius/Bundle/SandboxBundle/Resources/config/doctrine/OrderItem.orm.xml b/src/Sylius/Bundle/SandboxBundle/Resources/config/doctrine/OrderItem.orm.xml index 0d89db28..ba0aa490 100755 --- a/src/Sylius/Bundle/SandboxBundle/Resources/config/doctrine/OrderItem.orm.xml +++ b/src/Sylius/Bundle/SandboxBundle/Resources/config/doctrine/OrderItem.orm.xml @@ -9,6 +9,11 @@ + + + + + diff --git a/src/Sylius/Bundle/SandboxBundle/Resources/config/routing/backend/settings.yml b/src/Sylius/Bundle/SandboxBundle/Resources/config/routing/backend/settings.yml index 6498a140..41f8c154 100644 --- a/src/Sylius/Bundle/SandboxBundle/Resources/config/routing/backend/settings.yml +++ b/src/Sylius/Bundle/SandboxBundle/Resources/config/routing/backend/settings.yml @@ -7,3 +7,10 @@ sylius_sandbox_backend_settings_general_configure: _controller: sylius_settings.controller:configureAction namespace: general template: SyliusSandboxBundle:Backend/Settings:general.html.twig + +sylius_sandbox_backend_settings_taxation_configure: + pattern: /taxation + defaults: + _controller: sylius_settings.controller:configureAction + namespace: taxation + template: SyliusSandboxBundle:Backend/Settings:taxation.html.twig diff --git a/src/Sylius/Bundle/SandboxBundle/Resources/config/services.xml b/src/Sylius/Bundle/SandboxBundle/Resources/config/services.xml index 731a430a..a386fd72 100644 --- a/src/Sylius/Bundle/SandboxBundle/Resources/config/services.xml +++ b/src/Sylius/Bundle/SandboxBundle/Resources/config/services.xml @@ -22,6 +22,12 @@ Sylius\Bundle\SandboxBundle\Form\Type\ProductVariantsGridLineType Sylius\Bundle\SandboxBundle\Settings\GeneralSettingsSchema + Sylius\Bundle\SandboxBundle\Settings\TaxationSettingsSchema + + Sylius\Bundle\SandboxBundle\EventListener\OrderTaxationListener + Sylius\Bundle\SandboxBundle\EventListener\OrderInventoryListener + + Sylius\Bundle\SandboxBundle\Taxation\TaxRateResolver @@ -55,9 +61,9 @@ - - - + + + @@ -76,6 +82,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Sylius/Bundle/SandboxBundle/Resources/views/Backend/Order/show.html.twig b/src/Sylius/Bundle/SandboxBundle/Resources/views/Backend/Order/show.html.twig index bcaf3ef1..c09dda50 100755 --- a/src/Sylius/Bundle/SandboxBundle/Resources/views/Backend/Order/show.html.twig +++ b/src/Sylius/Bundle/SandboxBundle/Resources/views/Backend/Order/show.html.twig @@ -20,6 +20,14 @@ total {{ order.total }} € + + items total + {{ order.itemsTotal }} € + + + tax total + {{ order.taxTotal }} € + user @@ -151,9 +159,15 @@ {% set product = variant.product %} {{ loop.index }} - {{ variant.sku }} -

{{ product.name }}

+ + {{ variant.sku }} + + + +

+ {{ product.name }} +

{% if product.hasOptions %}
    {% for option in variant.options %} @@ -175,6 +189,31 @@ {% endfor %} + + Tax total + + + {{ order.taxTotal }} € + + + + {# + {% if order.adjustments|length > 0 %} + + Adjustments + + {% for adjustment in order.adjustments %} + + {{ adjustment.label }} + + + {{ adjustment.amount }} € + + + + {% endfor %} + {% endif %} + #} diff --git a/src/Sylius/Bundle/SandboxBundle/Resources/views/Backend/Settings/:w b/src/Sylius/Bundle/SandboxBundle/Resources/views/Backend/Settings/:w deleted file mode 100644 index 16a6b487..00000000 --- a/src/Sylius/Bundle/SandboxBundle/Resources/views/Backend/Settings/:w +++ /dev/null @@ -1,23 +0,0 @@ -{% extends 'SyliusSandboxBundle:Backend:layout.html.twig' %} - -{% block header %} -

    General settings General store configuration

    -{% endblock %} - -{% block content %} -
    - {{ form_errors(form) }} - {{ form_row(form.siteName, {'attr': {'class': 'input-xlarge'}}) }} - {{ form_row(form.siteUrl, {'attr': {'class': 'input-large'}}) }} -
    - {{ form_row(form.defaultMetaTitle, {'attr': {'class': 'input-xlarge'}}) }} - {{ form_row(form.defaultMetaKeywords, {'attr': {'class': 'input-xlarge'}}) }} - {{ form_row(form.defaultMetaDescription, {'attr': {'class': 'input-xxlarge'}}) }} - {{ form_rest(form) }} -
    - -   - -
    -
    -{% endblock %} diff --git a/src/Sylius/Bundle/SandboxBundle/Resources/views/Backend/Settings/taxation.html.twig b/src/Sylius/Bundle/SandboxBundle/Resources/views/Backend/Settings/taxation.html.twig new file mode 100644 index 00000000..f0177034 --- /dev/null +++ b/src/Sylius/Bundle/SandboxBundle/Resources/views/Backend/Settings/taxation.html.twig @@ -0,0 +1,18 @@ +{% extends 'SyliusSandboxBundle:Backend:layout.html.twig' %} + +{% block header %} +

    Taxation settings

    +{% endblock %} + +{% block content %} +
    + {{ form_errors(form) }} + {{ form_row(form.defaultTaxZone, {'attr': {'class': 'input-xlarge select2'}}) }} + {{ form_rest(form) }} +
    + +   + +
    +
    +{% endblock %} diff --git a/src/Sylius/Bundle/SandboxBundle/Resources/views/Frontend/Checkout/Step/finalize.html.twig b/src/Sylius/Bundle/SandboxBundle/Resources/views/Frontend/Checkout/Step/finalize.html.twig index bcc18471..f4582e2f 100644 --- a/src/Sylius/Bundle/SandboxBundle/Resources/views/Frontend/Checkout/Step/finalize.html.twig +++ b/src/Sylius/Bundle/SandboxBundle/Resources/views/Frontend/Checkout/Step/finalize.html.twig @@ -131,6 +131,14 @@ {% endfor %} + + Tax total + + + {{ order.taxTotal }} € + + + diff --git a/src/Sylius/Bundle/SandboxBundle/Settings/GeneralSettingsSchema.php b/src/Sylius/Bundle/SandboxBundle/Settings/GeneralSettingsSchema.php index bddc4c8b..ca4e96f1 100644 --- a/src/Sylius/Bundle/SandboxBundle/Settings/GeneralSettingsSchema.php +++ b/src/Sylius/Bundle/SandboxBundle/Settings/GeneralSettingsSchema.php @@ -2,7 +2,7 @@ namespace Sylius\Bundle\SandboxBundle\Settings; -use Sylius\Bundle\SettingsBundle\Schema\SchemaInterface; +use Sylius\Bundle\SettingsBundle\Schema\Schema; use Symfony\Component\Form\FormBuilderInterface; /** @@ -10,16 +10,8 @@ * * @author Paweł Jędrzejewski */ -class GeneralSettingsSchema implements SchemaInterface +class GeneralSettingsSchema extends Schema { - /** - * {@inheritdoc} - */ - public function getNamespace() - { - return 'general'; - } - /** * {@inheritdoc} */ diff --git a/src/Sylius/Bundle/SandboxBundle/Settings/TaxationSettingsSchema.php b/src/Sylius/Bundle/SandboxBundle/Settings/TaxationSettingsSchema.php new file mode 100644 index 00000000..dc5be376 --- /dev/null +++ b/src/Sylius/Bundle/SandboxBundle/Settings/TaxationSettingsSchema.php @@ -0,0 +1,45 @@ + + */ +class TaxationSettingsSchema extends Schema +{ + private $zoneRepository; + + public function __construct(ObjectRepository $zoneRepository) + { + $this->zoneRepository = $zoneRepository; + } + + /** + * {@inheritdoc} + */ + public function getDataTransformers() + { + return array( + 'defaultTaxZone' => new ZoneToIdentifierTransformer($this->zoneRepository, 'id') + ); + } + + /** + * {@inheritdoc} + */ + public function build(FormBuilderInterface $builder) + { + $builder + ->add('defaultTaxZone', 'sylius_addressing_zone_choice', array( + 'label' => 'Default tax zone' + )) + ; + } +} diff --git a/src/Sylius/Bundle/SandboxBundle/Taxation/TaxRateResolver.php b/src/Sylius/Bundle/SandboxBundle/Taxation/TaxRateResolver.php new file mode 100644 index 00000000..b6d75878 --- /dev/null +++ b/src/Sylius/Bundle/SandboxBundle/Taxation/TaxRateResolver.php @@ -0,0 +1,41 @@ + + */ +class TaxRateResolver extends BaseTaxRateResolver +{ + /** + * {@inheritdoc} + */ + public function resolve(TaxableInterface $taxable, array $context = array()) + { + if (null === $category = $taxable->getTaxCategory()) { + return; + } + + $zone = $context['zone']; + + return $this->taxRateRepository->findOneBy(array( + 'category' => $category, + 'zone' => $zone + )); + } +} +