=== modified file 'uc_order/uc_order.install' --- uc_order/uc_order.install 2009-01-30 15:57:34 +0000 +++ uc_order/uc_order.install 2009-02-26 14:41:25 +0000 @@ -370,6 +370,10 @@ 'not null' => TRUE, 'default' => 0, ), + 'data' => array( + 'description' => t('Serialized array of extra data.'), + 'type' => 'text', + ), ), 'indexes' => array( 'order_id' => array('order_id'), @@ -907,3 +911,13 @@ return $ret; } + +// add data field to uc_order_line_items +function uc_order_update_6007() { + + $ret = array(); + + db_add_field($ret, 'uc_order_line_items', 'data', array('type' => 'text')); + + return $ret; +} === modified file 'uc_order/uc_order.line_item.inc' --- uc_order/uc_order.line_item.inc 2008-10-15 20:20:43 +0000 +++ uc_order/uc_order.line_item.inc 2009-02-26 14:41:25 +0000 @@ -91,12 +91,12 @@ return TRUE; } -function uc_order_line_item_add($order_id, $type, $title, $amount, $weight = NULL) { +function uc_order_line_item_add($order_id, $type, $title, $amount, $weight = NULL, $data = NULL) { if (is_null($weight)) { $weight = _line_item_data($type, 'weight'); } - db_query("INSERT INTO {uc_order_line_items} (order_id, type, title, amount, weight) VALUES (%d, '%s', '%s', %f, %d)", $order_id, $type, $title, $amount, $weight); + db_query("INSERT INTO {uc_order_line_items} (order_id, type, title, amount, weight, data) VALUES (%d, '%s', '%s', %f, %d, '%s')", $order_id, $type, $title, $amount, $weight, serialize( $data )); return TRUE; } === modified file 'uc_order/uc_order.module' --- uc_order/uc_order.module 2009-02-20 18:39:24 +0000 +++ uc_order/uc_order.module 2009-02-26 14:41:25 +0000 @@ -1180,6 +1180,7 @@ 'title' => $row->title, 'amount' => $row->amount, 'weight' => $row->weight, + 'data' => unserialize( $row->data ), ); } } @@ -1198,6 +1199,7 @@ 'title' => $line['title'], 'amount' => $line['amount'], 'weight' => isset($line['weight']) ? $line['weight'] : $type['weight'], + 'data' => $line['data'], ); } } @@ -1436,6 +1438,7 @@ 'title' => $line['title'], 'amount' => $line['amount'], 'weight' => $item['weight'], + 'data' => $item['data'], ); } } === added directory 'uc_tax_report' === added file 'uc_tax_report/uc_tax_report.info' --- uc_tax_report/uc_tax_report.info 1970-01-01 00:00:00 +0000 +++ uc_tax_report/uc_tax_report.info 2009-02-13 23:24:03 +0000 @@ -0,0 +1,8 @@ +; $Id$ +name = Tax Report +description = View a report about sales tax your customers paid. +dependencies[] = uc_reports +dependencies[] = uc_taxes +package = "Ubercart - core (optional)" +core = 6.x +php = 5.0 === added file 'uc_tax_report/uc_tax_report.module' --- uc_tax_report/uc_tax_report.module 1970-01-01 00:00:00 +0000 +++ uc_tax_report/uc_tax_report.module 2009-02-26 14:47:28 +0000 @@ -0,0 +1,232 @@ + 'Sales tax report', + 'description' => 'View report on sales tax', + 'page callback' => 'uc_tax_report_report_page', + 'access arguments' => array('view reports'), + 'type' => MENU_NORMAL_ITEM, + ); + + return $items; +} + +// Displays the sales tax report form and table. +function uc_tax_report_report_page() { + $timezone = _uc_reports_timezone_offset(); + $timezone_offset = time() + $timezone; + $format = variable_get('uc_date_format_default', 'm/d/Y'); + + // Use default report parameters if we don't detect values in the URL. + if (arg(4) == '') { + $args = array( + 'start_date' => gmmktime(0, 0, 0, gmdate('n', $timezone_offset), 1, gmdate('Y', $timezone_offset) - 1), + 'end_date' => time(), + 'status' => FALSE, + ); + } + else { + $args = array( + 'start_date' => arg(4), + 'end_date' => arg(5), + 'status' => explode(',', urldecode(arg(6))), + ); + } + + // Pull the order statuses into a SQL friendly array. + if ($args['status'] === FALSE) { + $order_statuses = _uc_reports_order_statuses(); + } + else { + $order_statuses = "('". implode("', '", $args['status']) ."')"; + } + + // Build the header for the report table. + $header = array(t('Tax Name'), t('Jurisdiction'), t('Tax rate'), t('Total taxable amount'), t('Total tax collected')); + $rows = array(); + $csv_rows = array(); + $csv_rows[] = $header; + + // Query to get the tax line items in this date range + + $result = db_query("SELECT ucoli.amount, ucoli.title, ucoli.data FROM {uc_orders} ucord LEFT JOIN {uc_order_statuses} ON order_status_id = order_status LEFT JOIN {uc_order_line_items} ucoli ON ucord.order_id = ucoli.order_id WHERE %d <= created AND created <= %d AND order_status IN $order_statuses AND ucoli.type = 'tax'", $args['start_date'], $args['end_date']); + + // add up the amounts by jurisdiction + $totals = array(); + $no_meta_totals = array(); + + while($item = db_fetch_object($result)) { + $name = trim($item->title); + $amt = floatval($item->amount); + + // get the meta-data out of the serialized array + $dat = unserialize($item->data); + $jur = trim($dat['tax_jurisdiction']); + $tamt = floatval($dat['taxable_amount']); + $rate = floatval($dat['tax_rate']); + + // make a line item in the report for each name/jurisdiction/rate + $key = strtolower($name) . strtolower($jur) . number_format($rate, 5); + + if(!empty($jur) && $amt && $tamt) { + // we have meta-data + if(empty($totals[ $key ])) { + $totals[ $key ] = array($name, $jur, $rate, $tamt, $amt); + } else { + $totals[ $key ][3] += $tamt; + $totals[ $key ][4] += $amt; + } + } else if($amt) { + // old data - no meta-data was stored - just report the amount collected + if(empty($no_meta_totals[$key ])) { + $no_meta_totals[$key] = array($name, $amt); + } else { + $no_meta_totals[$key][1] += $amt; + } + } + } + + // sort and make this into a report + + ksort($totals); + ksort($no_meta_totals); + $tamt = 0; + $amt = 0; + $starleg = ''; + + foreach($totals as $line) { + $row = array($line[0], $line[1], number_format($line[2] * 100, 3) . '%', + uc_currency_format($line[3]), + uc_currency_format($line[4])); + $rows[] = $row; + $csv_rows[] = $row; + $tamt += $line[3]; + $amt += $line[4]; + } + + foreach($no_meta_totals as $line) { + $row = array($line[0], '*', '*', '*', + uc_currency_format($line[1])); + $rows[] = $row; + $csv_rows[] = $row; + $amt += $line[1]; + // we have at least one no-meta-data line - explain why + $starleg = t('* No information on jurisdiction, tax rate, or taxable amount is available for this line.'); + } + + // add a totals line + + $row = array(t('Total'), '', '', uc_currency_format($tamt), + uc_currency_format($amt)); + $rows[] = $row; + $csv_rows[] = $row; + + // Cache the CSV export. + $csv_data = uc_reports_store_csv('uc_tax_report', $csv_rows); + + // Build the page output holding the form, table, and CSV export link. + $output = drupal_get_form('uc_tax_report_params_form', $args, $args['status']); + $output .= theme('table', $header, $rows, array('width' => '100%', 'class' => 'uc-sales-table')); + if($starleg) { + $output .= '

