Hi,

Would be good to have a built in rule that prevents a coupon being applied to an order if there's already one applied.

It is possible to do this with a rule, so I have included it here for anyone else that needs this functionality.

{ "rules_check_for_existing_coupon" : {
    "LABEL" : "Check for existing coupon",
    "PLUGIN" : "reaction rule",
    "TAGS" : [ "coupon" ],
    "REQUIRES" : [ "php", "rules", "commerce_coupon" ],
    "ON" : [ "commerce_coupon_validate" ],
    "IF" : [
      { "php_eval" : { "code" : "$line_items = $commerce_order-\u003ecommerce_line_items['und'];\r\nforeach ($line_items as $key =\u003e $line_item){\r\n$line = commerce_line_item_load($line_item['line_item_id']);\r\nif ($line-\u003etype == 'coupon') return TRUE;\r\n}\r\nreturn FALSE;" } }
    ],
    "DO" : [
      { "drupal_message" : {
          "message" : "Sorry, you can only use one voucher per order.",
          "type" : "warning"
        }
      },
      { "commerce_coupon_action_is_invalid_coupon" : [] }
    ]
  }
}

Comments

pcambra’s picture

I like this, as for today we have a fixed code to check if a coupon has been already redeemed in the context of an order:

function commerce_coupon_code_is_valid($code, $order) {
  global $commerce_coupon_validation_error_message;

  $commerce_coupon = commerce_coupon_load_by_code($code, TRUE);

  // if no such coupon found, the $code is invalid
  if (!is_object($commerce_coupon)) {
    return FALSE;
  }

  // Check if the coupon is already applied to this order. In any case we
  // never want that a coupon is applied twice.
  $log = db_select('commerce_coupon_log', 'c')
      ->fields('c')
      ->condition('order_id', $order->order_id, '=')
      ->condition('coupon_id', $commerce_coupon->coupon_id, '=')
      # ->condition('is_processed', 1, '=')
      ->execute()
      ->fetchAssoc();

  if (isset($log['log_id'])) {
    $commerce_coupon_validation_error_message = t('Sorry, you can only apply a coupon once per order.');
    return FALSE;
  }

  // We use the drupal_static function to generate a global variable.
  // We set per default the result to TRUE. The rules can modify this values,
  // by invoking the valid or invalid action.
  $validation_results = &drupal_static('commerce_coupon_action_validation_results');
  $validation_results = TRUE;

  // We invoke the rules. The defined action callback methods sets then the
  // validation result appropriate.
  rules_invoke_event('commerce_coupon_validate', $commerce_coupon, $order);

  // We get our global variable and return the result.
  return drupal_static('commerce_coupon_action_validation_results');
}

It may be a good idea not to force this and use a rule.

pcambra’s picture

Status: Active » Closed (duplicate)

Sorry, I misunderstood a little what you were doing here, the correct API function call to check if a coupon has been applied to an order is commerce_coupon_get_coupons_by_order, I've made some work on this in here (including a rule) #1538158: Limit number of coupons applied to the order.

Let's mark this as duplicate and keep the conversation in the other issue.