You are here

commerce_invoice_receipt.module in Commerce Invoice Receipt 7.2

Same filename and directory in other branches
  1. 7 commerce_invoice_receipt.module

Provides a printable invoice receipt along with HTML mailing rules.

File

commerce_invoice_receipt.module
View source
<?php

/**
 * @file
 * Provides a printable invoice receipt along with HTML mailing rules.
 */

/**
 * Implements hook_menu().
 */
function commerce_invoice_receipt_menu() {
  $items['admin/commerce/orders/%commerce_order/view/details'] = array(
    'title' => 'Order details',
    'page callback' => 'commerce_order_ui_order_view',
    'page arguments' => array(
      3,
    ),
    'access callback' => 'commerce_order_admin_order_view_access',
    'access arguments' => array(
      3,
    ),
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
  );
  $items['admin/commerce/orders/%commerce_order/view/print'] = array(
    'title' => 'Printable invoice',
    'page callback' => 'commerce_invoice_receipt_view_print',
    'page arguments' => array(
      3,
    ),
    'access callback' => 'commerce_order_access',
    'access arguments' => array(
      'view',
      3,
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 1,
    'parent' => 'admin/commerce/orders/%commerce_order',
  );
  $items['admin/commerce/orders/%commerce_order/view/mail'] = array(
    'title' => 'Email the invoice',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'commerce_invoice_receipt_mail_form',
      3,
    ),
    'access callback' => 'commerce_order_access',
    'access arguments' => array(
      'view',
      3,
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 2,
    'parent' => 'admin/commerce/orders/%commerce_order',
  );
  $items['admin/commerce/orders/%commerce_order/edit/edit'] = array(
    'title' => 'Edit order',
    'page callback' => 'commerce_order_ui_order_form_wrapper',
    'page arguments' => array(
      3,
    ),
    'access callback' => 'commerce_order_access',
    'access arguments' => array(
      'update',
      3,
    ),
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -5,
    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
    'file path' => drupal_get_path('module', 'commerce_order_ui'),
    'file' => 'includes/commerce_order_ui.orders.inc',
  );
  $items['admin/commerce/orders/%commerce_order/edit/print'] = array(
    'title' => 'Printable Invoice',
    'page callback' => 'commerce_invoice_receipt_view_print',
    'page arguments' => array(
      3,
    ),
    'access callback' => 'commerce_order_access',
    'access arguments' => array(
      'view',
      3,
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 1,
    'parent' => 'admin/commerce/orders/%commerce_order',
  );
  $items['admin/commerce/orders/%commerce_order/edit/mail'] = array(
    'title' => 'Email the invoice',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'commerce_invoice_receipt_mail_form',
      3,
    ),
    'access callback' => 'commerce_order_access',
    'access arguments' => array(
      'view',
      3,
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 2,
    'parent' => 'admin/commerce/orders/%commerce_order',
  );
  $items['user/%user/orders/%commerce_order/view'] = array(
    'title' => 'View',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => 0,
  );
  $items['user/%user/orders/%commerce_order/print'] = array(
    'title' => 'Printable Invoice',
    'page callback' => 'commerce_invoice_receipt_view_print',
    'page arguments' => array(
      3,
    ),
    'access callback' => 'commerce_order_customer_order_view_access',
    'access arguments' => array(
      3,
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 1,
  );
  $items['user/%user/orders/%commerce_order/mail'] = array(
    'title' => 'Email the invoice',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'commerce_invoice_receipt_mail_form',
      3,
    ),
    'access callback' => 'commerce_order_access',
    'access arguments' => array(
      'view',
      3,
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 2,
  );
  return $items;
}

/**
 * Implements hook_preprocess_commerce_invoice_receipt().
 */
function commerce_invoice_receipt_preprocess_commerce_invoice_receipt(&$variables) {

  // Get the CSS path.
  $css_path = _commerce_invoice_receipt_css_path();

  // Get the contents of target CSS file. This way we can print the styles
  // directly in the template file, and make it work with Emogrifier.
  $css_styles = file_get_contents($css_path);

  // Make this available in our template.
  $variables['styles'] = $css_styles;
}

/**
 * Menu callback, render invoice.
 */
function commerce_invoice_receipt_view_print($order, $view_mode = 'invoice', $breadcrumb = TRUE) {
  $build = entity_view('commerce_order', array(
    $order->order_id => $order,
  ), $view_mode, NULL, TRUE);
  $invoice_info = _commerce_invoice_receipt_get_invoice_info($order, $build);

  // Theme order invoice.
  $html = theme('commerce_invoice_receipt', array(
    'info' => $invoice_info,
    'order' => $order,
  ));

  // Print formatted output.
  print _commerce_invoice_receipt_prepare_output($html);
}

/**
 * Implements hook_entity_info_alter().
 */
function commerce_invoice_receipt_entity_info_alter(&$entity_info) {
  $entity_info['commerce_order']['view modes']['invoice'] = array(
    'label' => t('Invoice/Receipt'),
    'custom settings' => TRUE,
  );
}

/**
 * Implements hook_theme().
 */
function commerce_invoice_receipt_theme() {

  // Get current default theme
  $default_theme_path = drupal_get_path('theme', variable_get('theme_default', NULL));
  $default_template_path = drupal_get_path('module', 'commerce_invoice_receipt') . '/theme';

  // Check if the template has been copied in the front end theme.
  //
  // A manual check is necessary because otherwise Drupal will not find the
  // template override in the front end theme, when the site uses an admin theme
  // (e.g. when an administrator tries to see printable invoice from the back
  // end).
  //
  // This way the template will always be fetched from the front end theme if
  // there is one.
  //
  // Also, this way the template file can be located anywhere in the front end
  // theme (root, templates/, invoice/, or any other subfolder).
  $files = file_scan_directory($default_theme_path, '/commerce-invoice-receipt.tpl.php$/');
  if (count($files)) {
    $first = reset($files);
    $default_template_path = dirname($first->uri);
  }
  return array(
    'commerce_invoice_receipt' => array(
      'variables' => array(
        'info' => NULL,
        'order' => NULL,
      ),
      'path' => $default_template_path,
      'template' => 'commerce-invoice-receipt',
    ),
  );
}

/**
 * Implements hook_mail().
 */
function commerce_invoice_receipt_mail($key, &$message, $params) {

  // Set the default language.
  $langcode = isset($message['language']) ? $message['language']->language : NULL;
  $options = array(
    'langcode' => $langcode,
    'context' => '',
  );
  switch ($key) {

    // Setup an e-mailed invoice.
    case 'invoice':
      $build = entity_view('commerce_order', array(
        $params['order']->order_id => $params['order'],
      ), 'invoice', NULL, TRUE);
      $invoice_info = _commerce_invoice_receipt_get_invoice_info($params['order'], $build);

      // Prepare the message headers.
      if (isset($params['headers'])) {
        $message['headers'] = $params['headers'];
      }
      $message['headers']['Content-Type'] = 'text/html; charset=UTF-8; format=flowed;';
      if (isset($params['cc'])) {
        $message['headers']['Cc'] = $params['cc'];
      }
      if (isset($params['bcc'])) {
        $message['headers']['Bcc'] = $params['bcc'];
      }

      // Get the email subject.
      $message['subject'] = $params['subject'];

      // Theme order invoice.
      $html = theme('commerce_invoice_receipt', array(
        'info' => $invoice_info,
        'order' => $params['order'],
      ));

      // Get formatted output.
      $message['body'][] = _commerce_invoice_receipt_prepare_output($html);
      break;
  }
}

/**
 * Set recipients of an invoice, and mail it.
 *
 * @ingroup forms
 * @see
 *   commerce_invoice_receipt_mail_form_validate()
 *   commerce_invoice_receipt_mail_form_submit()
 */
function commerce_invoice_receipt_mail_form($form_state, $order) {

  // Store the order ID.
  $form['order_id'] = array(
    '#type' => 'hidden',
    '#value' => $order['build_info']['args'][0]->order_id,
  );

  // Recipient email address.
  //
  // Prepare the description text. Users who can manage orders should be able to
  // send the invoice to multiple emails at once.
  if (user_access('administer commerce_order entities')) {
    $description = t('Please enter an email address where you want to receive another copy of the invoice. You may enter multiple email addresses, separated with a comma.');
  }
  else {
    $description = t('Please enter an email address where you want to receive another copy of the invoice.');
  }

  // Form field.
  $form['email'] = array(
    '#type' => 'textfield',
    '#title' => t('Recipient e-mail address'),
    '#description' => $description,
    '#default_value' => $order['build_info']['args'][0]->mail,
    '#required' => TRUE,
  );

  // Form actions.
  $form['actions'] = array(
    '#type' => 'actions',
  );
  $form['actions']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Email invoice'),
  );
  return $form;
}

/**
 * Form validation handler for the commerce_invoice_receipt_mail_form().
 *
 * @see commerce_invoice_receipt_mail_form()
 */
function commerce_invoice_receipt_mail_form_validate($form, &$form_state) {
  $input = check_plain($form_state['values']['email']);

  // Validation rules for administrators.
  if (user_access('administer commerce_order entities')) {
    $recipients = explode(',', $input);

    // Since we will need to loop through all recipients (if there are more),
    // and need to show only one form validation error message, we will use a
    // flag that will indicate whether or not this should be displayed.
    $invalid_recipients = FALSE;
    foreach ($recipients as $recipient) {

      // Trim the recipient email address. We need to do this in case the user
      // separated the addresses with a space and a comma (", ").
      $recipient = trim($recipient);

      // Check if the email is valid.
      if (!valid_email_address($recipient)) {
        $invalid_recipients = TRUE;
      }
    }

    // Show the validation message.
    if ($invalid_recipients) {
      form_set_error('email', t('Please enter a valid email address(es). Multiple emails should be separated with a comma.'));
    }
  }
  elseif (!valid_email_address($input)) {
    form_set_error('email', t('Please enter a valid email address.'));
  }
}

/**
 * Form submit handler for the commerce_invoice_receipt_mail_form().
 *
 * @see commerce_invoice_receipt_mail_form()
 */
function commerce_invoice_receipt_mail_form_submit($form, &$form_state) {

  // Load the order.
  $order = commerce_order_load($form_state['values']['order_id']);

  // Default event we will invoke is the one for the front end.
  $event = 'commerce_invoice_receipt_rules_event_invoice_from_front';

  // However, if the current path is an administrative one, invoke a different
  // event. By default there is no difference, but this provides greater
  // flexibility to site builders.
  if (path_is_admin(current_path())) {
    $event = 'commerce_invoice_receipt_rules_event_invoice_from_admin';
  }

  // Invoke our event.
  rules_invoke_event($event, $order, check_plain($form_state['values']['email']));
}

/**
 * Helper function - generate an array for rendering all the invoice info.
 */
function _commerce_invoice_receipt_get_invoice_info($order, $build) {
  $info = array(
    'order_uid' => $order->uid,
    'order_created' => $order->created,
    'order_changed' => $order->changed,
    'order_number' => $order->order_number,
    'order_mail' => $order->mail,
    'order_status' => $order->status,
    'site_logo' => theme_get_setting('logo', variable_get('theme_default', NULL)),
  );

  // Adding a drupal_alter for other modules to edit the $info array prior to
  // being displayed.
  drupal_alter('commerce_invoice_receipt_info', $info, $order, $build);
  if (isset($build['commerce_order'][$order->order_id]['commerce_customer_shipping'])) {
    $info['customer_shipping'] = $build['commerce_order'][$order->order_id]['commerce_customer_shipping'][0]['#markup'];
  }
  if (isset($build['commerce_order'][$order->order_id]['commerce_customer_billing'][0]['#markup'])) {
    $info['customer_billing'] = $build['commerce_order'][$order->order_id]['commerce_customer_billing'][0]['#markup'];
  }
  if (isset($build['commerce_order'][$order->order_id]['commerce_line_items'])) {
    $info['line_items'] = $build['commerce_order'][$order->order_id]['commerce_line_items'][0]['#markup'];
  }
  if (isset($build['commerce_order'][$order->order_id]['commerce_order_total'])) {
    $info['order_total'] = $build['commerce_order'][$order->order_id]['commerce_order_total'][0]['#markup'];
  }
  return $info;
}

/**
 * Helper function - locate default CSS path.
 */
function _commerce_invoice_receipt_css_path() {

  // Get current default theme
  $default_theme_path = drupal_get_path('theme', variable_get('theme_default', NULL));
  $default_template_css = drupal_get_path('module', 'commerce_invoice_receipt') . '/theme/commerce_invoice_receipt.css';

  // Check if the default theme wants to override the invoice stylesheet.
  $files = file_scan_directory($default_theme_path, '/commerce_invoice_receipt.css$/');
  if (count($files)) {
    $default_template_css = key($files);
  }
  return $default_template_css;
}

/**
 * Helper function - prepare the content, depending on whether or not Emogrifier
 * module is installed.
 */
function _commerce_invoice_receipt_prepare_output($html) {

  // Since this module doesn't require Emogrifier, by default we will return the
  // same HTML output.
  $output = $html;

  // If Emogrifier module is installed, process the HTML with styles.
  if (module_exists('emogrifier')) {
    $output = _emogrifier_process($html, NULL, NULL, NULL, NULL, NULL);
  }
  elseif (module_exists('mimemail_compress')) {
    module_load_include('inc', 'mimemail_compress');

    // Separate CSS from HTML for processing.
    $parts = mimemail_compress_clean_message($html);

    // Compress HTML and CSS into combined message.
    if (!empty($parts)) {
      $output = new mimemail_compress($parts['html'], $parts['css']);
      $output = $output
        ->compress();
    }
  }
  return $output;
}

Functions

Namesort descending Description
commerce_invoice_receipt_entity_info_alter Implements hook_entity_info_alter().
commerce_invoice_receipt_mail Implements hook_mail().
commerce_invoice_receipt_mail_form Set recipients of an invoice, and mail it.
commerce_invoice_receipt_mail_form_submit Form submit handler for the commerce_invoice_receipt_mail_form().
commerce_invoice_receipt_mail_form_validate Form validation handler for the commerce_invoice_receipt_mail_form().
commerce_invoice_receipt_menu Implements hook_menu().
commerce_invoice_receipt_preprocess_commerce_invoice_receipt Implements hook_preprocess_commerce_invoice_receipt().
commerce_invoice_receipt_theme Implements hook_theme().
commerce_invoice_receipt_view_print Menu callback, render invoice.
_commerce_invoice_receipt_css_path Helper function - locate default CSS path.
_commerce_invoice_receipt_get_invoice_info Helper function - generate an array for rendering all the invoice info.
_commerce_invoice_receipt_prepare_output Helper function - prepare the content, depending on whether or not Emogrifier module is installed.