Implemented behat steps for deleting a coupon

This commit is contained in:
Jan Goralski 2016-02-29 10:18:00 +01:00
parent 8b28715dfb
commit cb97c955d9
22 changed files with 635 additions and 24 deletions

View file

@ -0,0 +1,38 @@
<?php
namespace Sylius\Migrations;
use Doctrine\DBAL\Migrations\AbstractMigration;
use Doctrine\DBAL\Schema\Schema;
/**
* Auto-generated Migration: Please modify to your needs!
*/
class Version20160305115221 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_promotion_coupon DROP deleted_at');
$this->addSql('ALTER TABLE sylius_order DROP FOREIGN KEY FK_6196A1F917B24436');
$this->addSql('ALTER TABLE sylius_order ADD CONSTRAINT FK_6196A1F917B24436 FOREIGN KEY (promotion_coupon_id) REFERENCES sylius_promotion_coupon (id)');
}
/**
* @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 FOREIGN KEY FK_6196A1F917B24436');
$this->addSql('ALTER TABLE sylius_order ADD CONSTRAINT FK_6196A1F917B24436 FOREIGN KEY (promotion_coupon_id) REFERENCES sylius_promotion_coupon (id) ON DELETE SET NULL');
$this->addSql('ALTER TABLE sylius_promotion_coupon ADD deleted_at DATETIME DEFAULT NULL');
}
}

View file

@ -42,5 +42,6 @@ imports:
- suites/domain/order.yml
- suites/domain/product.yml
- suites/domain/promotion.yml
- suites/cli/installer.yml

View file

@ -0,0 +1,28 @@
# This file is part of the Sylius package.
# (c) Paweł Jędrzejewski
default:
suites:
domain_promotion:
contexts_as_services:
- sylius.behat.context.hook.doctrine_orm
- sylius.behat.context.transform.shared_storage
- sylius.behat.context.transform.addressing
- sylius.behat.context.transform.customer
- sylius.behat.context.transform.payment
- sylius.behat.context.transform.product
- sylius.behat.context.transform.promotion
- sylius.behat.context.transform.shipping
- sylius.behat.context.setup.channel
- sylius.behat.context.setup.payment
- sylius.behat.context.setup.product
- sylius.behat.context.setup.promotion
- sylius.behat.context.setup.shipping
- sylius.behat.context.setup.order
- sylius.behat.context.domain.promotion
filters:
tags: @promotion && @domain

View file

@ -6,10 +6,9 @@ Feature: Deleting a coupon
Background:
Given the store operates on a single channel in "France"
And there is a promotion "Holiday promotion" with coupon "Santa's gift"
And I am logged in as administrator
And the store has promotion "Christmas sale" with coupon "Santa's gift"
@todo
@domain
Scenario: Deleted coupon should disappear from the registry
When I delete "Santa's Gift" coupon
Then this coupon should no longer exist in the registry

View file

@ -8,13 +8,14 @@ Feature: Not being able to delete a coupon which is in use
Given the store operates on a single channel in "France"
And the store ships everywhere for free
And the store has a product "Jacket"
And the store allows paying with "Cash on Delivery"
And the store has promotion "Christmas sale" with coupon "Santa's gift"
And the customer "john.doe@gmail.com" placed an order "#00000022"
And the customer chose "Free" shipping method to "France" with "Cash on Delivery" payment
And the customer bought single "Jacket" using "Santa's gift" coupon
@todo
@domain
Scenario: Being unable to delete a used coupon
When I try to delete "Santa's gift" coupon
Then And I should be notified that it is in use and cannot be deleted
When I delete "Santa's gift" coupon
Then I should be notified that it is in use and cannot be deleted
And this coupon should still exist in the registry

View file

@ -0,0 +1,93 @@
<?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\Behat\Context\Domain;
use Behat\Behat\Context\Context;
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
use Sylius\Component\Core\Test\Services\SharedStorageInterface;
use Sylius\Component\Promotion\Model\CouponInterface;
use Sylius\Component\Promotion\Repository\PromotionRepositoryInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
/**
* @author Jan Góralski <jan.goralski@lakion.com>
*/
final class PromotionContext implements Context
{
/**
* @var SharedStorageInterface
*/
private $sharedStorage;
/**
* @var PromotionRepositoryInterface
*/
private $promotionRepository;
/**
* @var RepositoryInterface
*/
private $couponRepository;
/**
* @param SharedStorageInterface $sharedStorage
* @param PromotionRepositoryInterface $promotionRepository
* @param RepositoryInterface $couponRepository
*/
public function __construct(
SharedStorageInterface $sharedStorage,
PromotionRepositoryInterface $promotionRepository,
RepositoryInterface $couponRepository
) {
$this->sharedStorage = $sharedStorage;
$this->promotionRepository = $promotionRepository;
$this->couponRepository = $couponRepository;
}
/**
* @When /^I delete ("([^"]+)" coupon)$/
*/
public function iDeleteCoupon(CouponInterface $coupon)
{
try {
$this->couponRepository->remove($coupon);
} catch(ForeignKeyConstraintViolationException $exception) {
$this->sharedStorage->set('exception', $exception);
}
}
/**
* @Then /^([^"]+) should no longer exist in the registry$/
*/
public function couponShouldNotExistInTheRegistry(CouponInterface $coupon)
{
expect($this->couponRepository->find($coupon->getId()))->toBe(null);
}
/**
* @Then I should be notified that it is in use and cannot be deleted
*/
public function iShouldBeNotified()
{
expect($this->sharedStorage->get('exception'))
->toReturnAnInstanceOf(ForeignKeyConstraintViolationException::class)
;
}
/**
* @Then /^([^"]+) should still exist in the registry$/
*/
public function couponShouldStillExistInTheRegistry(CouponInterface $coupon)
{
expect($this->couponRepository->find($coupon->getId()))->toNotBe(null);
}
}

