7

I have a redemption form that I want to enter a coupon code and then an order should be created automatically, then the coupon code applied to the order as well.

The order gets created successfully but $promotion->apply($order) does not work.

enter image description here

As you can see in the image above, I have a promotion containing coupon code Z-8FDA5A218B44 . In the condition section, this promotion is limited to a product called Monthly.

I want to create a redemption form in which when a user enters a coupon code, an order and an order item that contains my product (Monthly) will be automatically created. (picture below)

enter image description here As you can see when I submit the redemption form with a coupon code, an order will be created, but I want to apply the coupon code to the order too.

Here's my code:

namespace Drupal\my_subscription\Form;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountProxy;
use Drupal\commerce_product\Plugin\Commerce\Condition\OrderItemProduct as OrderItemProductCondition;
use Drupal\commerce_order\Entity\Order;
use Drupal\commerce_product\Entity\ProductVariation;


/**
 * Class RedemptionForm.
 *
 * @package Drupal\my_subscription\Form
 */
class RedemptionForm extends FormBase {

  /**
   * Drupal\Core\Session\AccountProxy definition.
   *
   * @var \Drupal\Core\Session\AccountProxy
   */
  protected $currentUser;

  public function __construct(
    AccountProxy $current_user
  ) {
    $this->currentUser = $current_user;
  }

  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('current_user')
    );
  }


  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'meditation_redemption_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['coupon_code'] = [
      '#type' => 'textfield',
      '#title' => t('Coupon code'),
      '#description' => t('Enter your coupon code to redeem a promotion.'),
    ];

    $form['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $coupon_code = $form_state->getValue('coupon_code');
    /** @var \Drupal\commerce_promotion\CouponStorageInterface $coupon_storage */
    $coupon_storage = \Drupal::entityTypeManager()->getStorage('commerce_promotion_coupon');

    $coupon = $coupon_storage->loadByCode($coupon_code);
    if (empty($coupon)) {
      $form_state->setErrorByName('coupon_code', t('The provided coupon code is invalid.'));
      return;
    }
    else {
      $form_state->set('coupon', $coupon);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    /** @var \Drupal\commerce_promotion\Entity\Coupon $coupon */
    $coupon = $form_state->get('coupon');
    /** @var \Drupal\commerce_promotion\Entity\Promotion $promotion */
    $promotion = $coupon->getPromotion();

    $conditions = $promotion->getConditions();
    if ($conditions[0] instanceof OrderItemProductCondition) {
      $uid = $this->currentUser->id();

      $configuration = $conditions[0]->getConfiguration();
      $subscription_product_id = $configuration['products'][0]['product_id'];

      $subscription = ProductVariation::load($subscription_product_id);

      $order_item_storage = \Drupal::entityManager()->getStorage('commerce_order_item');

      $order_item = $order_item_storage->createFromPurchasableEntity($subscription, [
        'quantity' => 1,
      ]);

      /** @var \Drupal\commerce_order\Entity\Order $order */
      $order = Order::create([
        'type' => 'default',
      ]);
      $order->addItem($order_item);
      $order->setCustomerId($uid);
      $order->set('store_id', 1);
      $order->save();
      ///** @var  \Drupal\commerce_ORDER\OrderAssignment $order_assignment */
      //$order_assignment = \Drupal::service('commerce_order.order_assignment');
      //$order_assignment->assign($order, $account);

      if ($coupon->available($order) && $promotion->applies($order)) {
        $promotion->apply($order);
      }
    }

  }

}
  • 2
    Is it failing due to the available and applies check, not actually apply? Also, try setting refresh on next load possibly, to rerun refresh – Matt Glaman Jul 15 '17 at 16:00
  • Dear @MattGlaman, both available and applies are passed. And what do you mean about refresh? – Iman Kiani Jul 15 '17 at 20:10
1

Hi I'm maybe TLTTP but it appears that your implementation is right (assuming as you say it passes the available and applies checks). The problem I think is that you're not saving the order after the promotion gets applied.

...
if ($coupon->available($order) && $promotion->applies($order)) {
    $promotion->apply($order);
    $order->save();
}
...

Also as @matt-glaman suggests you should refresh the order so the final price gets updated.

...
if ($coupon->available($order) && $promotion->applies($order)) {
    $promotion->apply($order);
    // Recalculates total price of the order including any adjustment
    // to the order or it's order items.
    $order->recalculateTotalPrice();
    // Persist any changes applied to the order.
    $order->save();
}
...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.