| 1 |
<?php
|
| 2 |
// $Id$
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Invoice module
|
| 7 |
*
|
| 8 |
* This module was developed by Platina Designs, http://www.platinadesigns.nl
|
| 9 |
*
|
| 10 |
* @author Pieter Vogelaar <ps.vogelaar@platinadesigns.nl>
|
| 11 |
*/
|
| 12 |
|
| 13 |
// Set locale so money has the right format for the preferred culture
|
| 14 |
setlocale(LC_MONETARY, variable_get('invoice_locale', 'en_US.utf8'));
|
| 15 |
|
| 16 |
// Include files
|
| 17 |
|
| 18 |
// Ajax functions
|
| 19 |
require_once dirname(__FILE__) .'/invoice_ajax.inc';
|
| 20 |
// Form functions
|
| 21 |
require_once dirname(__FILE__) .'/invoice_form.inc';
|
| 22 |
// Helper functions
|
| 23 |
require_once dirname(__FILE__) .'/invoice_helpers.inc';
|
| 24 |
|
| 25 |
/**
|
| 26 |
* Implementation of hook_node_info()
|
| 27 |
*/
|
| 28 |
function invoice_node_info() {
|
| 29 |
return array(
|
| 30 |
'invoice' => array(
|
| 31 |
'name' => t('Invoice'),
|
| 32 |
'module' => 'invoice',
|
| 33 |
'description' => t("If you want to add an invoice, use this content type."),
|
| 34 |
'has_title' => TRUE,
|
| 35 |
'title_label' => t('Title'),
|
| 36 |
'has_body' => TRUE,
|
| 37 |
'body_label' => t('Body'),
|
| 38 |
)
|
| 39 |
);
|
| 40 |
}
|
| 41 |
|
| 42 |
/**
|
| 43 |
* Implementation of hook_menu()
|
| 44 |
*/
|
| 45 |
function invoice_menu() {
|
| 46 |
$items = array();
|
| 47 |
$items['invoices'] = array(
|
| 48 |
'title' => 'Invoices',
|
| 49 |
'page callback' => 'invoice_invoices',
|
| 50 |
'access arguments' => array('access invoices'),
|
| 51 |
);
|
| 52 |
$items['invoice/list'] = array(
|
| 53 |
'title' => 'List invoices',
|
| 54 |
'type' => MENU_DEFAULT_LOCAL_TASK,
|
| 55 |
'access arguments' => array('access invoices'),
|
| 56 |
);
|
| 57 |
$items['invoice/list/customers'] = array(
|
| 58 |
'title' => 'List customers',
|
| 59 |
'type' => MENU_LOCAL_TASK,
|
| 60 |
'access arguments' => array('access invoices'),
|
| 61 |
);
|
| 62 |
$items['invoice/add/invoice'] = array(
|
| 63 |
'title' => 'Add invoice',
|
| 64 |
'page callback' => 'invoice_add_invoice',
|
| 65 |
'access arguments' => array('administer invoices'),
|
| 66 |
'type' => MENU_CALLBACK,
|
| 67 |
);
|
| 68 |
$items['invoice/add/customer'] = array(
|
| 69 |
'title' => 'Add customer',
|
| 70 |
'page callback' => 'invoice_add_customer',
|
| 71 |
'access arguments' => array('administer customers'),
|
| 72 |
'type' => MENU_CALLBACK,
|
| 73 |
);
|
| 74 |
$items['invoice/edit/invoice/%'] = array(
|
| 75 |
'title' => 'Edit invoice',
|
| 76 |
'page callback' => 'invoice_edit_invoice',
|
| 77 |
'page arguments' => array(2),
|
| 78 |
'access arguments' => array('administer invoices'),
|
| 79 |
'type' => MENU_CALLBACK,
|
| 80 |
);
|
| 81 |
$items['invoice/set/template'] = array(
|
| 82 |
'title' => 'Edit invoice',
|
| 83 |
'page callback' => 'invoice_set_template',
|
| 84 |
'access arguments' => array('administer invoices'),
|
| 85 |
'type' => MENU_CALLBACK,
|
| 86 |
);
|
| 87 |
$items['invoice/print/%'] = array(
|
| 88 |
'title' => 'Invoice in HTML print format',
|
| 89 |
'page callback' => 'invoice_view_print',
|
| 90 |
'page arguments' => array(2),
|
| 91 |
'access arguments' => array('access invoices'),
|
| 92 |
'type' => MENU_CALLBACK,
|
| 93 |
);
|
| 94 |
$items['invoice/pdf/%'] = array(
|
| 95 |
'title' => 'Invoice in PDF format',
|
| 96 |
'page callback' => 'invoice_view_pdf',
|
| 97 |
'page arguments' => array(2),
|
| 98 |
'access arguments' => array('access invoices'),
|
| 99 |
'type' => MENU_CALLBACK,
|
| 100 |
);
|
| 101 |
$items['invoice/set/pay_status/%/%'] = array(
|
| 102 |
'title' => 'Set invoice pay status',
|
| 103 |
'page callback' => 'invoice_set_pay_status',
|
| 104 |
'page arguments' => array(3, 4),
|
| 105 |
'access arguments' => array('administer invoices'),
|
| 106 |
'type' => MENU_CALLBACK,
|
| 107 |
);
|
| 108 |
$items['invoice/search/customer'] = array(
|
| 109 |
'title' => 'Search customer',
|
| 110 |
'page callback' => 'invoice_search_customer',
|
| 111 |
'page arguments' => array(3),
|
| 112 |
'access arguments' => array('administer customers'),
|
| 113 |
'type' => MENU_CALLBACK,
|
| 114 |
);
|
| 115 |
$items['invoice/get/customer_info'] = array(
|
| 116 |
'title' => 'Get customer info',
|
| 117 |
'page callback' => 'invoice_get_customer_info',
|
| 118 |
'access arguments' => array('administer customers'),
|
| 119 |
'type' => MENU_CALLBACK,
|
| 120 |
);
|
| 121 |
$items['invoice/delete/invoice/%'] = array(
|
| 122 |
'page callback' => 'invoice_delete_invoice',
|
| 123 |
'page arguments' => array(2),
|
| 124 |
'access arguments' => array('administer invoices'),
|
| 125 |
'type' => MENU_CALLBACK,
|
| 126 |
);
|
| 127 |
$items['invoice/save/item'] = array(
|
| 128 |
'title' => 'Save item',
|
| 129 |
'page callback' => 'invoice_save_item',
|
| 130 |
'access arguments' => array('administer invoices'),
|
| 131 |
'type' => MENU_CALLBACK,
|
| 132 |
);
|
| 133 |
$items['invoice/edit/item'] = array(
|
| 134 |
'title' => 'Edit item',
|
| 135 |
'page callback' => 'invoice_edit_item',
|
| 136 |
'access arguments' => array('administer invoices'),
|
| 137 |
'type' => MENU_CALLBACK,
|
| 138 |
);
|
| 139 |
$items['invoice/delete/item'] = array(
|
| 140 |
'title' => 'Delete item',
|
| 141 |
'page callback' => 'invoice_delete_item',
|
| 142 |
'access arguments' => array('administer invoices'),
|
| 143 |
'type' => MENU_CALLBACK,
|
| 144 |
);
|
| 145 |
$items['admin/settings/invoice'] = array(
|
| 146 |
'title' => 'Invoice',
|
| 147 |
'page callback' => 'invoice_settings',
|
| 148 |
'access arguments' => array('administer invoices'),
|
| 149 |
'description' => 'Create and manage invoices.',
|
| 150 |
'type' => MENU_NORMAL_ITEM,
|
| 151 |
);
|
| 152 |
$items['invoice/installed_locales'] = array(
|
| 153 |
'title' => 'Installed locales on your system',
|
| 154 |
'page callback' => 'invoice_installed_locales',
|
| 155 |
'access arguments' => array('administer invoices'),
|
| 156 |
'type' => MENU_CALLBACK,
|
| 157 |
);
|
| 158 |
return $items;
|
| 159 |
}
|
| 160 |
|
| 161 |
/**
|
| 162 |
* Implementation of hook_perm()
|
| 163 |
*/
|
| 164 |
function invoice_perm() {
|
| 165 |
return array('access invoices', 'administer invoices', 'administer own invoices');
|
| 166 |
}
|
| 167 |
|
| 168 |
/**
|
| 169 |
* Implementation of hook_access()
|
| 170 |
*
|
| 171 |
* @param string $op
|
| 172 |
* @param object $node
|
| 173 |
* @param object $account
|
| 174 |
* @return boolean
|
| 175 |
*/
|
| 176 |
function invoice_access($op, $node, $account) {
|
| 177 |
if ($op == 'view') {
|
| 178 |
return user_access('access invoices', $account);
|
| 179 |
}
|
| 180 |
if ($op == 'create') {
|
| 181 |
return user_access('administer invoices', $account);
|
| 182 |
}
|
| 183 |
if ($op == 'update') {
|
| 184 |
if (user_access('administer invoices', $account) || (user_access('administer own invoices', $account) && ($account->uid == $node->uid))) {
|
| 185 |
return TRUE;
|
| 186 |
}
|
| 187 |
}
|
| 188 |
if ($op == 'delete') {
|
| 189 |
if (user_access('administer invoices', $account) || (user_access('administer own invoices', $account) && ($account->uid == $node->uid))) {
|
| 190 |
return TRUE;
|
| 191 |
}
|
| 192 |
}
|
| 193 |
}
|
| 194 |
|
| 195 |
/**
|
| 196 |
* Implementation of hook_theme()
|
| 197 |
*
|
| 198 |
* @param unknown_type $existing
|
| 199 |
* @param unknown_type $type
|
| 200 |
* @param unknown_type $theme
|
| 201 |
* @param unknown_type $path
|
| 202 |
* @return array
|
| 203 |
*/
|
| 204 |
function invoice_theme($existing, $type, $theme, $path) {
|
| 205 |
return array(
|
| 206 |
'invoice_body' => array(
|
| 207 |
'arguments' => array('node' => NULL, 'type' => NULL),
|
| 208 |
),
|
| 209 |
'invoice_markup' => array(
|
| 210 |
'arguments' => array('s_fieldname' => NULL, 'value' => NULL, 's_title' => NULL),
|
| 211 |
),
|
| 212 |
'invoice_table' => array(
|
| 213 |
'arguments' => array('header' => NULL, 'rows' => NULL, 'attributes' => NULL, 'caption' => NULL),
|
| 214 |
),
|
| 215 |
);
|
| 216 |
}
|
| 217 |
|
| 218 |
/**
|
| 219 |
* Implementation of hook_load()
|
| 220 |
*
|
| 221 |
* @param object $node
|
| 222 |
* @return mixed
|
| 223 |
*/
|
| 224 |
function invoice_load($node) {
|
| 225 |
(object) $o_additions;
|
| 226 |
|
| 227 |
// Get all invoices information
|
| 228 |
$o_invoice = db_fetch_object(db_query("SELECT *,ii.iid as invoice_number,ii.leading_zeros AS leading_zeros, ii.prefix AS prefix,
|
| 229 |
ii.description AS invoice_description, ii.pay_limit AS pay_limit, ic.description AS customer_description, t.name as template
|
| 230 |
FROM {invoice_invoices} ii
|
| 231 |
LEFT JOIN {invoice_customers} ic ON ic.invoice_id=ii.iid
|
| 232 |
LEFT JOIN {invoice_templates} t ON ii.tid=t.tid
|
| 233 |
WHERE nid=%d
|
| 234 |
GROUP BY ii.iid",
|
| 235 |
$node->nid
|
| 236 |
));
|
| 237 |
|
| 238 |
$a_totals = _invoice_get_invoice_totals($o_invoice->invoice_number);
|
| 239 |
|
| 240 |
$o_invoice->extotal = $a_totals['extotal'];
|
| 241 |
$o_invoice->inctotal = $a_totals['inctotal'];
|
| 242 |
$o_invoice->vattotal = $a_totals['vattotal'];
|
| 243 |
|
| 244 |
// Determine template to use
|
| 245 |
$template = !empty($o_invoice->template) ? $o_invoice->template : variable_get('invoice_default_template', 'default');
|
| 246 |
|
| 247 |
// Set locale so money has the right format for the preferred culture
|
| 248 |
if ($locale = _invoice_get_variable($template, 'locale')) {
|
| 249 |
setlocale(LC_MONETARY, $locale);
|
| 250 |
}
|
| 251 |
|
| 252 |
// Calculate vat totals per different VAT percentage
|
| 253 |
$a_vattotals = array();
|
| 254 |
|
| 255 |
$result = db_query("SELECT vat, (quantity*unitcost)*((vat / 100) +1) * (1 - (1 / ((vat / 100) +1))) as vattotal
|
| 256 |
FROM {invoice_items}
|
| 257 |
WHERE invoice_id=%d",
|
| 258 |
$o_invoice->invoice_number
|
| 259 |
);
|
| 260 |
|
| 261 |
// SUM all vat totals per different VAT percentage
|
| 262 |
while ($row = db_fetch_object($result)) {
|
| 263 |
if (!isset($a_vattotals[$row->vat])) {
|
| 264 |
$a_vattotals[$row->vat] = array(
|
| 265 |
'vattotal' => $row->vattotal,
|
| 266 |
);
|
| 267 |
}
|
| 268 |
else {
|
| 269 |
$a_vattotals[$row->vat]['vattotal'] += $row->vattotal;
|
| 270 |
}
|
| 271 |
}
|
| 272 |
|
| 273 |
// Round every total per different VAT percentage
|
| 274 |
// and add a formatted version
|
| 275 |
foreach ($a_vattotals as $key => &$total) {
|
| 276 |
$total['vattotal'] = _invoice_round($total['vattotal'], 2);
|
| 277 |
$total['formatted_vattotal'] = money_format('%.2n', $total['vattotal']);
|
| 278 |
}
|
| 279 |
|
| 280 |
// Set totals
|
| 281 |
$extotal = _invoice_round($o_invoice->extotal, 2);
|
| 282 |
$inctotal = _invoice_round($o_invoice->inctotal, 2);
|
| 283 |
$vattotal = _invoice_round($o_invoice->vattotal, 2);
|
| 284 |
|
| 285 |
// Add general invoice information to the node object
|
| 286 |
$o_additions->invoice = array(
|
| 287 |
'invoice_number' => $o_invoice->invoice_number,
|
| 288 |
'formatted_invoice_number' => _invoice_get_formatted_invoice_number($o_invoice->invoice_number),
|
| 289 |
'invoice_number_zerofill' => $o_invoice->leading_zeros,
|
| 290 |
'invoice_number_prefix' => $o_invoice->prefix,
|
| 291 |
'description' => $o_invoice->invoice_description,
|
| 292 |
'vat' => $a_vattotals,
|
| 293 |
'pay_status' => $o_invoice->pay_status,
|
| 294 |
'pay_limit' => $o_invoice->pay_limit,
|
| 295 |
'template' => $template,
|
| 296 |
'extotal' => $extotal,
|
| 297 |
'inctotal' => $inctotal,
|
| 298 |
'formatted_vattotal' => money_format('%.2n', $vattotal),
|
| 299 |
'formatted_extotal' => money_format('%.2n', $extotal),
|
| 300 |
'formatted_inctotal' => money_format('%.2n', $inctotal),
|
| 301 |
'formatted_created' => format_date($node->created, 'custom', _invoice_get_variable($template, 'date_format')),
|
| 302 |
);
|
| 303 |
|
| 304 |
// Add customer information to the node object
|
| 305 |
$o_additions->customer = array(
|
| 306 |
'cid' => $o_invoice->cid,
|
| 307 |
'customer_number' => $o_invoice->customer_number,
|
| 308 |
'name' => $name,
|
| 309 |
'company_name' => $o_invoice->company_name,
|
| 310 |
'firstname' => $o_invoice->firstname,
|
| 311 |
'lastname' => $o_invoice->lastname,
|
| 312 |
'fullname' => $o_invoice->lastname . (!empty($o_invoice->firstname) ? ', '. $o_invoice->firstname : ''),
|
| 313 |
'street' => $o_invoice->street,
|
| 314 |
'building_number' => $o_invoice->building_number,
|
| 315 |
'zipcode' => $o_invoice->zipcode,
|
| 316 |
'city' => $o_invoice->city,
|
| 317 |
'country' => $o_invoice->country,
|
| 318 |
'coc_number' => $o_invoice->coc_number,
|
| 319 |
'vat_number' => $o_invoice->vat_number,
|
| 320 |
'description' => $o_invoice->customer_description,
|
| 321 |
);
|
| 322 |
|
| 323 |
// Add invoices items to the node object
|
| 324 |
$o_additions->invoice_items = array();
|
| 325 |
|
| 326 |
$result = db_query("SELECT * FROM {invoice_items} WHERE invoice_id=%d ORDER BY created ASC, weight ASC", $o_invoice->invoice_number);
|
| 327 |
while ($row = db_fetch_object($result)) {
|
| 328 |
|
| 329 |
// Display unitcost VAT in 2 decimals, if there are more decimals round it to 3 decimals
|
| 330 |
$exp = explode('.', $row->unitcost);
|
| 331 |
$exunitcost_roundnum = strlen($exp[1]) > 2 ? 3 : 2;
|
| 332 |
$exunitcost = _invoice_round($row->unitcost, $exunitcost_roundnum);
|
| 333 |
|
| 334 |
// Add invoice item row to the array
|
| 335 |
$o_additions->invoice_items[] = array(
|
| 336 |
'iid' => $row->iid,
|
| 337 |
'description' => $row->description,
|
| 338 |
'quantity' => $row->quantity,
|
| 339 |
'unitcost' => $row->unitcost,
|
| 340 |
'vat' => $row->vat,
|
| 341 |
'formatted_exunitcost' => money_format('%.'. $exunitcost_roundnum .'n', $exunitcost),
|
| 342 |
'formatted_incunitcost' => money_format('%.2n', _invoice_round($row->unitcost * _invoice_vat_percent_to_decimal($row->vat), 2)),
|
| 343 |
'formatted_extotal' => money_format('%.2n', _invoice_round($row->quantity * $row->unitcost, 2)),
|
| 344 |
'formatted_inctotal' => money_format('%.2n', _invoice_round($row->quantity * $row->unitcost * _invoice_vat_percent_to_decimal($row->vat), 2)),
|
| 345 |
);
|
| 346 |
}
|
| 347 |
|
| 348 |
return $o_additions;
|
| 349 |
}
|
| 350 |
|
| 351 |
/**
|
| 352 |
* Implementation of hook_nodeapi()
|
| 353 |
*
|
| 354 |
* @param object $node
|
| 355 |
* @param string $op
|
| 356 |
* @param string $teaser
|
| 357 |
* @param string $page
|
| 358 |
*/
|
| 359 |
function invoice_nodeapi(&$node, $op, $teaser, $page) {
|
| 360 |
switch ($op) {
|
| 361 |
case "presave":
|
| 362 |
if ($node->type == 'invoice') {
|
| 363 |
// If true we are creating a new invoice
|
| 364 |
if (intval($node->invoice_number) == 0) {
|
| 365 |
// Get new invoice number
|
| 366 |
if (intval($node->user_defined_invoice_number) > 0) {
|
| 367 |
$node->invoice_number = $node->user_defined_invoice_number;
|
| 368 |
}
|
| 369 |
else {
|
| 370 |
$node->invoice_number = _invoice_get_new_invoice_number();
|
| 371 |
}
|
| 372 |
}
|
| 373 |
|
| 374 |
// Save the title, this must happen when creating AND editing a node because otherwise
|
| 375 |
// the pathauto module will give an error
|
| 376 |
if (intval($node->invoice_number) > 0) {
|
| 377 |
$node->title = t('Invoice') .' #'. _invoice_get_formatted_invoice_number($node->invoice_number, $node);
|
| 378 |
}
|
| 379 |
|
| 380 |
// Get customer number
|
| 381 |
if (!empty($node->company_name)) {
|
| 382 |
$customer_number = db_result(db_query("SELECT customer_number FROM {invoice_customers}
|
| 383 |
WHERE company_name='%s' AND country='%s' LIMIT 1",
|
| 384 |
$node->company_name,
|
| 385 |
$node->country
|
| 386 |
));
|
| 387 |
}
|
| 388 |
elseif (!empty($node->lastname)) {
|
| 389 |
$customer_number = db_result(db_query("SELECT customer_number FROM {invoice_customers}
|
| 390 |
WHERE lastname='%s' AND zipcode='%s' AND building_number='%s' LIMIT 1",
|
| 391 |
$node->lastname,
|
| 392 |
$node->zipcode,
|
| 393 |
$node->building_number
|
| 394 |
));
|
| 395 |
}
|
| 396 |
|
| 397 |
// If customer number is still empty, get a new one
|
| 398 |
if (empty($customer_number)) {
|
| 399 |
$customer_number = 1 + db_result(db_query("SELECT MAX(customer_number) FROM {invoice_customers}"));
|
| 400 |
}
|
| 401 |
|
| 402 |
// Add customer number to the node object
|
| 403 |
$node->customer_number = $customer_number;
|
| 404 |
}
|
| 405 |
break;
|
| 406 |
}
|
| 407 |
}
|
| 408 |
|
| 409 |
/**
|
| 410 |
* Invoice settings
|
| 411 |
*/
|
| 412 |
function invoice_settings() {
|
| 413 |
|
| 414 |
// A little test to see if the function _invoice_round() rounds well on every server
|
| 415 |
if (_invoice_round(38.675, 2) != 38.68) {
|
| 416 |
drupal_set_message(t('TEST: The answer of _invoice_round(38.675, 2) must be 38.68, but is @answer! This problem is maybe caused by your PHP version.', array('@answer' => _invoice_round(38.675, 2))), 'error');
|
| 417 |
}
|
| 418 |
|
| 419 |
$content = '';
|
| 420 |
$content = drupal_get_form('invoice_settings_form');
|
| 421 |
return $content;
|
| 422 |
}
|
| 423 |
|
| 424 |
/**
|
| 425 |
* Submit function for the settings form
|
| 426 |
*/
|
| 427 |
function invoice_settings_form_submit(&$form_state, $form) {
|
| 428 |
$fv =& $form['values'];
|
| 429 |
|
| 430 |
// Invoice specific settings
|
| 431 |
variable_set('invoice_locale', $fv['locale']);
|
| 432 |
variable_set('invoice_date_format', $fv['date_format']);
|
| 433 |
variable_set('invoice_vat', $fv['vat']);
|
| 434 |
variable_set('invoice_pay_limit', $fv['pay_limit']);
|
| 435 |
variable_set('invoice_invoice_number_zerofill', $fv['invoice_number_zerofill']);
|
| 436 |
variable_set('invoice_invoice_number_prefix', $fv['invoice_number_prefix']);
|
| 437 |
variable_set('invoice_default_template', $fv['default_template']);
|
| 438 |
|
| 439 |
// Display columns specific settings
|
| 440 |
variable_set('invoice_display_column_vat', $fv['display_column_vat']);
|
| 441 |
variable_set('invoice_display_column_exunitcost', $fv['display_column_exunitcost']);
|
| 442 |
variable_set('invoice_display_column_incunitcost', $fv['display_column_incunitcost']);
|
| 443 |
variable_set('invoice_display_column_extotal', $fv['display_column_extotal']);
|
| 444 |
variable_set('invoice_display_column_inctotal', $fv['display_column_inctotal']);
|
| 445 |
|
| 446 |
// Supplier specific settings
|
| 447 |
variable_set('invoice_supplier_company_name', $fv['supplier_company_name']);
|
| 448 |
variable_set('invoice_supplier_street', $fv['supplier_street']);
|
| 449 |
variable_set('invoice_supplier_building_number', $fv['supplier_building_number']);
|
| 450 |
variable_set('invoice_supplier_zipcode', $fv['supplier_zipcode']);
|
| 451 |
variable_set('invoice_supplier_city', $fv['supplier_city']);
|
| 452 |
variable_set('invoice_supplier_country', $fv['supplier_country']);
|
| 453 |
variable_set('invoice_supplier_phone', $fv['supplier_phone']);
|
| 454 |
variable_set('invoice_supplier_fax', $fv['supplier_fax']);
|
| 455 |
variable_set('invoice_supplier_email', $fv['supplier_email']);
|
| 456 |
variable_set('invoice_supplier_web', $fv['supplier_web']);
|
| 457 |
variable_set('invoice_supplier_coc_number', $fv['supplier_coc_number']);
|
| 458 |
variable_set('invoice_supplier_vat_number', $fv['supplier_vat_number']);
|
| 459 |
|
| 460 |
$a_templates = _invoice_get_templates();
|
| 461 |
|
| 462 |
foreach ($a_templates as $s_template) {
|
| 463 |
$count = db_result(db_query("SELECT COUNT(*) FROM {invoice_templates} WHERE name='%s'", $s_template));
|
| 464 |
if ($count == 0) {
|
| 465 |
db_query("INSERT INTO {invoice_templates} (name) VALUES ('%s')", $s_template);
|
| 466 |
}
|
| 467 |
|
| 468 |
db_query("UPDATE {invoice_templates} SET locale='%s', date_format='%s', vat=%d, pay_limit=%d,
|
| 469 |
supplier_company_name='%s', supplier_street='%s', supplier_building_number='%s', supplier_zipcode='%s', supplier_city='%s',
|
| 470 |
supplier_country='%s', supplier_phone='%s', supplier_fax='%s', supplier_email='%s', supplier_web='%s', supplier_coc_number='%s',
|
| 471 |
supplier_vat_number='%s', display_column_vat=%d, display_column_exunitcost=%d, display_column_incunitcost=%d,
|
| 472 |
display_column_extotal=%d, display_column_inctotal=%d
|
| 473 |
WHERE name='%s'",
|
| 474 |
$fv[$s_template .'_locale'],
|
| 475 |
$fv[$s_template .'_date_format'],
|
| 476 |
$fv[$s_template .'_vat'],
|
| 477 |
$fv[$s_template .'_pay_limit'],
|
| 478 |
$fv[$s_template .'_supplier_company_name'],
|
| 479 |
$fv[$s_template .'_supplier_street'],
|
| 480 |
$fv[$s_template .'_supplier_building_number'],
|
| 481 |
$fv[$s_template .'_supplier_zipcode'],
|
| 482 |
$fv[$s_template .'_supplier_city'],
|
| 483 |
$fv[$s_template .'_supplier_country'],
|
| 484 |
$fv[$s_template .'_supplier_phone'],
|
| 485 |
$fv[$s_template .'_supplier_fax'],
|
| 486 |
$fv[$s_template .'_supplier_email'],
|
| 487 |
$fv[$s_template .'_supplier_web'],
|
| 488 |
$fv[$s_template .'_supplier_coc_number'],
|
| 489 |
$fv[$s_template .'_supplier_vat_number'],
|
| 490 |
$count > 0 ? $fv[$s_template .'_display_column_vat'] : 0, // set default value if we deal with a new template
|
| 491 |
$count > 0 ? $fv[$s_template .'_display_column_exunitcost'] : 1, // set default value if we deal with a new template
|
| 492 |
$count > 0 ? $fv[$s_template .'_display_column_incunitcost'] : 1, // set default value if we deal with a new template
|
| 493 |
$count > 0 ? $fv[$s_template .'_display_column_extotal'] : 1, // set default value if we deal with a new template
|
| 494 |
$count > 0 ? $fv[$s_template .'_display_column_inctotal'] : 1, // set default value if we deal with a new template
|
| 495 |
$s_template
|
| 496 |
);
|
| 497 |
}
|
| 498 |
|
| 499 |
drupal_set_message(t('Succesfully saved'));
|
| 500 |
}
|
| 501 |
|
| 502 |
/**
|
| 503 |
* Overview of all invoices
|
| 504 |
*/
|
| 505 |
function invoice_invoices() {
|
| 506 |
|
| 507 |
//_make_sure_node_promote_flag_is_off();
|
| 508 |
|
| 509 |
$content = '';
|
| 510 |
|
| 511 |
//Our header defenition
|
| 512 |
$header = array(
|
| 513 |
array('data' => t('Invoice #'), 'field' => 'ii.iid'),
|
| 514 |
array('data' => t('Customer'), 'field' => 'c.customer'),
|
| 515 |
array('data' => t('Total (ex)'), 'field' => 'extotal'),
|
| 516 |
array('data' => t('Total (inc)'), 'field' => 'inctotal'),
|
| 517 |
array('data' => t('Created'), 'field' => 'invoices.created'),
|
| 518 |
array('data' => _invoice_get_icon('bullet_black', NULL, array('title' => t('sort by @s', array('@s' => t('Pay status'))))), 'field' => 'ii.pay_status'),
|
| 519 |
t('Actions')
|
| 520 |
);
|
| 521 |
|
| 522 |
if (!isset($_GET['order']) || empty($_GET['order'])) {
|
| 523 |
$_GET['order'] = t("Invoice #");
|
| 524 |
$_GET['sort'] = "desc";
|
| 525 |
}
|
| 526 |
|
| 527 |
$query = "SELECT COUNT(*),ii.iid,ii.nid,ii.pay_limit,ii.pay_status,c.company_name,c.lastname,c.firstname,n.created,it.name as template
|
| 528 |
FROM {invoice_invoices} ii
|
| 529 |
LEFT JOIN {node} n ON ii.nid=n.nid
|
| 530 |
LEFT JOIN {invoice_customers} c ON ii.iid=c.invoice_id
|
| 531 |
LEFT JOIN {invoice_templates} it ON ii.tid=it.tid
|
| 532 |
GROUP BY ii.iid
|
| 533 |
";
|
| 534 |
|
| 535 |
//$query .= tablesort_sql($header);
|
| 536 |
$query .= "ORDER BY nid DESC";
|
| 537 |
|
| 538 |
$count_query = "SELECT COUNT(*) FROM {invoice_invoices}";
|
| 539 |
|
| 540 |
$rows = array();
|
| 541 |
$result = pager_query($query, 15, 0, $count_query);
|
| 542 |
while ($row = db_fetch_object($result)) {
|
| 543 |
|
| 544 |
// Set locale so money has the right format for the preferred culture
|
| 545 |
if ($locale = _invoice_get_variable($row->template, 'locale')) {
|
| 546 |
setlocale(LC_MONETARY, $locale);
|
| 547 |
}
|
| 548 |
|
| 549 |
// Get locale settings
|
| 550 |
$a_locales = localeconv();
|
| 551 |
|
| 552 |
// Set formatted create date
|
| 553 |
$created = format_date($row->created, 'custom', variable_get('invoice_date_format' , ''));
|
| 554 |
|
| 555 |
// If no default invoice date format is set, use the small drupal date format
|
| 556 |
if (empty($created)) {
|
| 557 |
$created = format_date($row->created, 'small');
|
| 558 |
}
|
| 559 |
|
| 560 |
// Get invoice totals
|
| 561 |
$a_totals = _invoice_get_invoice_totals($row->iid);
|
| 562 |
|
| 563 |
// Set pay status
|
| 564 |
$pay_status = $row->pay_status == 'paid' ? _invoice_get_icon('bullet_green', NULL, array('title' => t('Paid'))) : _invoice_get_icon('bullet_yellow', NULL, array('title' => t('Unpaid')));
|
| 565 |
|
| 566 |
// Check if invoice has pay limit, if yes see if the date exceeded it
|
| 567 |
if ($row->pay_status == 'unpaid' && $row->pay_limit > 0) {
|
| 568 |
if (mktime(0, 0, 0, date('m'), date('d'), date('Y')) > $row->created + (86400 * $row->pay_limit)) {
|
| 569 |
$pay_status = _invoice_get_icon('bullet_red', NULL, array('title' => t('Overtime')));
|
| 570 |
}
|
| 571 |
}
|
| 572 |
|
| 573 |
$rows[] = array(
|
| 574 |
'invoices.iid' => l(_invoice_get_formatted_invoice_number($row->iid), 'node/'. $row->nid),
|
| 575 |
'customer' => !empty($row->company_name) ? _invoice_get_icon('building') .' '. $row->company_name : _invoice_get_icon('user') .' '. $row->lastname . (!empty($row->firstname) ? ', '. $row->firstname : ''),
|
| 576 |
'extotal' => money_format('%.2n', _invoice_round($a_totals['extotal'], 2)),
|
| 577 |
'inctotal' => money_format('%.2n', _invoice_round($a_totals['inctotal'], 2)),
|
| 578 |
'invoices.created' => $created,
|
| 579 |
'ii.status' => $pay_status,
|
| 580 |
'actions' => _invoice_get_icon('edit', 'node/'. $row->nid .'/edit', array('title' => t('Edit')))
|
| 581 |
. ($row->pay_status != 'paid' ? _invoice_get_icon('delete', 'node/'. $row->nid .'/delete', array('title' => t('Delete'))) : '')
|
| 582 |
. ($row->pay_status != 'paid' ? _invoice_get_icon('accept', 'invoice/set/pay_status/'. $row->iid .'/paid/'. _invoice_getvars_array_to_string($_GET), array('title' => t('Set paid'))) : '')
|
| 583 |
. ($row->pay_status == 'paid' ? _invoice_get_icon('coins_delete', 'invoice/set/pay_status/'. $row->iid .'/unpaid/'. _invoice_getvars_array_to_string($_GET), array('title' => t('Set unpaid'))) : ''),
|
| 584 |
);
|
| 585 |
}
|
| 586 |
|
| 587 |
$content .= theme('invoice_table', $header, $rows);
|
| 588 |
$content .= theme('pager');
|
| 589 |
|
| 590 |
return $content;
|
| 591 |
}
|
| 592 |
|
| 593 |
/**
|
| 594 |
* Implementation of node_validate()
|
| 595 |
*/
|
| 596 |
function invoice_validate($node, $form) {
|
| 597 |
if ($node->op != t('Delete')) {
|
| 598 |
_invoice_add_css_js();
|
| 599 |
|
| 600 |
// Count invoice items
|
| 601 |
$count = db_result(db_query("SELECT COUNT(*) FROM {invoice_items} WHERE uid=%d AND invoice_id=%d",
|
| 602 |
$GLOBALS['user']->uid,
|
| 603 |
$node->invoice_number
|
| 604 |
));
|
| 605 |
|
| 606 |
// Display an error if there are no invoice items
|
| 607 |
if ($count == 0) {
|
| 608 |
form_set_error('description', t('You have to fill in at least one invoice item!'));
|
| 609 |
}
|
| 610 |
|
| 611 |
if (empty($node->company_name) && empty($node->lastname)) {
|
| 612 |
form_set_error('company_name', t('Company name and lastname may not both be empty!'));
|
| 613 |
}
|
| 614 |
}
|
| 615 |
|
| 616 |
if ($node->op == t('Save')) {
|
| 617 |
$possible_new_invoice_number = _invoice_get_new_invoice_number(true);
|
| 618 |
|
| 619 |
// If user defined invoice number is higher than the new possible invoice number,
|
| 620 |
// use the defined invoice number as the new invoice number
|
| 621 |
if (intval($node->user_defined_invoice_number) > 0) {
|
| 622 |
if ($node->user_defined_invoice_number <= $possible_new_invoice_number) {
|
| 623 |
form_set_error('user_defined_invoice_number', t('The user defined invoice number is not greater than the latest invoice number "@invoice_number"!', array('@invoice_number' => $possible_new_invoice_number)));
|
| 624 |
}
|
| 625 |
}
|
| 626 |
}
|
| 627 |
}
|
| 628 |
|
| 629 |
/**
|
| 630 |
* Implementation of hook_insert()
|
| 631 |
*/
|
| 632 |
function invoice_insert($node) {
|
| 633 |
|
| 634 |
// Get template ID
|
| 635 |
$tid = db_result(db_query("SELECT tid FROM {invoice_templates} WHERE name='%s'", $node->template));
|
| 636 |
|
| 637 |
// Create invoice
|
| 638 |
db_query("INSERT INTO {invoice_invoices} (iid,nid,leading_zeros,prefix,description,tid,pay_limit,uid) VALUES (%d,%d,%d,'%s','%s',%d,'%s',%d)",
|
| 639 |
$node->invoice_number,
|
| 640 |
$node->nid,
|
| 641 |
empty($node->invoice_invoice_number_zerofill) ? variable_get('invoice_invoice_number_zerofill', 0) : $node->invoice_invoice_number_zerofill,
|
| 642 |
empty($node->invoice_invoice_number_prefix) ? variable_get('invoice_invoice_number_prefix', NULL) : $node->invoice_invoice_number_prefix,
|
| 643 |
$node->invoice_description,
|
| 644 |
$tid,
|
| 645 |
$node->pay_limit,
|
| 646 |
$GLOBALS['user']->uid
|
| 647 |
);
|
| 648 |
|
| 649 |
// Create customer
|
| 650 |
db_query("INSERT {invoice_customers} (customer_number,company_name,firstname,lastname,street,building_number,zipcode,city,country,coc_number,vat_number,description,invoice_id)
|
| 651 |
VALUES (%d, '%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s',%d)",
|
| 652 |
$node->customer_number,
|
| 653 |
$node->company_name,
|
| 654 |
$node->firstname,
|
| 655 |
$node->lastname,
|
| 656 |
$node->street,
|
| 657 |
$node->building_number,
|
| 658 |
$node->zipcode,
|
| 659 |
$node->city,
|
| 660 |
$node->country,
|
| 661 |
$node->coc_number,
|
| 662 |
$node->vat_number,
|
| 663 |
$node->customer_description,
|
| 664 |
$node->invoice_number
|
| 665 |
);
|
| 666 |
|
| 667 |
// Add all temporary invoice items to this invoice
|
| 668 |
db_query("UPDATE {invoice_items} SET invoice_id=%d WHERE uid=%d AND invoice_id=0",
|
| 669 |
$node->invoice_number,
|
| 670 |
$GLOBALS['user']->uid
|
| 671 |
);
|
| 672 |
|
| 673 |
db_query("UPDATE {node} SET promote=0 WHERE type='invoice' AND nid=%d", $node->nid);
|
| 674 |
|
| 675 |
unset($_SESSION['invoice_template']);
|
| 676 |
}
|
| 677 |
|
| 678 |
/**
|
| 679 |
* Implementation of hook_update()
|
| 680 |
*/
|
| 681 |
function invoice_update($node) {
|
| 682 |
|
| 683 |
// Make sure that this invoice belongs to this user
|
| 684 |
$count = db_result(db_query("SELECT COUNT(*) FROM {invoice_invoices} WHERE iid=%d AND uid=%d",
|
| 685 |
$node->invoice_number,
|
| 686 |
$GLOBALS['user']->uid
|
| 687 |
));
|
| 688 |
|
| 689 |
if ($count > 0) {
|
| 690 |
// Get template ID
|
| 691 |
$tid = db_result(db_query("SELECT tid FROM {invoice_templates} WHERE name='%s'", $node->template));
|
| 692 |
|
| 693 |
// Update invoice
|
| 694 |
db_query("UPDATE {invoice_invoices} SET leading_zeros=%d, prefix='%s', description='%s', tid='%s', pay_limit=%d WHERE iid=%d AND uid=%d",
|
| 695 |
$node->invoice_invoice_number_zerofill,
|
| 696 |
$node->invoice_invoice_number_prefix,
|
| 697 |
$node->invoice_description,
|
| 698 |
$tid,
|
| 699 |
$node->pay_limit,
|
| 700 |
$node->invoice_number,
|
| 701 |
$GLOBALS['user']->uid
|
| 702 |
);
|
| 703 |
|
| 704 |
// Update customers
|
| 705 |
db_query("UPDATE {invoice_customers} SET customer_number=%d, company_name='%s', firstname='%s', lastname='%s', street='%s', building_number='%s',
|
| 706 |
zipcode='%s', city='%s', country='%s', coc_number='%s', vat_number='%s', description='%s'
|
| 707 |
WHERE invoice_id=%d",
|
| 708 |
$node->customer_number,
|
| 709 |
$node->company_name,
|
| 710 |
$node->firstname,
|
| 711 |
$node->lastname,
|
| 712 |
$node->street,
|
| 713 |
$node->building_number,
|
| 714 |
$node->zipcode,
|
| 715 |
$node->city,
|
| 716 |
$node->country,
|
| 717 |
$node->coc_number,
|
| 718 |
$node->vat_number,
|
| 719 |
$node->description,
|
| 720 |
$node->invoice_number
|
| 721 |
);
|
| 722 |
|
| 723 |
// It's not needed to update invoice items because they are directly updated by every AJAX call
|
| 724 |
}
|
| 725 |
else {
|
| 726 |
drupal_set_message(t('You are not the owner of this invoice!'), 'error');
|
| 727 |
}
|
| 728 |
|
| 729 |
db_query("UPDATE {node} SET promote=0 WHERE type='invoice' AND nid=%d", $node->nid);
|
| 730 |
|
| 731 |
unset($_SESSION['invoice_template']);
|
| 732 |
}
|
| 733 |
|
| 734 |
/**
|
| 735 |
* Implemenation of hook_delete()
|
| 736 |
*/
|
| 737 |
function invoice_delete(&$node) {
|
| 738 |
$invoice_number = db_result(db_query("SELECT iid FROM {invoice_invoices} WHERE nid=%d", $node->nid));
|
| 739 |
db_query("DELETE FROM {invoice_invoices} WHERE iid=%d", $invoice_number);
|
| 740 |
db_query("DELETE FROM {invoice_customers} WHERE invoice_id=%d", $invoice_number);
|
| 741 |
db_query("DELETE FROM {invoice_items} WHERE invoice_id=%d", $invoice_number);
|
| 742 |
unset($_SESSION['invoice_template']);
|
| 743 |
}
|
| 744 |
|
| 745 |
/**
|
| 746 |
* Implementation of hook_view()
|
| 747 |
*/
|
| 748 |
function invoice_view($node, $teaser = FALSE, $page = FALSE) {
|
| 749 |
$node->content['body'] = array(
|
| 750 |
'#value' => '<div class="view">'. theme('invoice_body', $node, 'view') .'</div>',
|
| 751 |
'#weight' => 0,
|
| 752 |
);
|
| 753 |
|
| 754 |
$links = '<div class="invoice-links">';
|
| 755 |
$links .= _invoice_get_icon('pdf', 'invoice/pdf/'. $node->invoice['invoice_number'], array('width' => '30', 'height' => '30'), 'jpg');
|
| 756 |
$links .= _invoice_get_icon('print', 'invoice/print/'. $node->invoice['invoice_number'], array('width' => '30', 'height' => '30'), 'jpg');
|
| 757 |
$links .= '</div>';
|
| 758 |
|
| 759 |
$node->content['invoice_links'] = array(
|
| 760 |
'#value' => $links,
|
| 761 |
'#weight' => 1,
|
| 762 |
);
|
| 763 |
|
| 764 |
return $node;
|
| 765 |
}
|
| 766 |
|
| 767 |
/**
|
| 768 |
* List of installed locales
|
| 769 |
*/
|
| 770 |
function invoice_installed_locales() {
|
| 771 |
$locales = _invoice_get_installed_system_locales();
|
| 772 |
|
| 773 |
if (count($locales) > 0) {
|
| 774 |
$content = '<ul>';
|
| 775 |
foreach ($locales as $locale) {
|
| 776 |
$content .= '<li>'. $locale .'</li>';
|
| 777 |
}
|
| 778 |
$content .= '</ul>';
|
| 779 |
}
|
| 780 |
else {
|
| 781 |
$content = 'No locales found. But maybe the "locale -a" command is not supported on your system.';
|
| 782 |
}
|
| 783 |
|
| 784 |
return $content;
|
| 785 |
}
|
| 786 |
|
| 787 |
/**
|
| 788 |
* Set the status of an invoice to paid
|
| 789 |
*/
|
| 790 |
function invoice_set_pay_status($invoice_number, $status) {
|
| 791 |
|
| 792 |
if ($status != 'paid' && $status != 'unpaid') {
|
| 793 |
drupal_set_message(t('Invalid invoice pay status'), 'error');
|
| 794 |
}
|
| 795 |
else {
|
| 796 |
db_query("UPDATE {invoice_invoices} SET pay_status='%s' WHERE iid=%d", $status, $invoice_number);
|
| 797 |
drupal_set_message('Succesfully changed pay status of invoice '. check_plain($invoice_number) .' to "paid"');
|
| 798 |
}
|
| 799 |
|
| 800 |
$exp = explode('?', $_GET['q']);
|
| 801 |
$query_string = '?q=&'. $exp[1];
|
| 802 |
|
| 803 |
$a_query_vars = _invoice_getvars_string_to_array($query_string);
|
| 804 |
|
| 805 |
drupal_goto('invoices', $a_query_vars);
|
| 806 |
}
|
| 807 |
|
| 808 |
/**
|
| 809 |
* Display the invoice in HTML print format
|
| 810 |
*/
|
| 811 |
function invoice_view_print($invoice_number) {
|
| 812 |
echo _invoice_get_html($invoice_number);
|
| 813 |
}
|
| 814 |
|
| 815 |
/**
|
| 816 |
* Display the invoice in PDF format
|
| 817 |
*/
|
| 818 |
function invoice_view_pdf($invoice_number) {
|
| 819 |
// include the dompdf library
|
| 820 |
_invoice_dompdf_include_lib();
|
| 821 |
$html = _invoice_get_html($invoice_number, 'pdf');
|
| 822 |
$dompdf = new DOMPDF();
|
| 823 |
$dompdf->load_html($html);
|
| 824 |
$dompdf->render();
|
| 825 |
$dompdf->stream("invoice-". $invoice_number .".pdf", array('Attachment' => 1));
|
| 826 |
die();
|
| 827 |
}
|
| 828 |
|
| 829 |
/**
|
| 830 |
* Theme function for displaying the invoice
|
| 831 |
*/
|
| 832 |
function theme_invoice_body($node, $type=NULL) {
|
| 833 |
|
| 834 |
$content = '<div class="invoice-wrapper">';
|
| 835 |
|
| 836 |
require_once dirname(__FILE__) .'/templates/'. $node->invoice['template'] .'.inc';
|
| 837 |
drupal_add_css(drupal_get_path('module', 'invoice') .'/templates/'. $node->invoice['template'] .'.css', 'module');
|
| 838 |
|
| 839 |
$content_function = '_invoice_'. $node->invoice['template'] .'_get_template_output';
|
| 840 |
$content .= $content_function($node, $type);
|
| 841 |
|
| 842 |
$content .= '</div>';
|
| 843 |
|
| 844 |
return $content;
|
| 845 |
}
|
| 846 |
|
| 847 |
/**
|
| 848 |
* Add extra markup info to a markup form field
|
| 849 |
*
|
| 850 |
* @param string $s_field_name
|
| 851 |
* @param mixed $value
|
| 852 |
* @param string $s_title
|
| 853 |
*/
|
| 854 |
function theme_invoice_markup($s_field_name, $value, $s_title) {
|
| 855 |
$markup_before = '<div id="edit-'. $s_field_name .'-wrapper" class="form-item">
|
| 856 |
<label for="edit-'. $s_field_name .'">'. $s_title .':</label><div>';
|
| 857 |
$markup_after = '</div></div>';
|
| 858 |
|
| 859 |
return $markup_before . $value . $markup_after;
|
| 860 |
}
|
| 861 |
|
| 862 |
|
| 863 |
/**
|
| 864 |
* An override for the table_theme() function
|
| 865 |
*
|
| 866 |
* Added the possibility to disable the sticky header
|
| 867 |
*
|
| 868 |
* @param unknown_type $header
|
| 869 |
* @param unknown_type $rows
|
| 870 |
* @param unknown_type $attributes
|
| 871 |
* @param unknown_type $caption
|
| 872 |
* @return unknown
|
| 873 |
*/
|
| 874 |
function theme_invoice_table($header, $rows, $attributes = array(), $caption = NULL) {
|
| 875 |
|
| 876 |
// Add sticky headers, if applicable.
|
| 877 |
if (count($header) && (bool) $attributes['disable_sticky_header'] != TRUE) {
|
| 878 |
drupal_add_js('misc/tableheader.js');
|
| 879 |
// Add 'sticky-enabled' class to the table to identify it for JS.
|
| 880 |
// This is needed to target tables constructed by this function.
|
| 881 |
$attributes['class'] = empty($attributes['class']) ? 'sticky-enabled' : ($attributes['class'] .' sticky-enabled');
|
| 882 |
}
|
| 883 |
else {
|
| 884 |
unset($attributes['disable_sticky_header']);
|
| 885 |
}
|
| 886 |
|
| 887 |
$output = '<table'. drupal_attributes($attributes) .">\n";
|
| 888 |
|
| 889 |
if (isset($caption)) {
|
| 890 |
$output .= '<caption>'. $caption ."</caption>\n";
|
| 891 |
}
|
| 892 |
|
| 893 |
// Format the table header:
|
| 894 |
if (count($header)) {
|
| 895 |
$ts = tablesort_init($header);
|
| 896 |
// HTML requires that the thead tag has tr tags in it follwed by tbody
|
| 897 |
// tags. Using ternary operator to check and see if we have any rows.
|
| 898 |
$output .= (count($rows) ? ' <thead><tr>' : ' <tr>');
|
| 899 |
foreach ($header as $cell) {
|
| 900 |
$cell = tablesort_header($cell, $header, $ts);
|
| 901 |
$output .= _theme_table_cell($cell, TRUE);
|
| 902 |
}
|
| 903 |
// Using ternary operator to close the tags based on whether or not there are rows
|
| 904 |
$output .= (count($rows) ? " </tr></thead>\n" : "</tr>\n");
|
| 905 |
}
|
| 906 |
else {
|
| 907 |
$ts = array();
|
| 908 |
}
|
| 909 |
|
| 910 |
// Format the table rows:
|
| 911 |
if (count($rows)) {
|
| 912 |
$output .= "<tbody>\n";
|
| 913 |
$flip = array('even' => 'odd', 'odd' => 'even');
|
| 914 |
$class = 'even';
|
| 915 |
foreach ($rows as $number => $row) {
|
| 916 |
$attributes = array();
|
| 917 |
|
| 918 |
// Check if we're dealing with a simple or complex row
|
| 919 |
if (isset($row['data'])) {
|
| 920 |
foreach ($row as $key => $value) {
|
| 921 |
if ($key == 'data') {
|
| 922 |
$cells = $value;
|
| 923 |
}
|
| 924 |
else {
|
| 925 |
$attributes[$key] = $value;
|
| 926 |
}
|
| 927 |
}
|
| 928 |
}
|
| 929 |
else {
|
| 930 |
$cells = $row;
|
| 931 |
}
|
| 932 |
if (count($cells)) {
|
| 933 |
// Add odd/even class
|
| 934 |
$class = $flip[$class];
|
| 935 |
if (isset($attributes['class'])) {
|
| 936 |
$attributes['class'] .= ' '. $class;
|
| 937 |
}
|
| 938 |
else {
|
| 939 |
$attributes['class'] = $class;
|
| 940 |
}
|
| 941 |
|
| 942 |
// Build row
|
| 943 |
$output .= ' <tr'. drupal_attributes($attributes) .'>';
|
| 944 |
$i = 0;
|
| 945 |
foreach ($cells as $cell) {
|
| 946 |
$cell = tablesort_cell($cell, $header, $ts, $i++);
|
| 947 |
$output .= _theme_table_cell($cell);
|
| 948 |
}
|
| 949 |
$output .= " </tr>\n";
|
| 950 |
}
|
| 951 |
}
|
| 952 |
$output .= "</tbody>\n";
|
| 953 |
}
|
| 954 |
|
| 955 |
$output .= "</table>\n";
|
| 956 |
return $output;
|
| 957 |
}
|