View file

@ -13,6 +13,8 @@ namespace Sylius\Behat\Context\Setup;
use Behat\Behat\Context\Context;
use Doctrine\Common\Persistence\ObjectManager;
use Sylius\Component\Core\Model\CouponInterface;
use Sylius\Component\Core\OrderProcessing\OrderRecalculatorInterface;
use Sylius\Component\Order\Modifier\OrderItemQuantityModifierInterface;
use Sylius\Component\Core\Model\AddressInterface;
use Sylius\Component\Core\Model\OrderInterface;
@ -74,6 +76,11 @@ final class OrderContext implements Context
*/
private $shippingChargesProcessor;
/**
* @var OrderRecalculatorInterface
*/
private $orderRecalculator;
/**
* @var ObjectManager
*/
@ -88,6 +95,8 @@ final class OrderContext implements Context
* @param FactoryInterface $orderItemFactory
* @param OrderItemQuantityModifierInterface $itemQuantityModifier
* @param ShippingChargesProcessorInterface $shippingChargesProcessor
* @param SharedStorageInterface $sharedStorage
* @param OrderRecalculatorInterface $orderRecalculator
* @param ObjectManager $objectManager
*/
public function __construct(
@ -99,6 +108,7 @@ final class OrderContext implements Context
FactoryInterface $orderItemFactory,
OrderItemQuantityModifierInterface $itemQuantityModifier,
ShippingChargesProcessorInterface $shippingChargesProcessor,
OrderRecalculatorInterface $orderRecalculator,
ObjectManager $objectManager
) {
$this->sharedStorage = $sharedStorage;
@ -109,6 +119,7 @@ final class OrderContext implements Context
$this->orderItemFactory = $orderItemFactory;
$this->itemQuantityModifier = $itemQuantityModifier;
$this->shippingChargesProcessor = $shippingChargesProcessor;
$this->orderRecalculator = $orderRecalculator;
$this->objectManager = $objectManager;
}
@ -193,4 +204,26 @@ final class OrderContext implements Context
$this->objectManager->flush();
}
/**
* @Given the customer bought single :product using :coupon coupon
*/
public function theCustomerBoughtSingleUsing(ProductInterface $product, CouponInterface $coupon)
{
/** @var OrderInterface $order */
$order = $this->sharedStorage->get('order');
/** @var OrderItemInterface $item */
$item = $this->orderItemFactory->createNew();
$item->setVariant($product->getMasterVariant());
$item->setUnitPrice($product->getPrice());
$this->itemQuantityModifier->modify($item, 1);
$order->setPromotionCoupon($coupon);
$order->addItem($item);
$this->orderRecalculator->recalculate($order);
$this->objectManager->flush();
}
}

View file

