You are here

function commerce_registration_commerce_cart_order_refresh in Commerce Registration 7.2

Implements hook_commerce_cart_order_refresh().

Alter the line items to make sure we are not overbooking a registration prod Based on https://www.drupal.org/node/2126417

@todo - can we do this in one pass rather than 3?

File

./commerce_registration.module, line 1480
Commerce Registration module code.

Code

function commerce_registration_commerce_cart_order_refresh($order_wrapper) {
  $order = $order_wrapper
    ->value();

  // Make sure registration entities still match up to products.
  if (isset($order->data['register_entities'])) {

    // Save a copy of register_entities to find registrations no longer associated with a product.
    $register_entities = $order->data['register_entities'];
    foreach ($order_wrapper->commerce_line_items as $line_item_wrapper) {
      if (!in_array($line_item_wrapper->type
        ->value(), commerce_product_line_item_types())) {
        continue;
      }
      $product = $line_item_wrapper->commerce_product;
      $line_item_id = $line_item_wrapper->line_item_id
        ->value();
      if (isset($order->data['register_entities'][$line_item_id . 'prod-' . $product->sku
        ->value()])) {

        // This registration still has a product.
        unset($register_entities[$line_item_id . 'prod-' . $product->sku
          ->value()]);
      }
    }

    // Delete registrations which no longer have a matching product in the cart.
    $orphan_registration_ids = array();
    foreach ($register_entities as $key => $registrations) {
      foreach ($registrations as $registration) {
        $orphan_registration_ids[] = $registration->registration_id;
      }
      unset($order->data['register_entities'][$key]);
    }
    registration_delete_multiple($orphan_registration_ids);
  }

  // Stop users overbooking registrations
  if (!commerce_cart_order_is_cart($order_wrapper
    ->value())) {
    return FALSE;
  }

  // Keep an array with the sum of qty
  $qty_sum = array();

  // Keep an array with the list of potentially overbooked line items
  $overbooked_prod_id = array();

  // Keep list of Warning Messages
  $msg_array = array();

  // Set the message we will show to the user if they need to change the quantity in their cart
  $adjust_qty_text = arg(0) == 'cart' ? t('Please adjust your cart quantity.') : l(t('Please adjust your cart quantity.'), 'cart');

  // ** First Pass:
  // Make sure individual line items do not exceed available registrations
  // For each of the line items in the order
  foreach ($order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {
    if (!in_array($line_item_wrapper->type
      ->value(), commerce_product_line_item_types())) {
      return FALSE;
    }

    // Get the line item  so we can work on it
    $line_item = $line_item_wrapper
      ->value();

    // Gets the quantity of this line item in the cart
    $qty = $line_item_wrapper->quantity
      ->value();

    // Gets the unique product id for the line item
    $product_id = $line_item_wrapper->commerce_product->product_id
      ->value();

    // Attempt to get registration settings for this product
    $settings = registration_entity_settings('commerce_product', $product_id);

    // Check if this product is registration enabled
    if (!empty($settings) && $settings['status'] == 1) {

      // For this product id, see how many are available
      $capacity = (int) $settings['capacity'];
      $filled = (int) registration_event_count('commerce_product', $product_id);

      // Add order registrations offset
      $order_registrations = 0;

      // Get registrations from current order if they have been created
      if (isset($order->data['register_entities'])) {

        // loop through registrations
        foreach ($order->data['register_entities'] as $key => $registrations) {
          foreach ($registrations as $registration) {
            if ($registration->order_id == $order->order_id && $registration->entity_id == $product_id) {

              // this registration belongs to the current order and current product; add to order registrations
              $order_registrations++;
            }
          }
        }
      }

      // Check if $capacity is set to 0 (unlimited) and ensure $avail isn't
      // negative which can cause too many registrations to be removed.
      $avail = 0;
      if ($capacity > 0) {
        $avail = $capacity - $filled + $order_registrations;
      }
      if ($avail < 0) {
        $avail = 0;
      }

      // If the line item qty is more than available, set the
      // line item to availability to avoid over booking
      if ($capacity > 0 && $qty > $avail) {

        // Set line item qty to availability
        _commerce_registration_set_line_item_qty($line_item, $avail);
        if (!array_key_exists($product_id, $qty_sum)) {
          $qty_sum[$product_id] = $avail;
        }
        else {
          $qty_sum[$product_id] += $avail;
        }

        //  Display a warning message.
        $msg_array[$product_id] = t("There are only @num available slots for @title. !adjust_text", array(
          '@num' => $avail,
          '@title' => $line_item_wrapper->commerce_product->title
            ->value(),
          '!adjust_text' => $adjust_qty_text,
        ));
      }
      else {

        // Let's add up the sum of all the same products in the cart
        // needed since  disabled the
        // 'Attempt to combine like products on the same line item in the cart.'
        if (!array_key_exists($product_id, $qty_sum)) {
          $qty_sum[$product_id] = $line_item_wrapper->quantity
            ->value();
        }
        else {
          $qty_sum[$product_id] += $line_item_wrapper->quantity
            ->value();
        }
      }

      // Check if the sum in cart would result in overbooking
      if ($capacity > 0 && $qty_sum[$product_id] > $avail) {
        $overbooked_prod_id[$product_id] = TRUE;
      }
    }
  }

  // ** Second Pass:
  //  if Sum of line item quantities would cause overbooking
  //  First try setting all of those products quantity to the slots available
  //  then re-check qty sum.  if still exceeds, then remove line item
  $qty_sum = array();

  // reset
  // For each of the line items in the order
  if (!empty($overbooked_prod_id)) {
    foreach ($order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {

      // If this line item product id is in the overbooked array, set qty 1
      $line_item = $line_item_wrapper
        ->value();

      // Gets the unique product id for the line item
      $product_id = $line_item_wrapper->commerce_product->product_id
        ->value();
      if (isset($overbooked_prod_id[$product_id])) {

        // Set line item qty to 1
        _commerce_registration_set_line_item_qty($line_item, $avail);
        if (!array_key_exists($product_id, $qty_sum)) {
          $qty_sum[$product_id] = $avail;
        }
        else {
          $qty_sum[$product_id] += $avail;
        }

        // For this product id, see how many are available
        // Attempt to get registration settings for this product
        $settings = registration_entity_settings('commerce_product', $product_id);
        $capacity = (int) $settings['capacity'];
        $filled = (int) registration_event_count('commerce_product', $product_id);
        $avail = $capacity - $filled;

        // Warning Message
        $msg_array[$product_id] = t("There are only @num available slots for @title. !adjust_text", array(
          '@num' => $avail,
          '@title' => $line_item_wrapper->commerce_product->title
            ->value(),
          '!adjust_text' => $adjust_qty_text,
        ));

        // Check if the sum in cart would result in overbooking
        // This time, we remove it.
        if ($qty_sum[$product_id] > $avail) {

          // Delete the line item
          // do not need to save order, as done after the hook for us
          commerce_cart_order_product_line_item_delete($order_wrapper
            ->value(), $line_item->line_item_id, $skip_save = TRUE);

          // $order_wrapper->value(), $line_item->line_item_id );
          $qty_sum[$product_id] -= 1.0;

          // Warning Message
          $msg_array[$product_id] = t("There are only @num available slots for @title. Item was removed from your cart", array(
            '@num' => $avail,
            '@title' => $line_item_wrapper->commerce_product->title
              ->value(),
          ));
        }
      }
    }
  }

  // ** Third Pass:
  // Verify if registration is possible
  // We have already checked capacity, check open/close dates and reg status
  // if not available, then remove
  foreach ($order_wrapper->commerce_line_items as $delta => $line_item_wrapper) {
    if (!in_array($line_item_wrapper->type
      ->value(), commerce_product_line_item_types())) {
      continue;
    }

    // Get the line item  so we can work on it
    $line_item = $line_item_wrapper
      ->value();

    // Gets the unique product id for the line item
    $product_id = $line_item_wrapper->commerce_product->product_id
      ->value();

    // Attempt to get registration settings for this product
    $settings = registration_entity_settings('commerce_product', $product_id);

    // Check if this product is registration enabled
    if (!empty($settings)) {
      $status = $settings['status'];
      $open = isset($settings['open']) ? strtotime($settings['open']) : NULL;
      $close = isset($settings['close']) ? strtotime($settings['close']) : NULL;
      $now = REQUEST_TIME;

      // remove line item if not open
      if ($status) {

        // check open date range
        if (isset($open) && $now < $open) {
          $status = FALSE;
        }

        // check close date range
        if (isset($close) && $now >= $close) {
          $status = FALSE;
        }
      }

      // Delete the line item
      if ($status == FALSE) {

        // do not need to save order, as done after the hook for us
        commerce_cart_order_product_line_item_delete($order_wrapper
          ->value(), $line_item->line_item_id, $skip_save = TRUE);

        // Warning Message
        $msg_array[$product_id] = t("Registration is not available for @product.  Item was removed from your cart.", array(
          '@product' => $line_item_wrapper->commerce_product->title
            ->value(),
        ));
      }
    }
  }

  // Display warning messages for any products that were overbooked
  foreach ($msg_array as $msg) {
    drupal_set_message($msg, 'warning', TRUE);
  }
}