-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Making the customer option calculation extendable with events (#103)
* feat: added event dispatcher to CustomerOptionRecalculator * refactor: optimized CustomerOptionRecalculator Events * refactor: added a subscriber to create adjustment for select options * refactor: replaced genericEvent with custom events * chore: updated readme * Stripping down the implementation * Fixing the tests Co-authored-by: Basil Baumgartner <basil.baumgartner@ongoing.ch>
- Loading branch information
Showing
10 changed files
with
364 additions
and
37 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
## Customizing Order Adjustment Calculations | ||
|
||
`Brille24\SyliusCustomerOptionsPlugin\Services\CustomerOptionRecalculator` handles all the adjustments for the customer | ||
options. You can add custom adjustment simply by creating a subscriber and listening to one of the | ||
`CustomerOptionRecalculator` events. | ||
|
||
### Events | ||
|
||
The following events are dispatched in this order. | ||
|
||
| Event class | description | | ||
| ------------------------------------- | ----------------------------------------------------------------------------------- | | ||
| `RemoveCustomerOptionFromOrderEvent` | This gets called to give the opportunity to remove more customer option adjustments | | ||
| `RecalculateOrderItemOptionEvent` | Gets called for every order item option that was added for the order | | ||
|
||
### Creating a custom adjustment | ||
|
||
Let's say our products have a text field for a gift card. The gift card costs 1 cent every 10 characters. First you have | ||
to add a `CustomerOption` with the code "gift_card" and type "text". After you added the option to your products you can | ||
create a subscriber to generate adjustments when customers insert a text for the gift card. | ||
|
||
```php | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace App\Module\Brille24CustomerOptionsPlugin\Subscriber; | ||
|
||
use Brille24\SyliusCustomerOptionsPlugin\Event\RecalculateOrderItemOptionEvent; | ||
use Brille24\SyliusCustomerOptionsPlugin\Services\CustomerOptionRecalculator; | ||
use Sylius\Component\Order\Factory\AdjustmentFactoryInterface; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
|
||
class GiftCardAdjustmentSubscriber implements EventSubscriberInterface | ||
{ | ||
/** @var AdjustmentFactoryInterface */ | ||
private $adjustmentFactory; | ||
|
||
public function __construct( | ||
AdjustmentFactoryInterface $adjustmentFactory | ||
) { | ||
$this->adjustmentFactory = $adjustmentFactory; | ||
} | ||
|
||
public static function getSubscribedEvents(): array | ||
{ | ||
return [ | ||
RecalculateOrderItemOptionEvent::class => 'createAdjustment', | ||
]; | ||
} | ||
|
||
public function createAdjustment( | ||
RecalculateOrderItemOptionEvent $event | ||
) { | ||
$orderItemOption = $event->getOrderItemOption(); | ||
// Skip handling all other customer options | ||
if ($orderItemOption->getCustomerOptionCode() !== 'gift_card') { | ||
return; | ||
} | ||
|
||
$orderItem = $orderItemOption->getOrderItem(); | ||
|
||
$textValue = trim($orderItemOption->getOptionValue()); | ||
$costForTextOnCard = (int) ceil(mb_strlen($textValue) / 10); | ||
|
||
if (mb_strlen($textValue) > 0) { | ||
foreach ($orderItem->getUnits() as $unit) { | ||
$adjustment = $this->adjustmentFactory->createWithData( | ||
CustomerOptionRecalculator::CUSTOMER_OPTION_ADJUSTMENT, | ||
'Gift card', | ||
$costForTextOnCard, | ||
false, | ||
[] | ||
); | ||
|
||
$unit->addAdjustment($adjustment); | ||
} | ||
} | ||
} | ||
} | ||
|
||
``` | ||
|
||
### Remove your custom adjustment | ||
|
||
If you used the `CustomerOptionRecalculator::CUSTOMER_OPTION_ADJUSTMENT` constant for your adjustments you are done! All | ||
adjustments of that type will be removed when the `CustomerOptionRecalculator` is executed. If you want to use your own | ||
type for the adjustments you can use the `RemoveCustomerOptionFromOrderEvent` to remove your adjustments. | ||
|
||
```php | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace App\Module\Brille24CustomerOptionsPlugin\Subscriber; | ||
|
||
use Brille24\SyliusCustomerOptionsPlugin\Event\RemoveCustomerOptionFromOrderEvent; | ||
use Brille24\SyliusCustomerOptionsPlugin\Event\RecalculateOrderItemOptionEvent; | ||
use Brille24\SyliusCustomerOptionsPlugin\Services\CustomerOptionRecalculator; | ||
use Sylius\Component\Order\Factory\AdjustmentFactoryInterface; | ||
use Symfony\Component\EventDispatcher\EventSubscriberInterface; | ||
|
||
class GiftCardAdjustmentSubscriber implements EventSubscriberInterface | ||
{ | ||
const GIFT_CARD_ADJUSTMENT_TYPE = 'gift_card'; | ||
|
||
/** @var AdjustmentFactoryInterface */ | ||
private $adjustmentFactory; | ||
|
||
/** | ||
* @param AdjustmentFactoryInterface $adjustmentFactory | ||
*/ | ||
public function __construct( | ||
AdjustmentFactoryInterface $adjustmentFactory | ||
) { | ||
$this->adjustmentFactory = $adjustmentFactory; | ||
} | ||
|
||
public static function getSubscribedEvents() | ||
{ | ||
return [ | ||
RemoveCustomerOptionFromOrderEvent::class => 'removeAdjustment', | ||
RecalculateOrderItemOptionEvent::class => 'createAdjustment', | ||
]; | ||
} | ||
|
||
/** | ||
* @param RemoveCustomerOptionFromOrderEvent $event | ||
*/ | ||
public function removeAdjustment(RemoveCustomerOptionFromOrderEvent $event) | ||
{ | ||
$order = $event->getOrder(); | ||
$order->removeAdjustmentsRecursively(self::GIFT_CARD_ADJUSTMENT_TYPE); | ||
} | ||
|
||
/** | ||
* @param RecalculateOrderItemOptionEvent $event | ||
*/ | ||
public function createAdjustment(RecalculateOrderItemOptionEvent $event) | ||
{ | ||
$orderItemOption = $event->getOrderItemOption(); | ||
// Skip handling all other customer options | ||
if ($orderItemOption->getCustomerOptionCode() !== 'gift_card') { | ||
return; | ||
} | ||
|
||
$orderItem = $orderItemOption->getOrderItem(); | ||
|
||
$textValue = trim($orderItemOption->getOptionValue()); | ||
$costForTextOnCard = (int) ceil(mb_strlen($textValue) / 10); | ||
|
||
if (mb_strlen($textValue) > 0) { | ||
foreach ($orderItem->getUnits() as $unit) { | ||
$adjustment = $this->adjustmentFactory->createWithData( | ||
self::GIFT_CARD_ADJUSTMENT_TYPE, | ||
'Gift card', | ||
$costForTextOnCard, | ||
false, | ||
[] | ||
); | ||
|
||
$unit->addAdjustment($adjustment); | ||
} | ||
} | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
/** | ||
* This file is part of the Brille24 customer options plugin. | ||
* | ||
* (c) Brille24 GmbH | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Brille24\SyliusCustomerOptionsPlugin\Event; | ||
|
||
use Brille24\SyliusCustomerOptionsPlugin\Entity\OrderItemOptionInterface; | ||
use Symfony\Contracts\EventDispatcher\Event; | ||
|
||
class RecalculateOrderItemOptionEvent extends Event | ||
{ | ||
/** @var OrderItemOptionInterface */ | ||
private $orderItemOption; | ||
|
||
public function __construct(OrderItemOptionInterface $orderItemOption) | ||
{ | ||
$this->orderItemOption = $orderItemOption; | ||
} | ||
|
||
public function getOrderItemOption(): OrderItemOptionInterface | ||
{ | ||
return $this->orderItemOption; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
/** | ||
* This file is part of the Brille24 customer options plugin. | ||
* | ||
* (c) Brille24 GmbH | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
declare(strict_types=1); | ||
|
||
namespace Brille24\SyliusCustomerOptionsPlugin\Event; | ||
|
||
use Sylius\Component\Order\Model\OrderInterface; | ||
use Symfony\Contracts\EventDispatcher\Event; | ||
|
||
class RemoveCustomerOptionFromOrderEvent extends Event | ||
{ | ||
/** @var OrderInterface */ | ||
private $order; | ||
|
||
public function __construct(OrderInterface $order) | ||
{ | ||
$this->order = $order; | ||
} | ||
|
||
public function getOrder(): OrderInterface | ||
{ | ||
return $this->order; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<container xmlns="http://symfony.com/schema/dic/services"> | ||
<services> | ||
<service | ||
class="Brille24\SyliusCustomerOptionsPlugin\Subscriber\SelectAdjustmentCalculatorSubscriber" | ||
id="brille24.customer_options_plugin.subscriber.adjustment" | ||
> | ||
<argument type="service" id="sylius.custom_factory.adjustment" /> | ||
<tag name="kernel.event_subscriber" /> | ||
</service> | ||
</services> | ||
</container> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.