' . $starleg . '

'; + } + + $output .= ''; + + return $output; +} + +// Form for parms on the tax report +function uc_tax_report_params_form($form_state, $values) { + $form = array(); + $form['params'] = array( + '#type' => 'fieldset', + '#title' => t('Customize tax report parameters'), + '#description' => t('Adjust these values and update the report to build your sales tax report. Once submitted, the report may be bookmarked for easy reference in the future.'), + '#collapsible' => TRUE, + '#collapsed' => FALSE, + ); + + $form['params']['start_date'] = array( + '#type' => 'date', + '#title' => t('Start date'), + '#default_value' => array( + 'month' => format_date($values['start_date'], 'custom', 'n', 0), + 'day' => format_date($values['start_date'], 'custom', 'j', 0), + 'year' => format_date($values['start_date'], 'custom', 'Y', 0), + ), + ); + $form['params']['end_date'] = array( + '#type' => 'date', + '#title' => t('End date'), + '#default_value' => array( + 'month' => format_date($values['end_date'], 'custom', 'n', 0), + 'day' => format_date($values['end_date'], 'custom', 'j', 0), + 'year' => format_date($values['end_date'], 'custom', 'Y', 0), + ), + ); + + $options = array(); + foreach (uc_order_status_list() as $status) { + $options[$status['id']] = $status['title']; + } + + $stat = $values['status']; + if ($stat === FALSE) { + $stat = variable_get('uc_reports_reported_statuses', array('completed')); + } + + $form['params']['status'] = array( + '#type' => 'select', + '#title' => t('Order statuses'), + '#description' => t('Only orders with selected statuses will be included in the report.') .'
'. t('Hold Ctrl + click to select multiple statuses.'), + '#options' => $options, + '#default_value' => $stat, + '#multiple' => TRUE, + '#size' => 5, + ); + + $form['params']['submit'] = array( + '#type' => 'submit', + '#value' => t('Update report'), + ); + + return $form; +} + +function uc_tax_report_params_form_validate($form, &$form_state) { + if (empty($form_state['values']['status'])) { + form_set_error('status', t('You must select at least one order status.')); + } +} + +function uc_tax_report_params_form_submit($form, &$form_state) { + $timezone_offset = _uc_reports_timezone_offset(); + + // Build the start and end dates from the form. + $start_date = gmmktime(0, 0, 0, $form_state['values']['start_date']['month'], $form_state['values']['start_date']['day'], $form_state['values']['start_date']['year']); + $end_date = gmmktime(23, 59, 59, $form_state['values']['end_date']['month'], $form_state['values']['end_date']['day'], $form_state['values']['end_date']['year']); + + $args = array( + $start_date, + $end_date, + drupal_urlencode(implode(',', array_keys($form_state['values']['status']))), + ); + + drupal_goto('admin/store/reports/tax/'. implode('/', $args)); +} + + === modified file 'uc_taxes/uc_taxes.ca.inc' --- uc_taxes/uc_taxes.ca.inc 2009-02-20 20:55:23 +0000 +++ uc_taxes/uc_taxes.ca.inc 2009-02-26 14:41:25 +0000 @@ -77,13 +77,14 @@ */ function uc_taxes_action_apply_tax($order, $tax) { $amount = 0; + $taxable_amount = 0; if (is_array($order->products)) { foreach ($order->products as $item) { $node = node_load($item->nid); // Tax products if they are of a taxed type and if it is shippable if // the tax only applies to shippable products. if (in_array($node->type, $tax->taxed_product_types) && ($tax->shippable == 0 || $node->shippable == 1)) { - $amount += $item->price * $item->qty * $tax->rate; + $taxable_amount += $item->price * $item->qty; } } } @@ -95,17 +96,23 @@ continue; } if (in_array($line_item['type'], $taxed_line_items)) { - $amount += $line_item['amount'] * $tax->rate; + $taxable_amount += $line_item['amount']; } } } if (isset($taxed_line_items['tax'])) { foreach ($order->taxes as $other_tax) { - $amount += $other_tax->amount * $tax->rate; + $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); + $line_item->data = array( + 'tax_rate' => $tax->rate, + 'taxable_amount' => $taxable_amount, + 'tax_jurisdiction' => $tax->name, + ); return $line_item; } } === modified file 'uc_taxes/uc_taxes.module' --- uc_taxes/uc_taxes.module 2009-02-19 20:44:23 +0000 +++ uc_taxes/uc_taxes.module 2009-02-26 14:41:25 +0000 @@ -151,8 +151,10 @@ foreach ($arg1->line_items as $line) { if ($line['type'] == 'tax') { $delete = TRUE; + $sdata = serialize( $line['data'] ); foreach ($line_items as $id => $new_line) { - if ($new_line['title'] == $line['title']) { + if ($new_line['title'] == $line['title'] && + serialize( $new_line['data'] ) == $sdata) { if ($new_line['amount'] != $line['amount']) { uc_order_update_line_item($line['line_item_id'], $new_line['title'], $new_line['amount']); $changes[] = t('Changed %title to %amount.', array('%amount' => uc_currency_format($new_line['amount']), '%title' => $new_line['title'])); @@ -171,7 +173,7 @@ } 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']); + uc_order_line_item_add($arg1->order_id, $line['id'], $line['title'], $line['amount'], $line['weight'], $line['data']); $changes[] = t('Added %amount for %title.', array('%amount' => uc_currency_format($line['amount']), '%title' => $line['title'])); } } @@ -215,6 +217,7 @@ 'title' => $tax->name, 'amount' => $tax->amount, 'weight' => variable_get('uc_li_tax_weight', 9) + $tax->weight / 10, + 'data' => $tax->data, ); } return $lines;