View source
<?php
require_once 'uc_taxes.ca.inc';
function uc_taxes_help($path, $arg) {
$output = '';
switch ($path) {
case 'admin/store/settings/taxes':
return t('Add tax rates through this page and then use the <a href="!url">conditional actions interface</a> to add conditions to the taxes that limit which orders they are applied to. Especially important are the geographic area conditions for the delivery address. Use the conditions link to jump to a particular tax rate conditions configuration page.', array(
'!url' => url(CA_UI_PATH),
));
}
return $output;
}
function uc_taxes_perm() {
return array(
'configure taxes',
);
}
function uc_taxes_menu() {
$items = array();
$items['admin/store/settings/taxes'] = array(
'title' => 'Tax rates and settings',
'description' => 'Configure the tax rates and settings.',
'page callback' => 'uc_taxes_admin_settings',
'access arguments' => array(
'configure taxes',
),
'type' => MENU_NORMAL_ITEM,
'file' => 'uc_taxes.admin.inc',
);
$items['admin/store/settings/taxes/overview'] = array(
'title' => 'Overview',
'weight' => 0,
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['admin/store/settings/taxes/add'] = array(
'title' => 'Add a tax rate',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'uc_taxes_form',
),
'access arguments' => array(
'configure taxes',
),
'file' => 'uc_taxes.admin.inc',
'weight' => 5,
'type' => MENU_LOCAL_TASK,
);
$items['admin/store/settings/taxes/%/edit'] = array(
'title' => 'Edit a tax rate',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'uc_taxes_form',
4,
),
'access arguments' => array(
'configure taxes',
),
'type' => MENU_CALLBACK,
'file' => 'uc_taxes.admin.inc',
);
$items['admin/store/settings/taxes/%/clone'] = array(
'page callback' => 'uc_taxes_clone',
'page arguments' => array(
4,
),
'access arguments' => array(
'configure taxes',
),
'type' => MENU_CALLBACK,
'file' => 'uc_taxes.admin.inc',
);
$items['admin/store/settings/taxes/%/delete'] = array(
'title' => 'Delete tax rule',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'uc_taxes_delete_form',
4,
),
'access arguments' => array(
'configure taxes',
),
'type' => MENU_CALLBACK,
'file' => 'uc_taxes.admin.inc',
);
$items['taxes/calculate'] = array(
'page callback' => 'uc_taxes_javascript',
'access arguments' => array(
'access content',
),
'type' => MENU_CALLBACK,
);
return $items;
}
function uc_taxes_form_alter(&$form, $form_state, $form_id) {
if ($form_id == 'uc_cart_checkout_form') {
if (isset($form['panes']['payment'])) {
drupal_add_js(array(
'ucTaxWeight' => variable_get('uc_li_tax_weight', 9),
'ucURL' => array(
'calculateTax' => url('taxes/calculate'),
),
), 'setting');
drupal_add_js(drupal_get_path('module', 'uc_taxes') . '/uc_taxes.js');
}
}
elseif ($form_id == 'uc_order_edit_form') {
if (isset($form['quotes'])) {
drupal_add_js(array(
'ucURL' => array(
'calculateTax' => url('taxes/calculate'),
),
), 'setting');
drupal_add_js(drupal_get_path('module', 'uc_taxes') . '/uc_taxes.js');
}
}
}
function uc_taxes_line_item() {
$items[] = array(
'id' => 'tax',
'title' => t('Tax'),
'callback' => 'uc_line_item_tax',
'weight' => 9,
'stored' => TRUE,
'default' => FALSE,
'calculated' => TRUE,
'display_only' => FALSE,
);
$items[] = array(
'id' => 'tax_subtotal',
'title' => t('Subtotal excluding taxes'),
'callback' => 'uc_line_item_tax_subtotal',
'weight' => 7,
'stored' => FALSE,
'calculated' => FALSE,
);
return $items;
}
function uc_taxes_order($op, $arg1, $arg2) {
switch ($op) {
case 'save':
$changes = array();
$callback = _line_item_data('tax', 'callback');
$line_items = $callback('load', $arg1);
$context = array(
'revision' => 'formatted',
'type' => 'line_item',
'subject' => array(
'order' => $arg1,
),
);
if (is_array($arg1->line_items)) {
foreach ($arg1->line_items as $i => $line) {
if ($line['type'] == 'tax') {
$delete = TRUE;
foreach ($line_items as $id => $new_line) {
if ($new_line['title'] == $line['title']) {
if ($new_line['amount'] != $line['amount']) {
$context['subject']['line_item'] = $new_line;
uc_order_update_line_item($line['line_item_id'], $new_line['title'], $new_line['amount'], $new_line['data']);
$arg1->line_items[$i]['amount'] = $new_line['amount'];
$changes[] = t('Changed %title to %amount.', array(
'%amount' => uc_price($new_line['amount'], $context),
'%title' => $new_line['title'],
));
}
unset($line_items[$id]);
$delete = FALSE;
break;
}
}
if ($delete) {
uc_order_delete_line_item($line['line_item_id']);
unset($arg1->line_items[$i]);
$changes[] = t('Removed %title.', array(
'%title' => $line['title'],
));
}
}
}
}
if (is_array($line_items)) {
foreach ($line_items as $line) {
uc_order_line_item_add($arg1->order_id, $line['id'], $line['title'], $line['amount'], $line['weight'], $line['data']);
$line['type'] = 'tax';
$arg1->line_items[] = $line;
$context['subject']['line_item'] = $line;
$changes[] = t('Added %amount for %title.', array(
'%amount' => uc_price($line['amount'], $context),
'%title' => $line['title'],
));
}
}
if (count($changes)) {
uc_order_log_changes($arg1->order_id, $changes);
}
break;
}
}
function uc_line_item_tax($op, $order) {
switch ($op) {
case 'load':
$lines = array();
$taxes = uc_taxes_calculate($order);
foreach ($taxes as $tax) {
$lines[] = array(
'id' => $tax->summed ? 'tax' : 'tax_included',
'title' => $tax->name,
'amount' => $tax->amount,
'weight' => variable_get('uc_li_tax_weight', 9) + $tax->weight / 10,
'data' => $tax->data,
);
}
return $lines;
}
}
function uc_line_item_tax_subtotal($op, $order) {
$amount = 0;
$has_taxes = FALSE;
$different = FALSE;
if (is_array($order->products)) {
foreach ($order->products as $item) {
$amount += $item->price * $item->qty;
}
}
if (is_array($order->line_items)) {
foreach ($order->line_items as $key => $line_item) {
if ($line_item['type'] == 'subtotal') {
continue;
}
if (substr($line_item['type'], 0, 3) != 'tax') {
$amount += $line_item['amount'];
$different = TRUE;
}
else {
$has_taxes = TRUE;
}
}
}
if (isset($order->taxes) && is_array($order->taxes)) {
$has_taxes = TRUE;
}
if ($different && $has_taxes) {
switch ($op) {
case 'cart-preview':
drupal_add_js("if (Drupal.jsEnabled) { \$(document).ready(function() {\n if (window.set_line_item) {\n set_line_item('tax_subtotal', '" . t('Subtotal excluding taxes') . "', " . $amount . ", " . variable_get('uc_li_tax_subtotal_weight', 8) . ");\n }\n })};", 'inline');
break;
case 'load':
return array(
array(
'id' => 'tax_subtotal',
'title' => t('Subtotal excluding taxes'),
'amount' => $amount,
'weight' => variable_get('uc_li_tax_subtotal_weight', 7),
),
);
}
}
}
function uc_taxes_rate_save($rate) {
if (!$rate->id) {
drupal_write_record('uc_taxes', $rate);
}
else {
drupal_write_record('uc_taxes', $rate, array(
'id',
));
}
return $rate;
}
function uc_taxes_rate_load($rate_id = NULL) {
static $rates = array();
if (empty($rates)) {
$result = db_query("SELECT * FROM {uc_taxes} ORDER BY weight");
while ($rate = db_fetch_object($result)) {
$rate->taxed_product_types = unserialize($rate->taxed_product_types);
$rate->taxed_line_items = unserialize($rate->taxed_line_items);
$rates[$rate->id] = $rate;
}
}
if ($rate_id) {
return $rates[$rate_id];
}
else {
return $rates;
}
}
function uc_taxes_rate_delete($rate_id) {
db_query("DELETE FROM {uc_taxes} WHERE id = %d", $rate_id);
ca_delete_predicate('uc_taxes_' . $rate_id);
}
function uc_taxes_calculate($order) {
$taxes = module_invoke_all('calculate_tax', $order);
return $taxes;
}
function uc_taxes_calculate_tax($order) {
global $user;
if (is_numeric($order)) {
$order = uc_order_load($order);
$account = user_load(array(
'uid' => $order->uid,
));
}
elseif ((int) $order->uid) {
$account = user_load(array(
'uid' => intval($order->uid),
));
}
else {
$account = $user;
}
if (!is_object($order)) {
return array();
}
if (empty($order->delivery_postal_code)) {
$order->delivery_postal_code = $order->billing_postal_code;
}
if (empty($order->delivery_zone)) {
$order->delivery_zone = $order->billing_zone;
}
if (empty($order->delivery_country)) {
$order->delivery_country = $order->billing_country;
}
$order->taxes = array();
if (isset($order->order_status)) {
$state = uc_order_status_data($order->order_status, 'state');
$use_same_rates = in_array($state, array(
'payment_received',
'completed',
));
}
else {
$use_same_rates = FALSE;
}
$arguments = array(
'order' => array(
'#entity' => 'uc_order',
'#title' => t('Order'),
'#data' => $order,
),
'tax' => array(
'#entity' => 'tax',
'#title' => t('Tax rule'),
),
'account' => array(
'#entity' => 'user',
'#title' => t('User'),
'#data' => $account,
),
);
$predicates = ca_load_trigger_predicates('calculate_taxes');
foreach (uc_taxes_rate_load() as $tax_rate) {
$tax = clone $tax_rate;
if ($use_same_rates) {
foreach ((array) $order->line_items as $old_line) {
if ($old_line['type'] == 'tax' && $old_line['data']['tax_id'] == $tax->id) {
$tax->rate = $old_line['data']['tax_rate'];
break;
}
}
}
$arguments['tax']['#data'] = $tax;
if (ca_evaluate_conditions($predicates['uc_taxes_' . $tax->id], $arguments)) {
$line_item = uc_taxes_action_apply_tax($order, $tax);
if ($line_item) {
$order->taxes[$line_item->id] = $line_item;
}
}
}
return $order->taxes;
}
function uc_taxes_javascript() {
$order = $_POST['order'];
if ($order = unserialize(rawurldecode($order))) {
$taxes = module_invoke_all('calculate_tax', $order);
$callback = _line_item_data('tax_subtotal', 'callback');
if (function_exists($callback)) {
$subtotal = $callback('load', $order);
if (is_array($subtotal) && !empty($taxes)) {
$taxes['subtotal'] = (object) array(
'id' => 'subtotal',
'name' => $subtotal[0]['title'],
'amount' => $subtotal[0]['amount'],
'weight' => -10,
'summed' => 0,
);
}
}
}
drupal_json((array) $taxes);
}
function uc_taxes_apply_item_tax($item, $tax) {
$node = node_load($item->nid);
if (!$node) {
$node = new stdClass();
$node->type = 'blank-line';
$node->shippable = $item->weight > 0;
}
if (in_array($node->type, $tax->taxed_product_types) && ($tax->shippable == 0 || $node->shippable == 1)) {
$context = array(
'revision' => 'altered',
'type' => 'cart_item',
'subject' => array(
'cart_item' => $item,
'node' => $item->nid ? $node : FALSE,
),
);
$price_info = array(
'price' => $item->price,
'qty' => $item->qty,
);
return uc_price($price_info, $context);
}
}
function uc_taxes_apply_tax($order, $tax) {
$amount = 0;
$taxable_amount = 0;
if (is_array($order->products)) {
foreach ($order->products as $item) {
$taxable_amount += uc_taxes_apply_item_tax($item, $tax);
}
}
$taxed_line_items = $tax->taxed_line_items;
if (is_array($order->line_items) && is_array($taxed_line_items)) {
foreach ($order->line_items as $key => $line_item) {
if ($line_item['type'] == 'tax') {
continue;
}
if (in_array($line_item['type'], $taxed_line_items)) {
$callback = _line_item_data($line_item['type'], 'tax_adjustment');
if (isset($callback) && function_exists($callback)) {
$taxable_amount += $callback($line_item['amount'], $order, $tax) / $tax->rate;
}
else {
$taxable_amount += $line_item['amount'];
}
}
}
}
if (isset($taxed_line_items['tax'])) {
foreach ($order->taxes as $other_tax) {
$taxable_amount += $other_tax->amount;
}
}
$amount = $taxable_amount * $tax->rate;
if ($amount) {
$line_item = (object) array(
'id' => $tax->id,
'name' => $tax->name,
'amount' => $amount,
'weight' => $tax->weight,
'summed' => 1,
);
$line_item->data = array(
'tax_id' => $tax->id,
'tax_rate' => $tax->rate,
'taxable_amount' => $taxable_amount,
'tax_jurisdiction' => $tax->name,
);
return $line_item;
}
}