Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manage multiple coupons in order #5

Merged
merged 7 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions dist/src/Entity/Order/Order.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

/*
* This file is part of Monsieur Biz' Advanced Promotion plugin for Sylius.
* (c) Monsieur Biz <[email protected]>
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace App\Entity\Order;

use Doctrine\ORM\Mapping as ORM;
use MonsieurBiz\SyliusAdvancedPromotionPlugin\Entity\PromotionCouponsAwareTrait;
use Sylius\Component\Core\Model\Order as BaseOrder;

/**
* @ORM\Entity
* @ORM\Table(name="sylius_order")
*/
#[ORM\Entity]
#[ORM\Table(name: 'sylius_order')]
class Order extends BaseOrder implements OrderInterface
{
use PromotionCouponsAwareTrait;

public function __construct()
{
parent::__construct();
$this->initializePromotionCoupons();
}
}
19 changes: 19 additions & 0 deletions dist/src/Entity/Order/OrderInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

/*
* This file is part of Monsieur Biz' Advanced Promotion plugin for Sylius.
* (c) Monsieur Biz <[email protected]>
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace App\Entity\Order;

use MonsieurBiz\SyliusAdvancedPromotionPlugin\Entity\PromotionCouponsAwareInterface;
use Sylius\Component\Core\Model\OrderInterface as BaseOrderInterface;

interface OrderInterface extends BaseOrderInterface, PromotionCouponsAwareInterface
{
}
42 changes: 42 additions & 0 deletions dist/src/Migrations/Version20231218092305.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

/*
* This file is part of Monsieur Biz' Advanced Promotion plugin for Sylius.
* (c) Monsieur Biz <[email protected]>
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace App\Migrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20231218092305 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}

public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE monsieurbiz_advanced_promotion_order_promotion_coupon (order_id INT NOT NULL, promotion_coupon_id INT NOT NULL, INDEX IDX_5C4132AF8D9F6D38 (order_id), INDEX IDX_5C4132AF17B24436 (promotion_coupon_id), PRIMARY KEY(order_id, promotion_coupon_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE monsieurbiz_advanced_promotion_order_promotion_coupon ADD CONSTRAINT FK_5C4132AF8D9F6D38 FOREIGN KEY (order_id) REFERENCES sylius_order (id)');
$this->addSql('ALTER TABLE monsieurbiz_advanced_promotion_order_promotion_coupon ADD CONSTRAINT FK_5C4132AF17B24436 FOREIGN KEY (promotion_coupon_id) REFERENCES sylius_promotion_coupon (id)');
}

public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE monsieurbiz_advanced_promotion_order_promotion_coupon DROP FOREIGN KEY FK_5C4132AF8D9F6D38');
$this->addSql('ALTER TABLE monsieurbiz_advanced_promotion_order_promotion_coupon DROP FOREIGN KEY FK_5C4132AF17B24436');
$this->addSql('DROP TABLE monsieurbiz_advanced_promotion_order_promotion_coupon');
}
}
2 changes: 1 addition & 1 deletion src/Entity/AfterTaxAwareTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ trait AfterTaxAwareTrait
* @ORM\Column(name="after_tax", type="boolean", nullable=false, options={"default": false})
*/
#[ORM\Column(name: 'after_tax', type: 'boolean', nullable: false, options: ['default' => false])]
protected bool $afterTax = false;
private bool $afterTax = false;

public function isAfterTax(): bool
{
Expand Down
27 changes: 27 additions & 0 deletions src/Entity/PromotionCouponsAwareInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/*
* This file is part of Monsieur Biz' Advanced Promotion plugin for Sylius.
* (c) Monsieur Biz <[email protected]>
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace MonsieurBiz\SyliusAdvancedPromotionPlugin\Entity;

use Doctrine\Common\Collections\Collection;
use Sylius\Component\Core\Model\PromotionCouponInterface;

interface PromotionCouponsAwareInterface
{
/** @return Collection<array-key, ?PromotionCouponInterface> */
public function getPromotionCoupons(): Collection;

public function hasPromotionCoupon(PromotionCouponInterface $promotionCoupon): bool;

public function addPromotionCoupon(PromotionCouponInterface $promotionCoupon): void;

public function removePromotionCoupon(PromotionCouponInterface $promotionCoupon): void;
}
65 changes: 65 additions & 0 deletions src/Entity/PromotionCouponsAwareTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

