You are here

commerce_billy.module in Commerce Billy 7

Commerce Billy module.

File

commerce_billy.module
View source
<?php

/**
 * @file
 * Commerce Billy module.
 */

// One single invoice number, never regenerated.
define('COMMERCE_BILLY_INVOICE_METHOD_INFINITE', 'infinite');

// Invoice number is regenerated every year.
define('COMMERCE_BILLY_INVOICE_METHOD_YEARLY', 'yearly');

// Invoice number is regenerated every month.
define('COMMERCE_BILLY_INVOICE_METHOD_MONTHLY', 'monthly');

/**
 * Implements hook_commerce_order_state_info().
 */
function commerce_billy_commerce_order_state_info() {
  return array(
    'invoiced' => array(
      'name' => 'invoiced',
      'title' => t('Invoiced'),
      'description' => t('Orders in this state have been completed and an invoice number + pdf is generated.'),
      'weight' => 15,
      'default_status' => 'invoiced',
    ),
  );
}

/**
 * Implements hook_commerce_order_status_info().
 */
function commerce_billy_commerce_order_status_info() {
  return array(
    'invoiced' => array(
      'name' => 'invoiced',
      'title' => t('Invoiced'),
      'state' => 'invoiced',
    ),
  );
}

/**
 * Implements hook_menu_alter().
 */
function commerce_billy_menu_alter(&$items) {
  $items['admin/commerce/orders/%commerce_order/delete']['access callback'] = 'commerce_billy_order_delete_access';
}

/**
 * Access callback for deleting orders.
 */
function commerce_billy_order_delete_access($op, $order) {

  // Deletion of orders in state 'invoiced' is not allowed.
  if ($order->status == 'invoiced') {
    return FALSE;
  }
  return commerce_order_access($op, $order);
}

/**
 * Sets invoice number on order.
 *
 * Used as Rules action callback.
 *
 * @see commerce_billy_rules_action_info()
 */
function commerce_billy_invoice_nr($order) {

  // Lock down this function so that other requests do not interfere.
  $lock_name = 'commerce_billy_invoice_nr';
  while (!lock_acquire($lock_name)) {
    lock_wait($lock_name);
  }
  $method = variable_get('commerce_billy_invoice_nr_method', COMMERCE_BILLY_INVOICE_METHOD_YEARLY);
  switch ($method) {
    case COMMERCE_BILLY_INVOICE_METHOD_MONTHLY:
      $invoice_nr = commerce_billy_invoice_nr_monthly();
      break;
    case COMMERCE_BILLY_INVOICE_METHOD_YEARLY:
      $invoice_nr = commerce_billy_invoice_nr_yearly();
      break;
    case COMMERCE_BILLY_INVOICE_METHOD_INFINITE:
      $invoice_nr = commerce_billy_invoice_nr_infinite();
      break;
  }

  // Check if we have a unique order number. If not, write a watchdog error and
  // do not change the order number.
  if (!commerce_order_validate_number_unique($invoice_nr, $order->order_id)) {
    watchdog('commerce_billy', 'Error: Order number %number for order %id already exists.', array(
      '%number' => $invoice_nr,
      '%id' => $order->order_id,
    ), WATCHDOG_ERROR);
  }
  else {
    $order->order_number = $invoice_nr;
  }
  lock_release($lock_name);
}

/**
 * Generated monthly invoice number.
 */
function commerce_billy_invoice_nr_monthly() {
  $last_number = commerce_billy_query_variable('commerce_billy_invoice_nr_last');
  $current_year = date('Y');
  $current_month = date('m');
  $id = 1;
  if ($last_number) {
    if ($last_number['year'] == $current_year && $last_number['month'] == $current_month) {
      $id = $last_number['id'] + 1;
    }
  }
  $new_nr_array = array(
    'month' => $current_month,
    'year' => $current_year,
    'id' => $id,
  );
  variable_set('commerce_billy_invoice_nr_last', $new_nr_array);
  return commerce_billy_apply_invoice_nr_pattern($new_nr_array);
}

/**
 * Generated yearly invoice number.
 */
function commerce_billy_invoice_nr_yearly() {
  $last_number = commerce_billy_query_variable('commerce_billy_invoice_nr_last');
  $current_year = date('Y');
  $id = 1;
  if ($last_number) {
    if ($last_number['year'] == $current_year) {
      $id = $last_number['id'] + 1;
    }
  }
  $new_nr_array = array(
    'year' => $current_year,
    'id' => $id,
  );
  variable_set('commerce_billy_invoice_nr_last', $new_nr_array);
  return commerce_billy_apply_invoice_nr_pattern($new_nr_array);
}

/**
 * Generated infinite invoice number.
 */