@ -20,6 +20,8 @@ use Sylius\Component\Core\Model\TaxonInterface;
use Sylius\Component\Core\Test\Factory\TestPromotionFactoryInterface;
use Sylius\Component\Core\Test\Services\SharedStorageInterface;
use Sylius\Component\Promotion\Model\ActionInterface;
use Sylius\Component\Promotion\Factory\CouponFactoryInterface;
use Sylius\Component\Promotion\Model\CouponInterface;
use Sylius\Component\Promotion\Repository\PromotionRepositoryInterface;
/**
@ -37,6 +39,11 @@ final class PromotionContext implements Context
*/
private $actionFactory;
/**
* @var CouponFactoryInterface
*/
private $couponFactory;
/**
* @var RuleFactoryInterface
*/
@ -60,6 +67,7 @@ final class PromotionContext implements Context
/**
* @param SharedStorageInterface $sharedStorage
* @param ActionFactoryInterface $actionFactory
* @param CouponFactoryInterface $couponFactory
* @param RuleFactoryInterface $ruleFactory
* @param TestPromotionFactoryInterface $testPromotionFactory
* @param PromotionRepositoryInterface $promotionRepository
@ -68,6 +76,7 @@ final class PromotionContext implements Context
public function __construct(
SharedStorageInterface $sharedStorage,
ActionFactoryInterface $actionFactory,
CouponFactoryInterface $couponFactory,
RuleFactoryInterface $ruleFactory,
TestPromotionFactoryInterface $testPromotionFactory,
PromotionRepositoryInterface $promotionRepository,
@ -75,6 +84,7 @@ final class PromotionContext implements Context
) {
$this->sharedStorage = $sharedStorage;
$this->actionFactory = $actionFactory;
$this->couponFactory = $couponFactory;
$this->ruleFactory = $ruleFactory;
$this->testPromotionFactory = $testPromotionFactory;
$this->promotionRepository = $promotionRepository;
@ -94,6 +104,26 @@ final class PromotionContext implements Context
$this->sharedStorage->set('promotion', $promotion);
}
/**
* @Given the store has promotion :promotionName with coupon :couponCode
*/
public function thereIsPromotionWithCoupon($promotionName, $couponCode)
{
/** @var CouponInterface $coupon */
$coupon = $this->couponFactory->createNew();
$coupon->setCode($couponCode);
$promotion = $this->testPromotionFactory
->createForChannel($promotionName, $this->sharedStorage->get('channel'))
;
$promotion->addCoupon($coupon);
$promotion->setCouponBased(true);
$this->promotionRepository->add($promotion);
$this->sharedStorage->set('promotion', $promotion);
$this->sharedStorage->set('coupon', $coupon);
}
/**
* @Given /^([^"]+) gives ("[^"]+") fixed discount to every order$/
*/

View file

@ -0,0 +1,78 @@
<?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\Behat\Context\Transform;
use Behat\Behat\Context\Context;
use Sylius\Component\Promotion\Repository\PromotionRepositoryInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
/**
* @author Jan Góralski <jan.goralski@lakion.com>
*/
final class PromotionContext implements Context
{
/**
* @var PromotionRepositoryInterface
*/
private $promotionRepository;
/**
* @var RepositoryInterface
*/
private $couponRepository;
/**
* @param PromotionRepositoryInterface $promotionRepository
* @param RepositoryInterface $couponRepository
*/
public function __construct(
PromotionRepositoryInterface $promotionRepository,
RepositoryInterface $couponRepository
) {
$this->promotionRepository = $promotionRepository;
$this->couponRepository = $couponRepository;
}
/**
* @Transform /^promotion "([^"]+)"$/
* @Transform /^"([^"]+)" promotion$/
* @Transform :promotion
*/
public function getPromotionByName($promotionName)
{
$promotion = $this->promotionRepository->findOneBy(['name' => $promotionName]);
if (null === $promotion) {
throw new \InvalidArgumentException(
sprintf('Promotion with name "%s" does not exist in the promotion repository.', $promotionName)
);
}
return $promotion;
}
/**
* @Transform /^coupon "([^"]+)"$/
* @Transform /^"([^"]+)" coupon$/
* @Transform :coupon
*/
public function getCouponByCode($couponCode)
{
$coupon = $this->couponRepository->findOneBy(['code' => $couponCode]);
if (null === $coupon) {
throw new \InvalidArgumentException(
sprintf('Coupon with code "%s" does not exist in the coupon repository.', $couponCode)
);
}
return $coupon;
}
}