/*
* This file is part of Monsieur Biz' Advanced Promotion plugin for Sylius.
* (c) Monsieur Biz <[email protected]>
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace MonsieurBiz\SyliusAdvancedPromotionPlugin\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Sylius\Component\Core\Model\PromotionCouponInterface;

trait PromotionCouponsAwareTrait
{
/**
* @ORM\ManyToMany(targetEntity=PromotionCouponInterface::class)
* @ORM\JoinTable(name="monsieurbiz_advanced_promotion_order_promotion_coupon",
* joinColumns={@ORM\JoinColumn(name="order_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="promotion_coupon_id", referencedColumnName="id")}
* )
*
* @var Collection<array-key, PromotionCouponInterface>
*/
#[ORM\ManyToMany(targetEntity: PromotionCouponInterface::class)]
#[ORM\JoinTable(name: 'monsieurbiz_advanced_promotion_order_promotion_coupon')]
#[ORM\JoinColumn(name: 'order_id', referencedColumnName: 'id')]
#[ORM\InverseJoinColumn(name: 'promotion_coupon_id', referencedColumnName: 'id')]
private $promotionCoupons;

private function initializePromotionCoupons(): void
{
$this->promotionCoupons = new ArrayCollection();
}

/** @return Collection<array-key, ?PromotionCouponInterface> */
public function getPromotionCoupons(): Collection
{
return $this->promotionCoupons;
}

public function hasPromotionCoupon(PromotionCouponInterface $promotionCoupon): bool
{
return $this->promotionCoupons->contains($promotionCoupon);
}

public function addPromotionCoupon(PromotionCouponInterface $promotionCoupon): void
{
if (!$this->hasPromotionCoupon($promotionCoupon)) {
$this->promotionCoupons->add($promotionCoupon);
}
}

public function removePromotionCoupon(PromotionCouponInterface $promotionCoupon): void
{
if ($this->hasPromotionCoupon($promotionCoupon)) {
$this->promotionCoupons->removeElement($promotionCoupon);
}
}
}
126 changes: 126 additions & 0 deletions src/Form/Extension/CartTypeExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php

/*
* This file is part of Monsieur Biz' Advanced Promotion plugin for Sylius.
* (c) Monsieur Biz <[email protected]>
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace MonsieurBiz\SyliusAdvancedPromotionPlugin\Form\Extension;

use MonsieurBiz\SyliusAdvancedPromotionPlugin\Entity\PromotionCouponsAwareInterface;
use Sylius\Bundle\OrderBundle\Form\Type\CartType;
use Sylius\Bundle\PromotionBundle\Form\Type\PromotionCouponToCodeType;
use Sylius\Component\Core\Model\PromotionCouponInterface;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Validator\Context\ExecutionContextInterface;

final class CartTypeExtension extends AbstractTypeExtension
{
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('promotionCoupons', CollectionType::class, [
'entry_type' => PromotionCouponToCodeType::class,
'entry_options' => [
'attr' => [
'form' => 'sylius_cart',
],
'constraints' => [
new Assert\Callback(
[$this, 'validatePromotionEntry'],
['monsieurbiz_advanced_promotion_coupon']
),
],
],
'required' => false,
'allow_add' => true,
'allow_delete' => true,
'button_add_label' => 'monsieurbiz_sylius_advanced_promotion.coupons.add_coupon',
'attr' => [
'class' => 'monsieurbiz-coupons',
],
])
->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'removeEmptyCouponsOnPreSubmit'])
;
}

public function validatePromotionEntry(?PromotionCouponInterface $entry, ExecutionContextInterface $context): void
{
if (null !== $entry) {
return;
}

$context
->buildViolation('sylius.promotion_coupon.is_invalid')
->addViolation()
;
}

/**
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function removeEmptyCouponsOnPreSubmit(FormEvent $event): void
{
$formData = $event->getData();
if (!\is_array($formData)) {
return;
}

$promotionCoupons = $formData['promotionCoupons'] ?? [];
if (!empty($promotionCoupons)) {
return;
}

$order = $event->getForm()->getNormData();
if (!$order instanceof PromotionCouponsAwareInterface) {
return;
}

foreach ($order->getPromotionCoupons() as $promotionCoupon) {
if (!$promotionCoupon) {
continue;
}
$order->removePromotionCoupon($promotionCoupon);
}
}

/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setNormalizer('validation_groups', fn (Options $options, array $validationGroups) => function (FormInterface $form) use ($validationGroups) {
foreach ($form->get('promotionCoupons') as $promotionCoupon) {
if ((bool) $promotionCoupon->getNormData()) { // Validate the coupon if it was sent
$validationGroups[] = 'monsieurbiz_advanced_promotion_coupon';

break;
}
}

return $validationGroups;
});
}

public static function getExtendedTypes(): iterable
{
return [
CartType::class,
];
}
}
33 changes: 33 additions & 0 deletions src/Form/Type/PromotionCouponType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

/*
* This file is part of Monsieur Biz' Advanced Promotion plugin for Sylius.
* (c) Monsieur Biz <[email protected]>
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace MonsieurBiz\SyliusAdvancedPromotionPlugin\Form\Type;

use Sylius\Bundle\PromotionBundle\Form\Type\PromotionCouponToCodeType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

final class PromotionCouponType extends AbstractType
{
/**
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('promotionCoupon', PromotionCouponToCodeType::class, [
'label' => 'sylius.form.cart.coupon',
'required' => false,
'by_reference' => false,
])
;
}
}
Loading
Loading