function commerce_billy_invoice_nr_infinite() {
  $last_number = commerce_billy_query_variable('commerce_billy_invoice_nr_last');
  $id = 1;
  if ($last_number) {
    $id = $last_number['id'] + 1;
  }
  $new_nr_array = array(
    'id' => $id,
  );
  variable_set('commerce_billy_invoice_nr_last', $new_nr_array);
  return commerce_billy_apply_invoice_nr_pattern($new_nr_array);
}

/**
 * Helper function that applies the invoice number pattern by replacing tokens
 * and the {id} placeholder.
 */
function commerce_billy_apply_invoice_nr_pattern($nr_array) {
  $pattern = variable_get('commerce_billy_invoice_nr_pattern', '[date:custom:Y]-{id}');
  $invoice_id = str_pad($nr_array['id'], variable_get('commerce_billy_invoice_nr_padding', 0), '0', STR_PAD_LEFT);
  $new_nr = str_replace('{id}', $invoice_id, $pattern);
  $new_nr = token_replace($new_nr, array(), array(
    'clear' => TRUE,
  ));
  return $new_nr;
}

/**
 * Helper function that directly queries variable values from the database.
 *
 * In certain situations variable_get() cannot be used, as it statically caches
 * the value. e.g. we always need to most recent invoice number.
 *
 * @param string $var_name
 *   The name of the variable.
 */
function commerce_billy_query_variable($var_name) {
  return unserialize(db_select('variable', 'v')
    ->fields('v')
    ->condition('name', $var_name)
    ->execute()
    ->fetchField(1));
}

/**
 * Implements hook_menu().
 */
function commerce_billy_menu() {
  $items['admin/commerce/config/billy-invoice'] = array(
    'title' => 'Billy invoice settings',
    'description' => 'Configure the Billy invoicing settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'commerce_billy_admin_form',
    ),
    'access arguments' => array(
      'configure order settings',
    ),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'commerce_billy.admin.inc',
  );
  $items['admin/commerce/config/billy-invoice/settings'] = array(
    'title' => 'Settings',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );
  return $items;
}

/**
 * Implements hook_flush_caches().
 */
function commerce_billy_flush_caches() {
  $entity_info = entity_get_info('commerce_order');
  $order_types = array_keys($entity_info['bundles']);

  // Allow modules to alter the list of order types to which invoice fields
  // will be added. Some order types might not need the invoice fields.
  drupal_alter('commerce_billy_order_types', $order_types);
  $field_definition = array(
    'type' => 'datestamp',
    'locked' => FALSE,
    'cardinality' => 1,
    'settings' => array(
      'granularity' => array(
        'year' => 'year',
        'month' => 'month',
        'day' => 'day',
        'hour' => 'hour',
        'minute' => 'minute',
        'second' => 'second',
      ),
    ),
  );
  $instance_definition = array(
    'entity_type' => 'commerce_order',
    'required' => FALSE,
    'settings' => array(
      'default_value' => 'blank',
    ),
    'widget' => array(
      'type' => 'date_text',
      'settings' => array(
        'input_format' => 'd.m.Y - H:i:s',
        'no_fieldset' => 0,
      ),
    ),
  );
  $fields = array(
    'field_commerce_billy_cancel_date' => array(
      'label' => 'Cancel date',
      'description' => 'Internally set once the order is cancelled.',
    ),
    'field_commerce_billy_i_date' => array(
      'label' => 'Invoice date',
      'description' => 'Internally set once the order is invoiced',
    ),
  );
  foreach ($fields as $field_name => $field_details) {
    $field = field_info_field($field_name);
    if (!$field) {
      $field = array(
        'field_name' => $field_name,
      ) + $field_definition;
      field_create_field($field);
    }

    // Ensure each order type has an instance of the field.
    foreach ($order_types as $order_type) {
      $instance = field_info_instance('commerce_order', $field_name, $order_type);
      if (!$instance) {
        $instance = array(
          'field_name' => $field_name,
          'bundle' => $order_type,
          'label' => $field_details['label'],
          'description' => $field_details['description'],
        ) + $instance_definition;
        field_create_instance($instance);
      }
    }
  }
}

Functions

Namesort descending Description
commerce_billy_apply_invoice_nr_pattern Helper function that applies the invoice number pattern by replacing tokens and the {id} placeholder.
commerce_billy_commerce_order_state_info Implements hook_commerce_order_state_info().
commerce_billy_commerce_order_status_info Implements hook_commerce_order_status_info().
commerce_billy_flush_caches Implements hook_flush_caches().
commerce_billy_invoice_nr Sets invoice number on order.
commerce_billy_invoice_nr_infinite Generated infinite invoice number.
commerce_billy_invoice_nr_monthly Generated monthly invoice number.
commerce_billy_invoice_nr_yearly Generated yearly invoice number.
commerce_billy_menu Implements hook_menu().
commerce_billy_menu_alter Implements hook_menu_alter().
commerce_billy_order_delete_access Access callback for deleting orders.
commerce_billy_query_variable Helper function that directly queries variable values from the database.

Constants