View file

@ -12,8 +12,6 @@
namespace spec\Sylius\Behat\Context\Domain;
use Behat\Behat\Context\Context;
use Behat\Mink\Exception\ExpectationException;
use Behat\Mink\Tests\Exception\ExpectationExceptionTest;
use PhpSpec\Exception\Example\NotEqualException;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;

View file

@ -0,0 +1,98 @@
<?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 spec\Sylius\Behat\Context\Domain;
use Behat\Behat\Context\Context;
use PhpSpec\Exception\Example\FailureException;
use PhpSpec\Exception\Example\NotEqualException;
use PhpSpec\ObjectBehavior;
use Sylius\Component\Core\Repository\PromotionRepositoryInterface;
use Sylius\Component\Core\Test\Services\SharedStorageInterface;
use Sylius\Component\Promotion\Model\CouponInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
/**
* @author Jan Góralski <jan.goralski@lakion.com>
*/
class PromotionContextSpec extends ObjectBehavior
{
function let(
SharedStorageInterface $sharedStorage,
PromotionRepositoryInterface $promotionRepository,
RepositoryInterface $couponRepository
) {
$this->beConstructedWith($sharedStorage, $promotionRepository, $couponRepository);
}
function it_is_initializable()
{
$this->shouldHaveType('Sylius\Behat\Context\Domain\PromotionContext');
}
function it_implements_context_interface()
{
$this->shouldImplement(Context::class);
}
function it_removes_a_coupon(RepositoryInterface $couponRepository, CouponInterface $coupon)
{
$couponRepository->remove($coupon)->shouldBeCalled();
$this->iDeleteCoupon($coupon);
}
function it_checks_whether_a_coupon_is_not_in_the_registry(
RepositoryInterface $couponRepository,
CouponInterface $coupon
) {
$coupon->getId()->willReturn(5);
$couponRepository->find(5)->willReturn(null);
$this->couponShouldNotExistInTheRegistry($coupon);
}
function it_throws_exception_when_a_coupon_is_found_when_it_should_not(
RepositoryInterface $couponRepository,
CouponInterface $coupon
) {
$coupon->getId()->willReturn(5);
$couponRepository->find(5)->willReturn($coupon);
$this
->shouldThrow(NotEqualException::class)
->during('couponShouldNotExistInTheRegistry', [$coupon])
;
}
function it_checks_whether_a_coupon_is_in_the_registry(
RepositoryInterface $couponRepository,
CouponInterface $coupon
) {
$coupon->getId()->willReturn(5);
$couponRepository->find(5)->willReturn($coupon);
$this->couponShouldStillExistInTheRegistry($coupon);
}
function it_throws_exception_when_a_coupon_is_not_found_when_it_should(
RepositoryInterface $couponRepository,
CouponInterface $coupon
) {
$coupon->getId()->willReturn(5);
$couponRepository->find(5)->willReturn(null);
$this
->shouldThrow(FailureException::class)
->during('couponShouldStillExistInTheRegistry', [$coupon])
;
}
}

View file

