Additonal charges is a method of allowing the store owner to pass in additional cost/discounts to customers. The order of these charges is important because variables will include amounts that were calculated in prior charges. This may affect how much is calculated for discounts or tax.

'); } } /** * Implements hook_menu(). */ function ec_charge_menu() { $items = array(); $items['admin/config/store/charge'] = array( 'title' => 'Additional charges', 'page callback' => 'drupal_get_form', 'page arguments' => array('ec_charge_admin_list'), 'access arguments' => array('store admin manage'), 'description' => 'Manage additional charges.', 'file' => 'ec_charge.admin.inc', ); $items['admin/config/store/charge/list'] = array( 'title' => 'List', 'access arguments' => array('store admin manage'), 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -9, 'file' => 'ec_charge.admin.inc', ); $items['admin/config/store/charge/add'] = array( 'title' => 'Add charge', 'page callback' => 'drupal_get_form', 'page arguments' => array('ec_charge_admin_edit_form'), 'access arguments' => array('store admin manage'), 'type' => MENU_LOCAL_ACTION, 'file' => 'ec_charge.admin.inc', ); $items['admin/config/store/charge/%ec_charge/edit'] = array( 'title callback' => 'ec_charge_admin_title', 'title arguments' => array('Edit', 4), 'page callback' => 'drupal_get_form', 'page arguments' => array('ec_charge_admin_edit_form', 5), 'access arguments' => array('store admin manage'), 'type' => MENU_CALLBACK, 'file' => 'ec_charge.admin.inc', ); $items['store/%ctools_js/charge-component-add/%/%'] = array( 'title' => 'Select component', 'page callback' => 'ec_charge_admin_edit_add_component', 'page arguments' => array(3, 4, 1), 'access arguments' => array('store admin manage'), 'type' => MENU_CALLBACK, 'file' => 'ec_charge.admin.inc', ); $items['store/%ctools_js/charge-component/%/%/add/%'] = array( 'title' => 'Add component', 'page callback' => 'ec_charge_admin_edit_component', 'page arguments' => array('add', 3, 4, 6, 1), 'access arguments' => array('store admin manage'), 'type' => MENU_CALLBACK, 'file' => 'ec_charge.admin.inc', ); $items['store/%ctools_js/charge-component/%/%/%/edit'] = array( 'title' => 'Edit component', 'page callback' => 'ec_charge_admin_edit_component', 'page arguments' => array('edit', 3, 4, 5, 1), 'access arguments' => array('store admin manage'), 'type' => MENU_CALLBACK, 'file' => 'ec_charge.admin.inc', ); $items['store/%ctools_js/charge-component/%/%/%/delete'] = array( 'title' => 'Delete component', 'page callback' => 'ec_charge_admin_delete_component', 'page arguments' => array(3, 4, 5, 1), 'access arguments' => array('store admin manage'), 'type' => MENU_CALLBACK, 'file' => 'ec_charge.admin.inc', ); $items['admin/config/store/charge/import'] = array( 'title' => 'Import', 'page callback' => 'drupal_get_form', 'page arguments' => array('ec_charge_admin_import_form'), 'access arguments' => array('store admin manage'), 'type' => MENU_LOCAL_ACTION, 'file' => 'ec_charge.admin.inc', ); $items['admin/config/store/charge/%ec_charge/delete'] = array( 'title callback' => 'ec_charge_admin_title', 'title arguments' => array('Delete', 4), 'page callback' => 'drupal_get_form', 'page arguments' => array('ec_charge_admin_delete_confirm', 4), 'access arguments' => array('store admin manage'), 'type' => MENU_CALLBACK, 'file' => 'ec_charge.admin.inc', ); $items['admin/config/store/charge/%ec_charge/enable'] = array( 'title callback' => 'ec_charge_admin_title', 'title arguments' => array('Enable', 4), 'page callback' => 'drupal_get_form', 'page arguments' => array('ec_charge_admin_enable_confirm', 4), 'access callback' => 'ec_charge_admin_enable_access', 'access arguments' => array(3), 'type' => MENU_CALLBACK, 'file' => 'ec_charge.admin.inc', ); $items['admin/config/store/charge/%ec_charge/disable'] = array( 'title callback' => 'ec_charge_admin_title', 'title arguments' => array('Disable', 3), 'page callback' => 'drupal_get_form', 'page arguments' => array('ec_charge_admin_disable_confirm', 4), 'access callback' => 'ec_charge_admin_disable_access', 'access arguments' => array(3), 'type' => MENU_CALLBACK, 'file' => 'ec_charge.admin.inc', ); $items['admin/config/store/charge/%ec_charge/export'] = array( 'title callback' => 'ec_charge_admin_title', 'title arguments' => array('Export', 3), 'page callback' => 'drupal_get_form', 'page arguments' => array('ec_charge_admin_export', 4), 'access arguments' => array('store admin manage'), 'type' => MENU_CALLBACK, 'file' => 'ec_charge.admin.inc', ); return $items; } /** * Implements hook_theme(). */ function ec_charge_theme() { return array( 'ec_charge_component_form' => array( 'render element' => 'form', 'file' => 'ec_charge.theme.inc', ), 'ec_charge_admin_list_table' => array( 'render element' => 'form', 'file' => 'ec_charge.theme.inc', ), 'ec_charge_variable_description' => array( 'variables' => array('descriptions' => array()), 'path' => drupal_get_path('module', 'ec_charge') . '/templates', 'template' => 'ec-charge-variable-description', 'file' => 'theme.inc', ), 'ec_charge_variable_description_row' => array( 'variables' => array( 'key' => NULL, 'description' => NULL, ), 'path' => drupal_get_path('module', 'ec_charge') . '/templates', 'template' => 'ec-charge-variable-description-row', 'file' => 'theme.inc', ), 'ec_charge_add_component' => array( 'variables' => array( 'name' => NULL, 'type' => NULL, 'category' => NULL, ), 'path' => drupal_get_path('module', 'ec_charge') . '/templates', 'template' => 'ec-charge-add-component', 'file' => 'theme.inc', ), ); } /** * Save Charge */ function ec_charge_save($chg) { $update = (isset($chg->chgid) && is_numeric($chg->chgid)) ? array('chgid') : array(); drupal_write_record('ec_charge', $chg, $update); } function _ec_charge_filter_new($a) { return isset($a['new']) && $a['new'] ? TRUE : FALSE; } /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function ec_charge_load($names) { ctools_include('export'); $result = ctools_export_load_object('ec_charge', 'names', array($name)); if (isset($result[$name])) { return $result[$name]; } } /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function ec_charge_delete($chgid) { db_delete('ec_charge') ->condition('chgid', $chgid) ->execute(); } /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function ec_charge_load_incs() { $loaded = & drupal_static(__FUNCTION__ . '_loaded', FALSE); if ($loaded) { return; } $path = drupal_get_path('module', 'ec_charge') . '/modules/'; foreach (module_list() as $module) { $file = $path . '/' . $module . '.inc'; if (is_file($file)) { require_once DRUPAL_ROOT . '/' . $file; } } $loaded = TRUE; } /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function ec_charge_get_info($type, $action = 'types', $callback = '') { $components = & drupal_static(__FUNCTION__ . '_components', array()); $component_names = & drupal_static(__FUNCTION__ . '_component_names', array()); if (!isset($components[$type])) { $components[$type] = array(); $core_path = drupal_get_path('module', 'ec_charge') . '/modules'; ec_charge_load_incs(); $hook = 'ec_charge_' . $type . '_info'; foreach (module_implements($hook) as $module) { $infos = module_invoke($module, $hook); foreach ($infos as $type_name => $info) { $info['type'] = $type_name; if (!isset($info['module'])) { $info['module'] = $module; } if (!isset($info['path'])) { if (isset($info['core']) && $info['core']) { $info['path'] = $core_path; } else { $info['path'] = drupal_get_path('module', $module); } } if (isset($info['file']) && !isset($info['include'])) { $info['include'] = $info['path'] . '/' . $info['file']; } $components[$type][$type_name] = $info; } } uasort($components[$type], 'ec_sort'); $component_names[$type] = array_map('_ec_charge_extract_names', $components[$type]); } if (($action == 'type' || $action == 'name') && empty($components[$type][$callback])) { return; } switch ($action) { case 'types': return $components[$type]; break; case 'type': return $components[$type][$callback]; break; case 'names': return $component_names[$type]; break; case 'name': return $component_names[$type][$callback]; break; } } function _ec_charge_extract_names($a) { return $a['name']; } /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function ec_charge_get_callback_function($type, $component, $hook) { $info = ec_charge_get_info($type, 'type', $component); if (isset($info['include'])) { require_once DRUPAL_ROOT . '/' . $info['include']; } $function = $info['module'] . '_' . $type . '_' . $hook; if (function_exists($function)) { return $function; } } /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function ec_charge_invoke_callback() { $args = func_get_args(); $type = array_shift($args); $component = array_shift($args); $hook = array_shift($args); if ($function = ec_charge_get_callback_function($type, $component, $hook)) { return call_user_func_array($function, $args); } } /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function ec_charge_admin_title($prefix, $chg) { return $prefix . ' ' . $chg->name; } /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function ec_charge_admin_enable_access($chg) { return user_access('store admin manage') && !$chg->enabled; } /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function ec_charge_admin_disable_access($chg) { return user_access('store admin manage') && $chg->enabled; } /** * Implements hook_checkout_info(). */ function ec_charge_checkout_info() { return array( 'charge' => array( 'name' => t('Charges'), 'description' => t('Implements charges into the checkout process.'), 'module' => 'ec_charge', 'file' => 'ec_charge.checkout.inc', 'weight' => 99, ), ); } /** * Test all the filters on this charge and make sure they are all TRUE */ function ec_charge_filter_charges($chg, $type, $object, $charges) { foreach ($chg->filters as $filter) { // Filter only handles components with a parent = 0. The child components are handled by the parent. if (!isset($filter['parent']) or $filter['parent'] == '0') { $ret = ec_charge_invoke_callback('filter', $filter['component'], 'process', $type, $filter, $object, $charges, $chg); if ($filter['reverse']) { $ret = !$ret; } if ($ret === FALSE) { return FALSE; } } } return TRUE; } /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function ec_charge_get_variables($chg, $type, $object, $charges = array()) { $variables = module_invoke_all('ec_charge_default_variables', $type, $object, $charges); foreach ($chg->variables as $settings) { $ret = ec_charge_invoke_callback('variable', $settings['component'], 'process', $type, $settings, $object, $charges); if (!is_null($ret) && is_numeric($ret)) { $variables[$settings['name']] = $ret; } elseif (is_array($ret)) { foreach ($ret as $key => $value) { if (is_numeric($value)) { if (!isset($variables[$settings['name']])) { $variables[$settings['name']] = $value; } $variables[$settings['name'] . ':' . $key] = $value; } } } else { $variables[$settings['name']] = 0; } } return $variables; } /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function ec_charge_get_variables_description($chg, $type, $object, $variables) { $descriptions = module_invoke_all('ec_charge_default_variables_description', $type, $object, $variables); foreach ($chg->variables as $settings) { $ret = ec_charge_invoke_callback('variable', $settings['component'], 'description', $type, $settings, $object, $variables); if (!is_null($ret) && !is_array($ret)) { $descriptions[$settings['name']] = $ret; } elseif (is_array($ret)) { foreach ($ret as $key => $value) { if (!isset($descriptions[$settings['name']])) { $descriptions[$settings['name']] = $value; } $descriptions[$settings['name'] . ':' . $key] = $value; } } } foreach (array_diff_key($variables, $descriptions) as $key => $value) { $descriptions[$key] = ''; } return $descriptions; } /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function ec_charge_create_charges($chg, $type, $object, $charges) { $misc = array(); $variables = ec_charge_get_variables($chg, $type, $object, $charges); foreach ($chg->calculations as $calc) { $default = array( 'type' => 'MT-' . $chg->name, 'description' => $chg->description, 'weight' => $chg->weight, 'misc_group' => $chg->chg_group, ); $ret = ec_charge_invoke_callback('calculation', $calc['component'], 'process', $type, $calc, $variables, $object, $charges); if (is_array($ret)) { if (isset($calc['multiple']) && $calc['multiple']) { foreach ($ret as $key => $item) { $ret[$key] += $default; } $misc = array_merge($misc, $ret); } else { $ret += $default; $misc[] = $ret; } $variables['last_calc'] = $ret['price']; } else { unset($variables['last_calc']); } } foreach ($chg->modifications as $modification) { $ret = ec_charge_invoke_callback('modification', $modification['component'], 'process', $type, $modification, $misc, $object); if (!is_null($ret)) { $misc = $ret; } } return $misc; } /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function ec_charge_product_charges($node, $type, $price_only = FALSE) { ctools_include('export'); $current_charge = & drupal_static(__FUNCTION__ . '_current_charge', ''); $charges = array(); $items = array(); $value = 0; $charges = ctools_export_load_object('ec_charge', 'conditions', array('enabled' => 1, 'chg_type' => 1)); uasort($charges, 'ec_sort'); foreach ($charges as $chg) { // Stop recurrsion on charges if ($current_charge != $chg->chgid) { $current_charge = $chg->chgid; if (ec_charge_filter_charges($chg, 'node', $node, $items)) { $misc = ec_charge_create_charges($chg, 'node', $node, $items); $defaults = array( 'vid' => $node->vid, 'invisible' => 1, 'qty' => isset($node->qty) && ec_product_has_quantity($node) ? $node->qty : 1, ); foreach ($misc as $item) { $item += $defaults; if (isset($charges[$item['type']])) { $charges[$item['type']]++; $item['type'] .= '-' . $charges[$item['type']]; } else { $charges[$item['type']] = 0; } $items[] = (object) $item; if ($price_only) { $value += $item['price']; } } } } } $current_charge = ''; return $price_only ? $value : $items; } /** * Implements hook_ec_charge_filter_settings_alter(). */ function ec_charge_ec_charge_filter_settings_alter(&$settings, $component, $chg) { $settings[] = 'reverse'; } /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function ec_charge_component_get_parents($type, $params) { $types = ec_charge_get_info($type); $types = array_filter($types, '_ec_charge_component_filter_parents'); if (!empty($types) && !empty($params)) { $components = array_map('_ec_charge_component_map_types', $types); $settings = array_map('_ec_charge_component_map_params', $params); $parents = array_intersect($settings, $components); return empty($parents) ? FALSE : array_keys($parents); } return FALSE; } function _ec_charge_component_filter_parents($a) { return isset($a['parent']) ? $a['parent'] : FALSE; } function _ec_charge_component_map_types($a) { return $a['type']; } function _ec_charge_component_map_params($a) { return $a['component']; } /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function ec_charge_component_get_categories($type, $category = NULL) { $types = ec_charge_get_info($type); $categories = array(); foreach ($types as $id => $type) { $cname = isset($type['category']) ? $type['category'] : t('Miscellaneous'); $categories[$cname][$id] = $type; } ksort($categories); return $categories; }