Created
February 28, 2018 16:35
-
-
Save lisastreeter/d7bfeff9ef948c4cd3e7a1daad1c9b63 to your computer and use it in GitHub Desktop.
Offer type example for Commerce documentation
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
<?php | |
namespace Drupal\my_module\Plugin\Commerce\PromotionOffer; | |
use Drupal\commerce_order\Adjustment; | |
use Drupal\commerce_price\Price; | |
use Drupal\commerce_promotion\Entity\PromotionInterface; | |
use Drupal\commerce_promotion\Plugin\Commerce\PromotionOffer\PromotionOfferBase; | |
use Drupal\Core\Entity\EntityInterface; | |
use Drupal\Core\Form\FormStateInterface; | |
/** | |
* Discounts a set quantity of items to fixed amount. | |
* | |
* @CommercePromotionOffer( | |
* id = "my_module_discount_to_fixed", | |
* label = @Translation("Discount items of each matching product to fixed amount"), | |
* entity_type = "commerce_order_item", | |
* ) | |
*/ | |
class OrderItemDiscountToFixed extends PromotionOfferBase { | |
/** | |
* {@inheritdoc} | |
*/ | |
public function defaultConfiguration() { | |
return [ | |
'quantity' => 1, | |
'amount' => NULL, | |
] + parent::defaultConfiguration(); | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function buildConfigurationForm(array $form, FormStateInterface $form_state) { | |
$form += parent::buildConfigurationForm($form, $form_state); | |
$quantity = $this->configuration['quantity']; | |
$amount = $this->configuration['amount']; | |
// A bug in the plugin_select form element causes $amount to be incomplete. | |
if (isset($amount) && !isset($amount['number'], $amount['currency_code'])) { | |
$amount = NULL; | |
} | |
$form['quantity'] = [ | |
'#type' => 'number', | |
'#title' => $this->t('Quantity'), | |
'#description' => $this->t('Number of items to discount for each matching product.'), | |
'#default_value' => $quantity, | |
'#min' => 1, | |
// Set max to match length of quantity text box match amount text box. | |
'#max' => 10000000, | |
'#required' => TRUE, | |
]; | |
$form['amount'] = [ | |
'#type' => 'commerce_price', | |
'#title' => $this->t('Amount'), | |
'#default_value' => $amount, | |
'#required' => TRUE, | |
]; | |
return $form; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) { | |
$values = $form_state->getValue($form['#parents']); | |
if (empty($values['quantity'])) { | |
$form_state->setError($form, $this->t('Quantity must be a positive number.')); | |
} | |
if ($values['amount']['number'] < 0) { | |
$form_state->setError($form, $this->t('Amount cannot be negative.')); | |
} | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { | |
parent::submitConfigurationForm($form, $form_state); | |
$values = $form_state->getValue($form['#parents']); | |
$this->configuration['quantity'] = $values['quantity']; | |
$this->configuration['amount'] = $values['amount']; | |
} | |
/** | |
* {@inheritdoc} | |
*/ | |
public function apply(EntityInterface $entity, PromotionInterface $promotion) { | |
$this->assertEntity($entity); | |
/** @var \Drupal\commerce_order\Entity\OrderItemInterface $order_item */ | |
$order_item = $entity; | |
$unit_price = $order_item->getUnitPrice(); | |
$quantity = $order_item->getQuantity(); | |
$target_amount = $this->getAmount(); | |
$offer_quantity = $this->configuration['quantity']; | |
// Confirm that the currency codes are the same. | |
if ($unit_price->getCurrencyCode() != $target_amount->getCurrencyCode()) { | |
return; | |
} | |
// Don't raise the order item unit price. | |
if ($target_amount->greaterThan($unit_price)) { | |
return; | |
} | |
// Offer quantity cannot exceed the order item quantity. | |
if ($offer_quantity > $quantity) { | |
$offer_quantity = $quantity; | |
} | |
// Calculate per-item reduction amount. | |
$adjustment_amount = $unit_price->subtract($target_amount); | |
$adjustment_amount = $adjustment_amount->multiply($offer_quantity); | |
// Adjustment amount is multiplied by quantity when applied, so we divide here. | |
$adjustment_amount = $adjustment_amount->divide($quantity); | |
$order_item->addAdjustment(new Adjustment([ | |
'type' => 'promotion', | |
// @todo Change to label from UI when added in #2770731. | |
'label' => t('Discount'), | |
'amount' => $adjustment_amount->multiply('-1'), | |
'source_id' => $promotion->id(), | |
])); | |
} | |
/** | |
* Gets the offer amount. | |
* | |
* @return \Drupal\commerce_price\Price|null | |
* The amount, or NULL if unknown. | |
*/ | |
protected function getAmount() { | |
if (!empty($this->configuration['amount'])) { | |
$amount = $this->configuration['amount']; | |
return new Price($amount['number'], $amount['currency_code']); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment