Skip to content

Commit

Permalink
Allowing to use the same input for PromotionCoupon and GiftCards
Browse files Browse the repository at this point in the history
Fixes #59
  • Loading branch information
Roshyo committed Aug 8, 2020
1 parent cebcb0c commit 868a066
Show file tree
Hide file tree
Showing 16 changed files with 254 additions and 9 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ $bundles = [

You will find the templates you need to override in the [test application](https://github.com/Setono/SyliusGiftCardPlugin/tree/master/tests/Application/templates).

If you enable the same input for Promotion and GiftCard (see [here](#using-same-input-for-promotion-and-giftcard)), remove all content of `SyliusShopBundle/Cart/Summary/_coupon.html.twig` since it is not needed.

### Extend `Product`, `Order`, `OrderRepository`, and `CustomerRepository`

**Extend `Product`**
Expand Down Expand Up @@ -283,3 +285,14 @@ setono_sylius_gift_card_shop_remove_gift_card_from_order:
The same applies for the `setono_sylius_gift_card_shop_partial_add_gift_card_to_order` route

You can also override or decorate the service `setono_sylius_gift_card.resolver.redirect_url` to define a more custom way of redirecting

## Using same input for Promotion and GiftCard

You can configure the shop to use same input for GiftCards and Promotion coupons. To do so, set this configuration :

```yaml
# config/packages/setono_sylius_gift_card.yaml
setono_sylius_gift_card:
cart:
use_same_input_for_promotion_and_gift_card: false
```
57 changes: 57 additions & 0 deletions src/Applicator/CouponCodeApplicator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusGiftCardPlugin\Applicator;

use Doctrine\ORM\EntityManagerInterface;
use Setono\SyliusGiftCardPlugin\Model\OrderInterface;
use Sylius\Component\Core\Model\PromotionCouponInterface;
use Sylius\Component\Order\Processor\OrderProcessorInterface;
use Sylius\Component\Promotion\Action\PromotionApplicatorInterface;
use Sylius\Component\Promotion\Repository\PromotionCouponRepositoryInterface;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Webmozart\Assert\Assert;

final class CouponCodeApplicator implements CouponCodeApplicatorInterface
{
/** @var PromotionCouponRepositoryInterface */
private $promotionCouponRepository;

/** @var OrderProcessorInterface */
private $orderProcessor;

/** @var EntityManagerInterface */
private $orderManager;

/** @var PromotionApplicatorInterface */
private $promotionApplicator;

public function __construct(
PromotionCouponRepositoryInterface $promotionCouponRepository,
OrderProcessorInterface $orderProcessor,
EntityManagerInterface $orderManager,
PromotionApplicatorInterface $promotionApplicator
) {
$this->promotionCouponRepository = $promotionCouponRepository;
$this->orderProcessor = $orderProcessor;
$this->orderManager = $orderManager;
$this->promotionApplicator = $promotionApplicator;
}

public function apply(OrderInterface $order, string $couponCode): void
{
$promotionCoupon = $this->promotionCouponRepository->findOneBy(['code' => $couponCode]);
if ($promotionCoupon instanceof PromotionCouponInterface) {
$order->setPromotionCoupon($promotionCoupon);
$promotion = $promotionCoupon->getPromotion();
Assert::notNull($promotion);
$this->promotionApplicator->apply($order, $promotion);
$this->orderProcessor->process($order);

$this->orderManager->flush();
} else {
throw new NotFoundHttpException('Impossible to find the coupon');
}
}
}
12 changes: 12 additions & 0 deletions src/Applicator/CouponCodeApplicatorInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusGiftCardPlugin\Applicator;

use Setono\SyliusGiftCardPlugin\Model\OrderInterface;

interface CouponCodeApplicatorInterface
{
public function apply(OrderInterface $order, string $couponCode): void;
}
53 changes: 44 additions & 9 deletions src/Controller/Action/AddGiftCardToOrderAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use FOS\RestBundle\View\View;
use FOS\RestBundle\View\ViewHandlerInterface;
use Setono\SyliusGiftCardPlugin\Applicator\CouponCodeApplicatorInterface;
use Setono\SyliusGiftCardPlugin\Applicator\GiftCardApplicatorInterface;
use Setono\SyliusGiftCardPlugin\Form\Type\AddGiftCardToOrderType;
use Setono\SyliusGiftCardPlugin\Model\OrderInterface;
Expand Down Expand Up @@ -39,20 +40,30 @@ final class AddGiftCardToOrderAction
/** @var RedirectUrlResolverInterface */
private $redirectRouteResolver;

/** @var CouponCodeApplicatorInterface */
private $couponCodeApplicator;

/** @var bool */
private $useSameInputForPromotionAndGiftCard;

public function __construct(
ViewHandlerInterface $viewHandler,
FormFactoryInterface $formFactory,
CartContextInterface $cartContext,
FlashBagInterface $flashBag,
GiftCardApplicatorInterface $giftCardApplicator,
RedirectUrlResolverInterface $redirectRouteResolver
RedirectUrlResolverInterface $redirectRouteResolver,
CouponCodeApplicatorInterface $couponCodeApplicator,
bool $useSameInputForPromotionAndGiftCard
) {
$this->viewHandler = $viewHandler;
$this->formFactory = $formFactory;
$this->cartContext = $cartContext;
$this->flashBag = $flashBag;
$this->giftCardApplicator = $giftCardApplicator;
$this->redirectRouteResolver = $redirectRouteResolver;
$this->couponCodeApplicator = $couponCodeApplicator;
$this->useSameInputForPromotionAndGiftCard = $useSameInputForPromotionAndGiftCard;
}

public function __invoke(Request $request): Response
Expand All @@ -68,18 +79,42 @@ public function __invoke(Request $request): Response
$form = $this->formFactory->create(AddGiftCardToOrderType::class, $addGiftCardToOrderCommand);
$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {
$giftCard = $addGiftCardToOrderCommand->getGiftCard();
Assert::notNull($giftCard);
$this->giftCardApplicator->apply($order, $giftCard);
if ($form->isSubmitted()) {
if ($form->isValid()) {
$giftCard = $addGiftCardToOrderCommand->getGiftCard();
Assert::notNull($giftCard);
$this->giftCardApplicator->apply($order, $giftCard);

$this->flashBag->add('success', 'setono_sylius_gift_card.gift_card_added');
$this->flashBag->add('success', 'setono_sylius_gift_card.gift_card_added');

if ($request->isXmlHttpRequest()) {
return $this->viewHandler->handle(View::create([], Response::HTTP_CREATED));
if ($request->isXmlHttpRequest()) {
return $this->viewHandler->handle(View::create([], Response::HTTP_CREATED));
}

return new RedirectResponse($this->redirectRouteResolver->getUrlToRedirectTo($request, 'sylius_shop_cart_summary'));
}

return new RedirectResponse($this->redirectRouteResolver->getUrlToRedirectTo($request, 'sylius_shop_cart_summary'));
if ($this->useSameInputForPromotionAndGiftCard) {
// Arrived here, the code applied is not a giftCard.
// Then check if it is a promotion and if so, apply it to order.
// Use NormData instead of Data since the form is invalid, Data is null
$promotionCouponCode = $form->get('giftCard')->getNormData();
if (null !== $promotionCouponCode) {
try {
$this->couponCodeApplicator->apply($order, $promotionCouponCode);

$this->flashBag->add('success', 'setono_sylius_gift_card.gift_card_added');

if ($request->isXmlHttpRequest()) {
return $this->viewHandler->handle(View::create([], Response::HTTP_CREATED));
}

return new RedirectResponse($this->redirectRouteResolver->getUrlToRedirectTo($request, 'sylius_shop_cart_summary'));
} catch (\Exception $exception) {
// Do not do anything here, let FOSRest handle the response
}
}
}
}

if ($request->isXmlHttpRequest()) {
Expand Down
22 changes: 22 additions & 0 deletions src/DependencyInjection/Compiler/OverrideCouponFormPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusGiftCardPlugin\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

final class OverrideCouponFormPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
$useSameInput = (bool) $container->getParameter('setono_sylius_gift_card.cart.use_same_input_for_promotion_and_gift_card');

if ($useSameInput) {
return;
}

$container->removeDefinition('setono_sylius_gift_card.form.type.promotion_coupon_to_code');
}
}
6 changes: 6 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ public function getConfigTreeBuilder(): TreeBuilder
->max(255)
->example(16)
->end()
->arrayNode('cart')
->addDefaultsIfNotSet()
->children()
->booleanNode('use_same_input_for_promotion_and_gift_card')->defaultFalse()->end()
->end()
->end()
->end()
;

Expand Down
5 changes: 5 additions & 0 deletions src/DependencyInjection/SetonoSyliusGiftCardExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ public function load(array $config, ContainerBuilder $container): void
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));

$container->setParameter('setono_sylius_gift_card.code_length', $config['code_length']);
$useSameInputForPromotionAndGiftCard = false;
if (array_key_exists('cart', $config) && array_key_exists('use_same_input_for_promotion_and_gift_card', $config['cart'])) {
$useSameInputForPromotionAndGiftCard = $config['cart']['use_same_input_for_promotion_and_gift_card'];
}
$container->setParameter('setono_sylius_gift_card.cart.use_same_input_for_promotion_and_gift_card', $useSameInputForPromotionAndGiftCard);

$this->registerResources('setono_sylius_gift_card', $config['driver'], $config['resources'], $container);

Expand Down
54 changes: 54 additions & 0 deletions src/Form/Type/PromotionCouponToCodeType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);

namespace Setono\SyliusGiftCardPlugin\Form\Type;

use Sylius\Bundle\PromotionBundle\Form\Type\PromotionCouponToCodeType as SyliusPromotionCouponToCodeType;
use Sylius\Component\Promotion\Model\PromotionCouponInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

final class PromotionCouponToCodeType extends AbstractType implements DataTransformerInterface
{
/** @var SyliusPromotionCouponToCodeType */
private $decoratedForm;

public function __construct(SyliusPromotionCouponToCodeType $decoratedForm)
{
$this->decoratedForm = $decoratedForm;
}

public function buildForm(FormBuilderInterface $builder, array $options): void
{
$this->decoratedForm->buildForm($builder, $options);
}

public function transform($coupon): string
{
return $this->decoratedForm->transform($coupon);
}

public function reverseTransform($code): ?PromotionCouponInterface
{
return $this->decoratedForm->reverseTransform($code);
}

public function configureOptions(OptionsResolver $resolver): void
{
$this->decoratedForm->configureOptions($resolver);
}

public function getParent(): string
{
return HiddenType::class;
}

public function getBlockPrefix(): string
{
return $this->decoratedForm->getBlockPrefix();
}
}
8 changes: 8 additions & 0 deletions src/Resources/config/services/applicator.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@
<argument type="service" id="sylius.manager.order" />
</service>

<service id="setono_sylius_gift_card.applicator.coupon_code"
class="Setono\SyliusGiftCardPlugin\Applicator\CouponCodeApplicator">
<argument type="service" id="sylius.repository.promotion_coupon" />
<argument type="service" id="sylius.order_processing.order_processor.composite" />
<argument type="service" id="sylius.manager.order" />
<argument type="service" id="sylius.promotion_applicator" />
</service>

</services>

</container>
2 changes: 2 additions & 0 deletions src/Resources/config/services/controller.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
<argument type="service" id="session.flash_bag"/>
<argument type="service" id="setono_sylius_gift_card.applicator.gift_card"/>
<argument type="service" id="setono_sylius_gift_card.resolver.redirect_url"/>
<argument type="service" id="setono_sylius_gift_card.applicator.coupon_code"/>
<argument>%setono_sylius_gift_card.cart.use_same_input_for_promotion_and_gift_card%</argument>
</service>

<service id="setono_sylius_gift_card.controller.action.remove_gift_card_from_order"
Expand Down
6 changes: 6 additions & 0 deletions src/Resources/config/services/form.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,11 @@
<argument type="service" id="router"/>
<tag name="form.type"/>
</service>

<service id="setono_sylius_gift_card.form.type.promotion_coupon_to_code"
class="Setono\SyliusGiftCardPlugin\Form\Type\PromotionCouponToCodeType"
decorates="sylius.form.type.promotion_coupon_to_code">
<argument type="service" id="setono_sylius_gift_card.form.type.promotion_coupon_to_code.inner" />
</service>
</services>
</container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div id="sylius-coupon" {{ sylius_test_html_attribute('cart-promotion-coupon') }}>
<div class="ui coupon action input">
{{ form_widget(form.promotionCoupon, sylius_test_form_attribute('cart-promotion-coupon-input')|sylius_merge_recursive({'attr': {'form': main_form, 'placeholder': 'sylius.ui.enter_your_code'|trans~'...'}})) }}
<button type="submit" id="sylius-save" {{ sylius_test_html_attribute('apply-coupon-button') }} class="ui teal icon labeled button" form="{{ main_form }}"><i class="ticket icon"></i> {{ 'sylius.ui.apply_coupon'|trans }}</button>
</div>
<br>
{{ form_errors(form.promotionCoupon) }}
</div>
2 changes: 2 additions & 0 deletions src/SetonoSyliusGiftCardPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace Setono\SyliusGiftCardPlugin;

use Setono\SyliusGiftCardPlugin\DependencyInjection\Compiler\AddAdjustmentsToOrderAdjustmentClearerPass;
use Setono\SyliusGiftCardPlugin\DependencyInjection\Compiler\OverrideCouponFormPass;
use Sylius\Bundle\CoreBundle\Application\SyliusPluginTrait;
use Sylius\Bundle\ResourceBundle\AbstractResourceBundle;
use Sylius\Bundle\ResourceBundle\SyliusResourceBundle;
Expand All @@ -19,6 +20,7 @@ public function build(ContainerBuilder $container): void
parent::build($container);

$container->addCompilerPass(new AddAdjustmentsToOrderAdjustmentClearerPass());
$container->addCompilerPass(new OverrideCouponFormPass());
}

public function getSupportedDrivers(): array
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
imports:
- { resource: "@SetonoSyliusGiftCardPlugin/Resources/config/app/config.yaml" }
- { resource: "@SetonoSyliusGiftCardPlugin/Resources/config/app/fixtures.yaml" }

setono_sylius_gift_card:
cart:
use_same_input_for_promotion_and_gift_card: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div id="sylius-coupon" {{ sylius_test_html_attribute('cart-promotion-coupon') }}>
<div class="ui coupon action input">
{{ form_widget(form.promotionCoupon, sylius_test_form_attribute('cart-promotion-coupon-input')|sylius_merge_recursive({'attr': {'form': main_form, 'placeholder': 'sylius.ui.enter_your_code'|trans~'...'}})) }}
<button type="submit" id="sylius-save" {{ sylius_test_html_attribute('apply-coupon-button') }} class="ui teal icon labeled button" form="{{ main_form }}"><i class="ticket icon"></i> {{ 'sylius.ui.apply_coupon'|trans }}</button>
</div>
<br>
{{ form_errors(form.promotionCoupon) }}
</div>
3 changes: 3 additions & 0 deletions tests/DependencyInjection/ConfigurationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ public function processed_configuration_for_array_node_1(): void
'setono_sylius_gift_card' => [],
], [
'code_length' => 20,
'cart' => [
'use_same_input_for_promotion_and_gift_card' => false,
],
'driver' => SyliusResourceBundle::DRIVER_DOCTRINE_ORM,
'resources' => [
'gift_card' => [
Expand Down

0 comments on commit 868a066

Please sign in to comment.