@ -15,10 +15,12 @@ use Behat\Behat\Context\Context;
use Doctrine\Common\Collections\Collection;
use Doctrine\Common\Persistence\ObjectManager;
use PhpSpec\ObjectBehavior;
use Sylius\Component\Core\OrderProcessing\OrderRecalculatorInterface;
use Sylius\Component\Order\Modifier\OrderItemQuantityModifierInterface;
use Sylius\Behat\Context\Setup\OrderContext;
use Sylius\Component\Core\Model\AddressInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Core\Model\CouponInterface;
use Sylius\Component\Core\Model\CustomerInterface;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\OrderItemInterface;
@ -52,6 +54,7 @@ class OrderContextSpec extends ObjectBehavior
FactoryInterface $orderItemFactory,
OrderItemQuantityModifierInterface $itemQuantityModifier,
ShippingChargesProcessorInterface $chargesProcessor,
OrderRecalculatorInterface $orderRecalculator,
ObjectManager $objectManager
) {
$this->beConstructedWith(
@ -63,6 +66,7 @@ class OrderContextSpec extends ObjectBehavior
$orderItemFactory,
$itemQuantityModifier,
$chargesProcessor,
$orderRecalculator,
$objectManager
);
}
@ -185,4 +189,37 @@ class OrderContextSpec extends ObjectBehavior
$this->theCustomerBoughtSingleProductVariant($variant);
}
function it_adds_single_item_by_customer_and_applies_a_coupon(
FactoryInterface $orderItemFactory,
OrderInterface $order,
OrderItemInterface $item,
OrderItemQuantityModifierInterface $itemQuantityModifier,
ProductInterface $product,
CouponInterface $coupon,
SharedStorageInterface $sharedStorage,
ProductVariantInterface $variant,
OrderRecalculatorInterface $orderRecalculator,
ObjectManager $objectManager
) {
$sharedStorage->get('order')->willReturn($order);
$orderItemFactory->createNew()->willReturn($item);
$product->getMasterVariant()->willReturn($variant);
$product->getPrice()->willReturn(1234);
$itemQuantityModifier->modify($item, 1)->shouldBeCalled();
$item->setVariant($variant)->shouldBeCalled();
$item->setUnitPrice(1234)->shouldBeCalled();
$order->setPromotionCoupon($coupon)->shouldBeCalled();
$order->addItem($item)->shouldBeCalled();
$orderRecalculator->recalculate($order)->shouldBeCalled();
$objectManager->flush()->shouldBeCalled();
$this->theCustomerBoughtSingleUsing($product, $coupon);
}
}

View file

