You are here

function commerce_registration_defer_form_submit in Commerce Registration 7.2

Submit callback for the registration deferral form.

File

modules/commerce_registration_defer/commerce_registration_defer.module, line 152
Module file for commerce_registration_defer.

Code

function commerce_registration_defer_form_submit($form, &$form_state) {
  $original_registration = $form_state['build_info']['args'][0];
  $line_item_type = $form_state['values']['line_item_type'];
  $original_line_item = $form_state['values']['original_line_item'];

  // The selected product.
  $product = commerce_product_load_by_sku($form_state['values']['product_sku']);
  $order = $form_state['build_info']['args'][1];

  // Wrap the order for easy access to field data.
  $order_wrapper = entity_metadata_wrapper('commerce_order', $order);

  // Get the line item we created in the validation callback.
  $line_item = $form_state['build_info']['new_line_item'];

  // Wrap the line item too, we'll need it.
  $line_item_wrapper = entity_metadata_wrapper('commerce_line_item', $line_item);

  // Copy all the existing registration's data and update it with the new
  // product info.
  $new_registration = clone $original_registration;
  $new_registration->entity_id = $product->product_id;
  unset($new_registration->created);
  $new_registration->registration_id = NULL;
  $new_registration
    ->save();

  // Now set the state of the original registration to deferred.
  $original_registration->state = 'deferred';
  $original_registration
    ->save();
  $quantity = $original_registration->count;

  // Reduce the original line item quantity by the registration count if the
  // line item quantity is synced with the number of associated registrations.
  $sync_original_quantity = isset($original_line_item->data['sync_registrations']) ? (bool) $original_line_item->data['sync_registrations'] : TRUE;
  if ($sync_original_quantity && $original_line_item->quantity > 0) {
    $original_line_item->quantity = $original_line_item->quantity < $quantity ? 0 : $original_line_item->quantity - $quantity;
    commerce_line_item_save($original_line_item);
  }

  // If we should try and combine line items look for an existing line item to
  // add the new registration to.
  $combine = isset($original_line_item->data['context']['add_to_cart_combine']) ? $original_line_item->data['context']['add_to_cart_combine'] : TRUE;

  // Determine if the product already exists on the order and increment its
  // quantity instead of adding a new line if it does.
  $matching_line_item = NULL;

  // If we are supposed to look for a line item to combine into...
  if ($combine) {

    // Generate an array of properties and fields to compare.
    $comparison_properties = array(
      'type',
      'commerce_product',
    );

    // Add any field that was exposed on the Add to Cart form to the array.
    // TODO: Bypass combination when an exposed field is no longer available but
    // the same base product is added to the cart.
    foreach (field_info_instances('commerce_line_item', $line_item->type) as $info) {
      if (!empty($info['commerce_cart_settings']['field_access'])) {
        $comparison_properties[] = $info['field_name'];
      }
    }

    // Allow other modules to specify what properties should be compared when
    // determining whether or not to combine line items.
    drupal_alter('commerce_cart_product_comparison_properties', $comparison_properties, clone $line_item);

    // Loop over each line item on the order.
    foreach ($order_wrapper->commerce_line_items as $delta => $matching_line_item_wrapper) {

      // Unwrap the line item so we can compare its data parameter.
      $existing_line_item = $matching_line_item_wrapper
        ->value();

      // Check if the original line item and any matching line item share the
      // same 'sync_registrations' settings.
      $sync_matching_quantity = isset($existing_line_item->data['sync_registrations']) ? (bool) $existing_line_item->data['sync_registrations'] : TRUE;
      if ($sync_original_quantity !== $sync_matching_quantity) {
        continue;
      }

      // Examine each of the comparison properties on the line item.
      foreach ($comparison_properties as $property) {

        // If the property is not present on either line item, bypass it.
        if (!isset($matching_line_item_wrapper
          ->value()->{$property}) && !isset($line_item_wrapper
          ->value()->{$property})) {
          continue;
        }

        // If any property does not match the same property on the incoming line
        // item or exists on one line item but not the other...
        if (!isset($matching_line_item_wrapper
          ->value()->{$property}) && isset($line_item_wrapper
          ->value()->{$property}) || isset($matching_line_item_wrapper
          ->value()->{$property}) && !isset($line_item_wrapper
          ->value()->{$property}) || $matching_line_item_wrapper->{$property}
          ->raw() != $line_item_wrapper->{$property}
          ->raw()) {

          // Continue the loop with the next line item.
          continue 2;
        }
      }

      // If every comparison line item matched, combine into this line item.
      $matching_line_item = $existing_line_item;
      break;
    }
  }

  // If no matching line item was found...
  if (empty($matching_line_item)) {

    // Always use the quantity defined by the registration count...
    $line_item->quantity = $quantity;

    // However if the original line item was not set to sync its quantity with
    // its number of registrations then we need someway to balance it out. So
    // we will set the line items unit price to zero.
    if (!$sync_original_quantity) {
      $line_item->commerce_unit_price[$product->language][0]['amount'] = 0;
      $line_item->commerce_unit_price[$product->language][0]['data']['components'] = array();
    }

    // Should the line item quantity be synced?
    $line_item->data['sync_registrations'] = $sync_original_quantity;

    // Save the incoming line item now so we get its ID.
    commerce_line_item_save($line_item);

    // Add it to the order's line item reference value.
    $order_wrapper->commerce_line_items[] = $line_item;
  }
  else {

    // Increment the quantity of the matching line item if its set to sync.
    if ($sync_matching_quantity) {
      $matching_line_item->quantity += $quantity;
    }

    // Update the data array and save it.
    $matching_line_item->data = array_merge($line_item->data, $matching_line_item->data);
    commerce_line_item_save($matching_line_item);

    // Update the line item variable for use in the invocation and return value.
    $line_item = $matching_line_item;
  }

  // Update the order with the new registration info.
  $key = $line_item->line_item_id . 'prod-' . $product->sku;
  $order->data['register_entities'][$key][] = $new_registration;

  // Record the deferral in the order revision log.
  $order->log = "Registration deferred: {$original_registration->registration_id} ==> {$new_registration->registration_id}.";
  $order->revision = true;

  // Save the updated order.
  commerce_order_save($order);
  $context = array(
    'original' => array(
      'registration' => $original_registration,
      'line_item' => $original_line_item,
    ),
    'new' => array(
      'registration' => $new_registration,
      'line_item' => $line_item,
    ),
    'order' => $order,
  );

  // Invoke the hook.
  module_invoke_all('commerce_registration_defer', $context);

  // Invoke rules.
  if (module_exists('rules')) {
    rules_invoke_event('commerce_registration_defer', $original_registration, $new_registration);
  }

  // Display the confirmation message.
  if (!empty($form['confirmation']['#value'])) {
    drupal_set_message(filter_xss($form['confirmation']['#value']));
  }

  // Log the deferral to Drupal's watchdog.
  $uri_options = entity_uri('commerce_order', $order);
  watchdog('commerce registration', "Registration Deferred for order #!oid: !orig ==> !new.", array(
    '!oid' => $order->order_id,
    '!orig' => $original_registration->registration_id,
    '!new' => $new_registration->registration_id,
  ), WATCHDOG_INFO, l(t('view order'), $uri_options['path'], $uri_options['options']));
}