Skip to content

Commit

Permalink
PromotionCouponEligbilityValidator refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
Zales0123 authored and Tomanhez committed Jun 24, 2021
1 parent 9cd2810 commit a2b7694
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 127 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?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.
*/

declare(strict_types=1);

namespace Sylius\Bundle\ApiBundle\Checker;

use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\PromotionCouponInterface;
use Sylius\Component\Core\Model\PromotionInterface;
use Sylius\Component\Promotion\Checker\Eligibility\PromotionCouponEligibilityCheckerInterface;
use Sylius\Component\Promotion\Checker\Eligibility\PromotionEligibilityCheckerInterface;

final class AppliedCouponEligibilityChecker implements AppliedCouponEligibilityCheckerInterface
{
/** @var PromotionEligibilityCheckerInterface */
private $promotionChecker;

/** @var PromotionCouponEligibilityCheckerInterface */
private $promotionCouponChecker;

public function __construct(
PromotionEligibilityCheckerInterface $promotionChecker,
PromotionCouponEligibilityCheckerInterface $promotionCouponChecker
) {
$this->promotionChecker = $promotionChecker;
$this->promotionCouponChecker = $promotionCouponChecker;
}

public function isEligible(PromotionCouponInterface $promotionCoupon, OrderInterface $cart): bool
{
/** @var PromotionInterface $promotion */
$promotion = $promotionCoupon->getPromotion();

if (!$promotion->getChannels()->contains($cart->getChannel())) {
return false;
}

if (!$this->promotionCouponChecker->isEligible($cart, $promotionCoupon)) {
return false;
}

if (!$this->promotionChecker->isEligible($cart, $promotionCoupon->getPromotion())) {
return false;
}

return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Sylius\Bundle\ApiBundle\Checker;

use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\PromotionCouponInterface;

interface AppliedCouponEligibilityCheckerInterface
{
public function isEligible(PromotionCouponInterface $promotionCoupon, OrderInterface $cart): bool;
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,13 @@
<service id="sylius.api.validator.promotion_coupon_eligibility" class="Sylius\Bundle\ApiBundle\Validator\Constraints\PromotionCouponEligibilityValidator">
<argument type="service" id="sylius.repository.promotion_coupon" />
<argument type="service" id="sylius.repository.order" />
<argument type="service" id="sylius.api.checker.applied_coupon_eligibility_checker" />
<tag name="validator.constraint_validator" alias="sylius_api_promotion_coupon_eligibility" />
</service>

<service id="sylius.api.checker.applied_coupon_eligibility_checker" class="Sylius\Bundle\ApiBundle\Checker\AppliedCouponEligibilityChecker">
<argument type="service" id="sylius.promotion_eligibility_checker" />
<argument type="service" id="sylius.promotion_coupon_eligibility_checker" />
<tag name="validator.constraint_validator" alias="sylius_api_promotion_coupon_eligibility" />
</service>

<service id="sylius.api.validator.shipment_already_shipped" class="Sylius\Bundle\ApiBundle\Validator\Constraints\ShipmentAlreadyShippedValidator">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@

namespace Sylius\Bundle\ApiBundle\Validator\Constraints;

use Sylius\Bundle\ApiBundle\Checker\AppliedCouponEligibilityCheckerInterface;
use Sylius\Bundle\ApiBundle\Command\Cart\ApplyCouponToCart;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\PromotionInterface;
use Sylius\Component\Core\Model\PromotionCouponInterface;
use Sylius\Component\Core\Repository\OrderRepositoryInterface;
use Sylius\Component\Promotion\Checker\Eligibility\PromotionCouponEligibilityCheckerInterface;
use Sylius\Component\Promotion\Checker\Eligibility\PromotionEligibilityCheckerInterface;
use Sylius\Component\Promotion\Model\PromotionCouponInterface;
use Sylius\Component\Promotion\Repository\PromotionCouponRepositoryInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
Expand All @@ -34,22 +32,17 @@ final class PromotionCouponEligibilityValidator extends ConstraintValidator
/** @var OrderRepositoryInterface */
private $orderRepository;

/** @var PromotionEligibilityCheckerInterface */
private $promotionChecker;

/** @var PromotionCouponEligibilityCheckerInterface */
private $promotionCouponChecker;
/** @var AppliedCouponEligibilityCheckerInterface */
private $appliedCouponEligibilityChecker;

public function __construct(
PromotionCouponRepositoryInterface $promotionCouponRepository,
OrderRepositoryInterface $orderRepository,
PromotionEligibilityCheckerInterface $promotionChecker,
PromotionCouponEligibilityCheckerInterface $promotionCouponChecker
AppliedCouponEligibilityCheckerInterface $appliedCouponEligibilityChecker
) {
$this->promotionCouponRepository = $promotionCouponRepository;
$this->orderRepository = $orderRepository;
$this->promotionChecker = $promotionChecker;
$this->promotionCouponChecker = $promotionCouponChecker;
$this->appliedCouponEligibilityChecker = $appliedCouponEligibilityChecker;
}

public function validate($value, Constraint $constraint): void
Expand All @@ -62,26 +55,20 @@ public function validate($value, Constraint $constraint): void

/** @var PromotionCouponInterface|null $promotionCoupon */
$promotionCoupon = $this->promotionCouponRepository->findOneBy(['code' => $value->couponCode]);
/** @var PromotionInterface $promotion */
$promotion = $promotionCoupon->getPromotion();

/** @var OrderInterface $cart */
$cart = $this->orderRepository->findCartByTokenValue($value->getOrderTokenValue());

$cart->setPromotionCoupon($promotionCoupon);

if (
$promotionCoupon === null ||
!$this->promotionCouponChecker->isEligible($cart, $promotionCoupon) ||
!$this->promotionChecker->isEligible($cart, $promotionCoupon->getPromotion()) ||
!$promotion->getChannels()->contains($cart->getChannel())
!$this->appliedCouponEligibilityChecker->isEligible($promotionCoupon, $cart)
) {
$this->addViolation('sylius.promotion_coupon.is_invalid', 'couponCode');
$this->context
->buildViolation('sylius.promotion_coupon.is_invalid')
->atPath('couponCode')
->addViolation()
;
}
}

private function addViolation(string $message, string $path): void
{
$this->context->buildViolation($message)->atPath($path)->addViolation();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
<?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.
*/

declare(strict_types=1);

namespace spec\Sylius\Bundle\ApiBundle\Checker;

use Doctrine\Common\Collections\ArrayCollection;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Sylius\Bundle\ApiBundle\Checker\AppliedCouponEligibilityCheckerInterface;
use Sylius\Component\Core\Model\ChannelInterface;
use Sylius\Component\Core\Model\OrderInterface;
use Sylius\Component\Core\Model\PromotionCouponInterface;
use Sylius\Component\Core\Model\PromotionInterface;
use Sylius\Component\Promotion\Checker\Eligibility\PromotionCouponEligibilityCheckerInterface;
use Sylius\Component\Promotion\Checker\Eligibility\PromotionEligibilityCheckerInterface;

final class AppliedCouponEligibilityCheckerSpec extends ObjectBehavior
{
function let(
PromotionEligibilityCheckerInterface $promotionChecker,
PromotionCouponEligibilityCheckerInterface $promotionCouponChecker
): void {
$this->beConstructedWith($promotionChecker, $promotionCouponChecker);
}

function it_implements_promotion_coupon_eligibility_checker_interface(): void
{
$this->shouldImplement(AppliedCouponEligibilityCheckerInterface::class);
}

function it_returns_false_if_cart_channel_is_not_one_of_promotion_channels(
PromotionEligibilityCheckerInterface $promotionChecker,
PromotionCouponEligibilityCheckerInterface $promotionCouponChecker,
PromotionCouponInterface $promotionCoupon,
PromotionInterface $promotion,
OrderInterface $cart,
ChannelInterface $firstChannel,
ChannelInterface $secondChannel,
ChannelInterface $thirdChannel
): void {
$promotionCoupon->getPromotion()->willReturn($promotion);

$promotion->getChannels()->willReturn(new ArrayCollection([
$secondChannel->getWrappedObject(),
$thirdChannel->getWrappedObject()
]));
$cart->getChannel()->willReturn($firstChannel);

$promotionChecker->isEligible(Argument::any())->shouldNotBeCalled();
$promotionCouponChecker->isEligible(Argument::any())->shouldNotBeCalled();

$this->isEligible($promotionCoupon, $cart)->shouldReturn(false);
}

function it_returns_false_if_coupon_is_not_eligible(
PromotionEligibilityCheckerInterface $promotionChecker,
PromotionCouponEligibilityCheckerInterface $promotionCouponChecker,
PromotionCouponInterface $promotionCoupon,
PromotionInterface $promotion,
OrderInterface $cart,
ChannelInterface $firstChannel,
ChannelInterface $secondChannel
): void {
$promotionCoupon->getPromotion()->willReturn($promotion);

$promotion->getChannels()->willReturn(new ArrayCollection([
$firstChannel->getWrappedObject(),
$secondChannel->getWrappedObject()
]));
$cart->getChannel()->willReturn($firstChannel);

$promotionCouponChecker->isEligible($cart, $promotionCoupon)->willReturn(false);
$promotionChecker->isEligible(Argument::any())->shouldNotBeCalled();

$this->isEligible($promotionCoupon, $cart)->shouldReturn(false);
}

function it_returns_false_if_promotion_is_not_eligible(
PromotionEligibilityCheckerInterface $promotionChecker,
PromotionCouponEligibilityCheckerInterface $promotionCouponChecker,
PromotionCouponInterface $promotionCoupon,
PromotionInterface $promotion,
OrderInterface $cart,
ChannelInterface $firstChannel,
ChannelInterface $secondChannel
): void {
$promotionCoupon->getPromotion()->willReturn($promotion);

$promotion->getChannels()->willReturn(new ArrayCollection([
$firstChannel->getWrappedObject(),
$secondChannel->getWrappedObject()
]));
$cart->getChannel()->willReturn($firstChannel);

$promotionCouponChecker->isEligible($cart, $promotionCoupon)->willReturn(true);
$promotionChecker->isEligible($cart, $promotion)->willReturn(false);

$this->isEligible($promotionCoupon, $cart)->shouldReturn(false);
}

function it_returns_true_if_promotion_and_coupon_are_eligible(
PromotionEligibilityCheckerInterface $promotionChecker,
PromotionCouponEligibilityCheckerInterface $promotionCouponChecker,
PromotionCouponInterface $promotionCoupon,
PromotionInterface $promotion,
OrderInterface $cart,
ChannelInterface $firstChannel,
ChannelInterface $secondChannel
): void {
$promotionCoupon->getPromotion()->willReturn($promotion);

$promotion->getChannels()->willReturn(new ArrayCollection([
$firstChannel->getWrappedObject(),
$secondChannel->getWrappedObject()
]));
$cart->getChannel()->willReturn($firstChannel);

$promotionCouponChecker->isEligible($cart, $promotionCoupon)->willReturn(true);
$promotionChecker->isEligible($cart, $promotion)->willReturn(true);

$this->isEligible($promotionCoupon, $cart)->shouldReturn(true);
}
}
Loading

0 comments on commit a2b7694

Please sign in to comment.