@ -17,10 +17,12 @@ use PhpSpec\ObjectBehavior;
use Sylius\Component\Core\Factory\ActionFactoryInterface;
use Sylius\Component\Core\Factory\RuleFactoryInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Core\Model\CouponInterface;
use Sylius\Component\Core\Model\PromotionInterface;
use Sylius\Component\Core\Model\TaxonInterface;
use Sylius\Component\Core\Test\Factory\TestPromotionFactoryInterface;
use Sylius\Component\Core\Test\Services\SharedStorageInterface;
use Sylius\Component\Promotion\Factory\CouponFactoryInterface;
use Sylius\Component\Promotion\Model\ActionInterface;
use Sylius\Component\Promotion\Model\RuleInterface;
use Sylius\Component\Promotion\Repository\PromotionRepositoryInterface;
@ -33,6 +35,7 @@ class PromotionContextSpec extends ObjectBehavior
function let(
SharedStorageInterface $sharedStorage,
ActionFactoryInterface $actionFactory,
CouponFactoryInterface $couponFactory,
RuleFactoryInterface $ruleFactory,
TestPromotionFactoryInterface $testPromotionFactory,
PromotionRepositoryInterface $promotionRepository,
@ -41,6 +44,7 @@ class PromotionContextSpec extends ObjectBehavior
$this->beConstructedWith(
$sharedStorage,
$actionFactory,
$couponFactory,
$ruleFactory,
$testPromotionFactory,
$promotionRepository,
@ -75,6 +79,33 @@ class PromotionContextSpec extends ObjectBehavior
$this->thereIsPromotion('Super promotion');
}
function it_creates_promotion_with_coupon(
SharedStorageInterface $sharedStorage,
TestPromotionFactoryInterface $testPromotionFactory,
PromotionRepositoryInterface $promotionRepository,
CouponFactoryInterface $couponFactory,
RepositoryInterface $couponRepository,
ChannelInterface $channel,
CouponInterface $coupon,
PromotionInterface $promotion
) {
$couponFactory->createNew()->willReturn($coupon);
$coupon->setCode('Coupon galore')->shouldBeCalled();
$sharedStorage->get('channel')->willReturn($channel);
$testPromotionFactory->createForChannel('Promotion galore', $channel)->willReturn($promotion);
$promotion->addCoupon($coupon)->shouldBeCalled();
$promotion->setCouponBased(true)->shouldBeCalled();
$promotionRepository->add($promotion)->shouldBeCalled();
$sharedStorage->set('promotion', $promotion)->shouldBeCalled();
$couponRepository->add($coupon)->shouldBeCalled();
$sharedStorage->set('coupon', $coupon)->shouldBeCalled();
$this->thereIsPromotionWithCoupon('Promotion galore', 'Coupon galore');
}
function it_creates_fixed_discount_action_for_promotion(
ActionFactoryInterface $actionFactory,
ActionInterface $action,

View file

@ -0,0 +1,74 @@
<?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 spec\Sylius\Behat\Context\Transform;
use Behat\Behat\Context\Context;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\Component\Promotion\Model\CouponInterface;
use Sylius\Component\Promotion\Model\PromotionInterface;
use Sylius\Component\Promotion\Repository\PromotionRepositoryInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
/**
* @author Jan Góralski <jan.goralski@lakion.com>
*/
class PromotionContextSpec extends ObjectBehavior
{
function let(PromotionRepositoryInterface $promotionRepository, RepositoryInterface $couponRepository)
{
$this->beConstructedWith($promotionRepository, $couponRepository);
}
function it_is_initializable()
{
$this->shouldHaveType('Sylius\Behat\Context\Transform\PromotionContext');
}
function it_implements_context_interface()
{
$this->shouldImplement(Context::class);
}
function it_gets_promotion_by_its_name(
PromotionRepositoryInterface $promotionRepository,
PromotionInterface $promotion
) {
$promotion->getName()->willReturn('Best Promotion');
$promotionRepository->findOneBy(['name' => 'Best Promotion'])->willReturn($promotion);
$this->getPromotionByName('Best Promotion');
}
function it_throws_exception_when_promotion_with_given_name_was_not_found(
PromotionRepositoryInterface $promotionRepository
) {
$promotionRepository->findOneBy(['name' => 'Wrong Promotion'])->willReturn(null);
$this->shouldThrow(\InvalidArgumentException::class)->during('getPromotionByName', ['Wrong Promotion']);
}
function it_gets_coupon_by_its_code(RepositoryInterface $couponRepository, CouponInterface $coupon)
{
$coupon->getCode()->willReturn('BEST-CODE');
$couponRepository->findOneBy(['code' => 'BEST-CODE'])->willReturn($coupon);
$this->getCouponByCode('BEST-CODE');
}
function it_throws_exception_when_coupon_with_given_code_was_not_found(RepositoryInterface $couponRepository)
{
$couponRepository->findOneBy(['code' => 'NO-CODE'])->willReturn(null);
$this->shouldThrow(\InvalidArgumentException::class)->during('getCouponByCode', ['NO-CODE']);
}
}

View file

@ -37,7 +37,7 @@
</one-to-one>
<many-to-one field="promotionCoupon" target-entity="Sylius\Component\Promotion\Model\CouponInterface">
<join-column name="promotion_coupon_id" on-delete="SET NULL" />
<join-column name="promotion_coupon_id" />
<cascade>
<cascade-persist />
</cascade>

View file

@ -38,6 +38,7 @@
<parameter key="sylius.order_processing.shipment_processor.class">Sylius\Component\Core\OrderProcessing\OrderShipmentProcessor</parameter>
<parameter key="sylius.order_processing.payment_processor.class">Sylius\Component\Core\OrderProcessing\PaymentProcessor</parameter>
<parameter key="sylius.order_processing.shipping_processor.class">Sylius\Component\Core\OrderProcessing\ShippingChargesProcessor</parameter>
<parameter key="sylius.order_processing.order_recalculator.class">Sylius\Component\Core\OrderProcessing\OrderRecalculator</parameter>
<parameter key="sylius.taxation.order_taxes_applicator.class">Sylius\Component\Core\Taxation\OrderTaxesApplicator</parameter>
<parameter key="sylius.taxation.order_shipment_taxes_by_zone_applicator.class">Sylius\Component\Core\Taxation\OrderShipmentTaxesByZoneApplicator</parameter>
@ -262,6 +263,12 @@
<argument type="service" id="sylius.shipping_calculator" />
</service>
<service id="sylius.order_processing.order_recalculator" class="%sylius.order_processing.order_recalculator.class%">
<argument type="service" id="sylius.promotion_processor" />
<argument type="service" id="sylius.taxation.order_taxes_applicator" />
<argument type="service" id="sylius.order_processing.shipping_processor" />
</service>
<service id="sylius.order.purger" class="%sylius.order.purger.class%">
<argument type="service" id="sylius.manager.order" />
<argument type="service" id="sylius.repository.order" />

View file

@ -34,9 +34,6 @@
<field name="updatedAt" column="updated_at" type="datetime" nullable="true">
<gedmo:timestampable on="update"/>
</field>
<field name="deletedAt" column="deleted_at" type="datetime" nullable="true" />
<gedmo:soft-deleteable field-name="deletedAt" />
</mapped-superclass>
</doctrine-mapping>

View file

@ -57,16 +57,11 @@ class OrderRecalculator implements OrderRecalculatorInterface
*/
public function recalculate(OrderInterface $order)
{
if (null === $order) {
return;
if (!empty($order->getPromotions())) {
$this->promotionProcessor->process($order);
}
$this->taxesApplicator->apply($order);
$this->shippingChargesProcessor->applyShippingCharges($order);
if (empty($promotions = $order->getPromotions())) {
return;
}
$this->promotionProcessor->process($order);
}
}

View file

@ -0,0 +1,74 @@
<?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 spec\Sylius\Component\Core\OrderProcessing;
use PhpSpec\ObjectBehavior;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\OrderProcessing\OrderRecalculatorInterface;
use Sylius\Component\Core\OrderProcessing\ShippingChargesProcessorInterface;
use Sylius\Component\Core\Taxation\OrderTaxesApplicatorInterface;
use Sylius\Component\Promotion\Model\PromotionInterface;
use Sylius\Component\Promotion\Processor\PromotionProcessorInterface;
/**
* @author Jan Góralski <jan.goralski@lakion.com>
*/
class OrderRecalculatorSpec extends ObjectBehavior
{
function let(
PromotionProcessorInterface $promotionProcessor,
OrderTaxesApplicatorInterface $taxesApplicator,
ShippingChargesProcessorInterface $shippingChargesProcessor
) {
$this->beConstructedWith($promotionProcessor, $taxesApplicator, $shippingChargesProcessor);
}
function it_is_initializable()
{
$this->shouldHaveType('Sylius\Component\Core\OrderProcessing\OrderRecalculator');
}
function it_implements_order_recalculator_interface()
{
$this->shouldImplement(OrderRecalculatorInterface::class);
}
function it_recalculates_order_promotions_taxes_and_shipping_charges(
PromotionProcessorInterface $promotionProcessor,
OrderTaxesApplicatorInterface $taxesApplicator,
ShippingChargesProcessorInterface $shippingChargesProcessor,
OrderInterface $order,
PromotionInterface $firstPromotion,
PromotionInterface $secondPromotion
) {
$order->getPromotions()->willReturn([$firstPromotion, $secondPromotion]);
$promotionProcessor->process($order)->shouldBeCalled();
$taxesApplicator->apply($order)->shouldBeCalled();
$shippingChargesProcessor->applyShippingCharges($order)->shouldBeCalled();
$this->recalculate($order);
}
function it_recalculates_order_taxes_and_shipping_charges(
OrderTaxesApplicatorInterface $taxesApplicator,
ShippingChargesProcessorInterface $shippingChargesProcessor,
OrderInterface $order
) {
$order->getPromotions()->willReturn([]);
$taxesApplicator->apply($order)->shouldBeCalled();
$shippingChargesProcessor->applyShippingCharges($order)->shouldBeCalled();
$this->recalculate($order);
}
}

View file

@ -11,6 +11,7 @@
namespace Sylius\Component\Promotion\Factory;
use Sylius\Component\Promotion\Model\CouponInterface;
use Sylius\Component\Resource\Factory\FactoryInterface;
/**

View file

@ -11,7 +11,6 @@
namespace Sylius\Component\Promotion\Model;
use Sylius\Component\Resource\Model\SoftDeletableTrait;
use Sylius\Component\Resource\Model\TimestampableTrait;
/**
@ -19,7 +18,7 @@ use Sylius\Component\Resource\Model\TimestampableTrait;
*/
class Coupon implements CouponInterface
{
use SoftDeletableTrait, TimestampableTrait;
use TimestampableTrait;
/**
* @var mixed

View file

@ -13,13 +13,12 @@ namespace Sylius\Component\Promotion\Model;
use Sylius\Component\Resource\Model\CodeAwareInterface;
use Sylius\Component\Resource\Model\ResourceInterface;
use Sylius\Component\Resource\Model\SoftDeletableInterface;
use Sylius\Component\Resource\Model\TimestampableInterface;
/**
* @author Saša Stamenković <umpirsky@gmail.com>
*/
interface CouponInterface extends CodeAwareInterface, SoftDeletableInterface, TimestampableInterface, ResourceInterface
interface CouponInterface extends CodeAwareInterface, TimestampableInterface, ResourceInterface
{
/**
* @return int