mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 17:10:53 +00:00
Implemented behat steps for deleting a coupon
This commit is contained in:
parent
8b28715dfb
commit
cb97c955d9
22 changed files with 635 additions and 24 deletions
38
app/migrations/Version20160305115221.php
Normal file
38
app/migrations/Version20160305115221.php
Normal 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');
|
||||
}
|
||||
}
|
||||
|
|
@ -42,5 +42,6 @@ imports:
|
|||
|
||||
- suites/domain/order.yml
|
||||
- suites/domain/product.yml
|
||||
- suites/domain/promotion.yml
|
||||
|
||||
- suites/cli/installer.yml
|
||||
|
|
|
|||
28
etc/behat/suites/domain_promotion.yml
Normal file
28
etc/behat/suites/domain_promotion.yml
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
93
src/Sylius/Behat/Context/Domain/PromotionContext.php
Normal file
93
src/Sylius/Behat/Context/Domain/PromotionContext.php
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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$/
|
||||
*/
|
||||
|
|
|
|||
78
src/Sylius/Behat/Context/Transform/PromotionContext.php
Normal file
78
src/Sylius/Behat/Context/Transform/PromotionContext.php
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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']);
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
namespace Sylius\Component\Promotion\Factory;
|
||||
|
||||
use Sylius\Component\Promotion\Model\CouponInterface;
|
||||
use Sylius\Component\Resource\Factory\FactoryInterface;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue