Skip to content

Instantly share code, notes, and snippets.

@WengerK
Last active June 3, 2022 09:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save WengerK/edbe17bb52067c5be86f34d1d1d2bd4e to your computer and use it in GitHub Desktop.
Save WengerK/edbe17bb52067c5be86f34d1d1d2bd4e to your computer and use it in GitHub Desktop.
Drupal Commerce Custom Order Total Range Condition

Article Ressources - How to setup a Drupal Commerce Order total range condition

This is the Gist repository for my article Drupal Commerce Order total range condition.

Be aware that this article has been wrote for the Blog of Antistatique — Web Agency in Lausanne, Switzerland. A place where I work as Full Stack Web Developer.

Feel free to read it the full article on Medium or check it out on Antistatique.

name: My Custom Commerce Range Condition
type: module
description: Module used to handle Commerce Range Condition
core_version_requirement: ^9.1
package: Commerce
dependencies:
- commerce:commerce
- commerce:commerce_order
- commerce:commerce_product
<?php
namespace Drupal\my_custom_commerce_range_condition\Plugin\Commerce\Condition;
use Drupal\commerce\Plugin\Commerce\Condition\ConditionBase;
use Drupal\commerce_price\Price;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
/**
* Provides the total price range condition for orders.
*
* To be used when willing to trigger condition when the order total falls
* within a range of price (including adjustments)
* e.g. $100 => order total <= $200.
*
* @CommerceCondition(
* id="order_total_price_range",
* label=@Translation("Total price range"),
* display_label=@Translation("Current order total within a range"),
* category=@Translation("Order", context="Commerce"),
* entity_type="commerce_order",
* )
*/
class OrderTotalPriceRange extends ConditionBase {
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return [
'amount_from' => NULL,
'amount_to' => NULL,
] + parent::defaultConfiguration();
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form = parent::buildConfigurationForm($form, $form_state);
$amount_from = $this->configuration['amount_from'];
$amount_to = $this->configuration['amount_to'];
// An #ajax bug can cause $amount_from to be incomplete.
if (isset($amount_from) && !isset($amount_from['number'], $amount_from['currency_code'])) {
$amount_from = NULL;
}
// An #ajax bug can cause $amount_to to be incomplete.
if (isset($amount_to) && !isset($amount_to['number'], $amount_to['currency_code'])) {
$amount_to = NULL;
}
$form['amount_from'] = [
'#type' => 'commerce_price',
'#title' => $this->t('Amount from'),
'#default_value' => $amount_from,
'#required' => TRUE,
];
$form['amount_to'] = [
'#type' => 'commerce_price',
'#title' => $this->t('Amount to'),
'#default_value' => $amount_to,
'#required' => TRUE,
];
return $form;
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::submitConfigurationForm($form, $form_state);
$values = $form_state->getValue($form['#parents']);
$this->configuration['amount_from'] = $values['amount_from'];
$this->configuration['amount_to'] = $values['amount_to'];
}
/**
* {@inheritdoc}
*/
public function evaluate(EntityInterface $entity) {
$this->assertEntity($entity);
/** @var \Drupal\commerce_order\Entity\OrderInterface $order */
$order = $entity;
$total_price = $order->getTotalPrice();
if (!$total_price) {
return FALSE;
}
$condition_price_from = Price::fromArray($this->configuration['amount_from']);
if ($total_price->getCurrencyCode() !== $condition_price_from->getCurrencyCode()) {
return FALSE;
}
$condition_price_to = Price::fromArray($this->configuration['amount_to']);
if ($total_price->getCurrencyCode() !== $condition_price_to->getCurrencyCode()) {
return FALSE;
}
return $total_price->greaterThanOrEqual($condition_price_from)
&& $total_price->lessThanOrEqual($condition_price_to);
}
}
<?php
namespace Drupal\Tests\my_custom_commerce_range_condition\Unit\Plugin\Commerce\Condition;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_price\Price;
use Drupal\my_custom_commerce_range_condition\Plugin\Commerce\Condition\OrderTotalPriceRange;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\my_custom_commerce_range_condition\Plugin\Commerce\Condition\OrderTotalPriceRange
* @group commerce
*
* @internal
*/
final class OrderTotalPriceRangeRangeTest extends UnitTestCase {
/**
* ::covers evaluate.
*/
public function testEmptyOrder() {
$condition = new OrderTotalPriceRange([
'amount_from' => [
'number' => '10.00',
'currency_code' => 'EUR',
],
'amount_to' => [
'number' => '25.00',
'currency_code' => 'EUR',
],
], 'order_total_price', ['entity_type' => 'commerce_order']);
$order = $this->prophesize(OrderInterface::class);
$order->getEntityTypeId()->willReturn('commerce_order');
$order->getTotalPrice()->willReturn(NULL);
$order = $order->reveal();
self::assertFalse($condition->evaluate($order));
}
/**
* ::covers evaluate.
*/
public function testMismatchedCurrencies() {
$condition = new OrderTotalPriceRange([
'amount_from' => [
'number' => '10.00',
'currency_code' => 'EUR',
],
'amount_to' => [
'number' => '25.00',
'currency_code' => 'EUR',
],
], 'order_total_price', ['entity_type' => 'commerce_order']);
$order = $this->prophesize(OrderInterface::class);
$order->getEntityTypeId()->willReturn('commerce_order');
$order->getTotalPrice()->willReturn(new Price('10.00', 'USD'));
$order = $order->reveal();
self::assertFalse($condition->evaluate($order));
}
/**
* ::covers evaluate.
*
* @dataProvider totalPriceProvider
*/
public function testEvaluate($amount_from, $amount_to, $given_total_price, $result) {
$condition = new OrderTotalPriceRange([
'amount_from' => [
'number' => $amount_from,
'currency_code' => 'USD',
],
'amount_to' => [
'number' => $amount_to,
'currency_code' => 'USD',
],
], 'order_total_price', ['entity_type' => 'commerce_order']);
$order = $this->prophesize(OrderInterface::class);
$order->getEntityTypeId()->willReturn('commerce_order');
$order->getTotalPrice()->willReturn(new Price($given_total_price, 'USD'));
$order = $order->reveal();
self::assertEquals($result, $condition->evaluate($order));
}
/**
* Data provider for ::testEvaluate.
*
* @return array
* A list of testEvaluate function arguments.
*/
public function totalPriceProvider() {
return [
[10, 25, 5, FALSE],
[10, 25, 9, FALSE],
[10, 25, 10, TRUE],
[10, 25, 11, TRUE],
[10, 25, 20, TRUE],
[10, 25, 24, TRUE],
[10, 25, 25, TRUE],
[10, 25, 26, FALSE],
[10, 25, 100, FALSE],
];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment