--- worklog.module.orig 2007-03-15 21:52:15.000000000 -0400 +++ worklog.module 2007-03-15 21:55:26.000000000 -0400 @@ -16,12 +16,7 @@ */ function worklog_help($section) { switch ($section) { - case 'admin/modules#description': - return t('Keep track of time spent working.'); - case 'node/add#worklog': - return t('Log time spent working on something.'); - case 'node/add#worklog-invoice': - return t('A collection of worklog entries.'); + } } @@ -30,9 +25,12 @@ * Implementation of hook_node_info(). */ function worklog_node_info() { - return array('worklog' => array('name' => t('worklog'), 'base' => 'worklog'), - 'worklog-invoice' => array('name' => t('worklog invoice'), - 'base' => 'worklog')); + return array('worklog' => array('name' => t('worklog'), + 'module' => 'worklog', + 'description' => 'Log time spent working on something.'), + 'worklog_invoice' => array('name' => t('worklog invoice'), + 'module' => 'worklog_invoice', + 'description' => 'A collection of worklog entries.')); } /** @@ -41,9 +39,9 @@ define ('WORKLOG_PERM_CREATE', 'create worklog'); define ('WORKLOG_PERM_EDIT', 'edit own worklog'); define ('WORKLOG_PERM_VIEW_OTHERS', 'view others worklog'); +define ('WORKLOG_PERM_ADMIN', 'admin worklog settings'); function worklog_perm() { - return array(WORKLOG_PERM_EDIT, WORKLOG_PERM_CREATE, - WORKLOG_PERM_VIEW_OTHERS); + return array(WORKLOG_PERM_EDIT, WORKLOG_PERM_CREATE, WORKLOG_PERM_VIEW_OTHERS, WORKLOG_PERM_ADMIN); } /** @@ -74,14 +72,16 @@ $items = array(); if ($may_cache) { - $items[] = array('path' => 'node/add/worklog', 'title' => t('worklog'), - 'access' => user_access(WORKLOG_PERM_CREATE)); - $items[] = array('path' => 'node/add/worklog-invoice', - 'title' => t('worklog invoice'), - 'access' => user_access(WORKLOG_PERM_CREATE) - ); + $items[] = array('path' => 'admin/settings/worklog', + 'title' => t('Worklog settings'), + 'description' => t('Configure worklog settings'), + 'callback' => 'drupal_get_form', + 'callback arguments' => array('worklog_settings'), + 'access' => user_access(WORKLOG_PERM_ADMIN), + 'type' => MENU_NORMAL_ITEM + ); } - + return $items; } @@ -94,7 +94,7 @@ if (!user_access(WORKLOG_PERM_VIEW_OTHERS)) { global $user; if ($primary_table == 'n' || $primary_table == 'node') { - $where = "$primary_table.type != 'worklog' OR $primary_table.type != 'worklog-invoice' OR $primary_table.uid=$user->uid"; + $where = "$primary_table.type != 'worklog' OR $primary_table.type != 'worklog_invoice' OR $primary_table.uid=$user->uid"; return array('where' => $where); } } @@ -112,13 +112,6 @@ * Implementation of hook_insert(). */ function worklog_insert($node) { - if ($node->type == 'worklog') - return _worklog_insert($node); - else if ($node->type == 'worklog-invoice') - return _worklog_invoice_insert($node); -} - -function _worklog_insert($node) { $form_values = $node->worklog; if ($form_values['wlid']) // if worklog row already exists, simply update @@ -130,40 +123,17 @@ db_query('INSERT INTO {worklog} (nid, started, elapsed, name, rate) VALUES (%d, %d, %d, \'%s\', %d)', $node->nid, $started, $elapsed, $node->title, $form_values['rate']); - - if (count($node->worklog_invoice)) { - if ($invoice_nid = $node->worklog_invoice['invoice_nid']) { - db_query('INSERT INTO {worklog_invoice_map} (invoice_nid, worklog_nid) VALUES (%d, %d)', $invoice_nid, $node->nid); - } - } - } -function _worklog_invoice_insert($node) { +function worklog_invoice_insert($node) { db_query('INSERT INTO {worklog_invoice} (nid, closed) VALUES (%d, %d)', $node->nid, $node->worklog['closed']); - - if (count($node->worklog_invoice) && - count($node->worklog_invoice['worklog_nids'])) { - foreach ($node->worklog_invoice['worklog_nids'] as $worklog_nid => $checked) { - if ($checked) - db_query('INSERT INTO {worklog_invoice_map} (invoice_nid, worklog_nid) VALUES (%d, %d)', $node->nid, $worklog_nid); - } - } - } /** * Implementation of hook_update(). */ function worklog_update($node) { - if ($node->type == 'worklog') - return _worklog_update($node); - else if ($node->type == 'worklog-invoice') - return _worklog_invoice_update($node); -} - -function _worklog_update($node) { $form_values = $node->worklog; $elapsed = $form_values['elapsed']; $started = $form_values['started']; @@ -171,30 +141,12 @@ db_query('REPLACE INTO {worklog} (wlid, nid, started, elapsed, name, rate) VALUES (%d, %d, %d, %d, \'%s\', %f)', $form_values['wlid'], $node->nid, $started, $elapsed, $node->title, $form_values['rate']); - db_query('DELETE FROM {worklog_invoice_map} WHERE worklog_nid = %d', $node->nid); - if (count($node->worklog_invoice)) { - if ($invoice_nid = $node->worklog_invoice['invoice_nid']) { - db_query('INSERT INTO {worklog_invoice_map} (invoice_nid, worklog_nid) VALUES (%d, %d)', $invoice_nid, $node->nid); - } - } - - } -function _worklog_invoice_update($node) { +function worklog_invoice_update($node) { // will this work if new revision created? db_query('REPLACE INTO {worklog_invoice} (nid, closed) VALUES (%d, %d)', $node->nid, $node->worklog['closed']); - - db_query('DELETE FROM {worklog_invoice_map} WHERE invoice_nid = %d', $node->nid); - if (count($node->worklog_invoice) && - count($node->worklog_invoice['worklog_nids'])) { - foreach ($node->worklog_invoice['worklog_nids'] as $worklog_nid => $checked) { - if ($checked) - db_query('INSERT INTO {worklog_invoice_map} (invoice_nid, worklog_nid) VALUES (%d, %d)', $node->nid, $worklog_nid); - } - } - } @@ -202,50 +154,38 @@ * Implementation of hook_delete(). */ function worklog_delete($node) { - if ($node->type == 'worklog') { - db_query('DELETE FROM {worklog} WHERE wlid=%d', $node->worklog->wlid); - db_query('DELETE FROM {worklog_invoice_map} WHERE worklog_nid=%d', $node->nid); - } - else if ($node->type == 'worklog-invoice') { - // TODO: what should happen to orphaned worklog entries? - db_query('DELETE FROM {worklog_invoice_map} WHERE invoice_nid=%d', $node->nid); - db_query('DELETE FROM {worklog_invoice} WHERE nid=%d', $node->nid); - } + db_query('DELETE FROM {worklog} WHERE wlid=%d', $node->worklog->wlid); + db_query('DELETE FROM {worklog_invoice_map} WHERE worklog_nid=%d', $node->nid); +} +function worklog_invoice_delete($node) { + // TODO: what should happen to orphaned worklog entries? + db_query('DELETE FROM {worklog_invoice_map} WHERE invoice_nid=%d', $node->nid); + db_query('DELETE FROM {worklog_invoice} WHERE nid=%d', $node->nid); } /** * Implementation of hook_load(). */ function worklog_load($node) { - if ($node->type == 'worklog') { - $worklog = db_fetch_object(db_query('SELECT * FROM {worklog} WHERE nid=%d', $node->nid)); - $invoice = db_result(db_query('SELECT invoice_nid FROM {worklog_invoice_map} WHERE worklog_nid = %d', $node->nid)); - $worklog->invoice_nid = $invoice; - - return array('worklog' => $worklog); - } - - else if ($node->type == 'worklog-invoice') { - $invoice_map = db_query('SELECT * FROM {worklog_invoice_map} WHERE invoice_nid = %d', $node->nid); - $invoice = db_fetch_object(db_query('SELECT * FROM {worklog_invoice} WHERE nid=%d', $node->nid)); - while ($row = db_fetch_object($invoice_map)) { - $invoice->worklog_nids[] = $row->worklog_nid; - } - return array('worklog' => $invoice); + $worklog = db_fetch_object(db_query('SELECT * FROM {worklog} WHERE nid=%d', $node->nid)); + $invoice = db_result(db_query('SELECT invoice_nid FROM {worklog_invoice_map} WHERE worklog_nid = %d', $node->nid)); + $worklog->invoice_nid = $invoice; + + return array('worklog' => $worklog); +} +function worklog_invoice_load($node) { + $invoice_map = db_query('SELECT * FROM {worklog_invoice_map} WHERE invoice_nid = %d', $node->nid); + $invoice = db_fetch_object(db_query('SELECT * FROM {worklog_invoice} WHERE nid=%d', $node->nid)); + while ($row = db_fetch_object($invoice_map)) { + $invoice->worklog_nids[] = $row->worklog_nid; } + return array('worklog' => $invoice); } /** * Implementation of hook_form(). */ function worklog_form(&$node) { - if ($node->type == 'worklog') - return _worklog_form($node); - else if ($node->type == 'worklog-invoice') - return _worklog_invoice_form($node); -} - -function _worklog_form(&$node) { // if we are creating a new node, get default values from wlid passed in if (!isset($node->nid) && !isset($node->worklog)) { $timer = _worklog_get_timer($_REQUEST['wlid']); @@ -286,98 +226,21 @@ $form['body'] = array('#type' => 'textarea', '#title' => t('Description'), '#default_value' => $node->body, '#rows' => 5, '#required' => false); $form['format'] = filter_form($node->format); - // mapping between worklog and invoice - $invoice_nid = $node->worklog->invoice_nid; - $invoice = new stdClass(); - if ($invoice_nid) { - $invoice = node_load($invoice_nid); - if ($invoice->worklog->closed) { - drupal_set_message(t('This worklog entry may have already been invoiced.')); - $form['worklog_invoice'] = - array('#type' => 'fieldset', - '#title' => t('Invoice'), - '#description' => t('This worklog entry is included in the invoice %invoice_link. The invoice has been marked closed. It is recommended not to make any changes to this entry.', - array('%invoice_link' => $invoice->title)), - ); - } - } - if (!$invoice_nid || !$invoice->worklog->closed) { - // let user assign a worklog to an invoice - $form['worklog_invoice'] = - array('#type' => 'fieldset', - '#title' => t('Invoice'), - '#tree' => TRUE, - '#collapsible' => TRUE, - ); - - $result = db_query(db_rewrite_sql('SELECT n.title, n.nid FROM {node} n LEFT JOIN {worklog_invoice} wi ON n.nid = wi.nid WHERE n.type=\'worklog-invoice\' AND n.status = 1 AND (wi.closed = 0 OR n.nid=%d)'), $invoice_nid); - $options = array(0 => t('no invoice')); - while ($row = db_fetch_object($result)) { - $options[$row->nid] = t('%title', - array('%title' =>$row->title, - ) - ); - } - $form['worklog_invoice']['invoice_nid'] = - array('#type' => 'radios', - '#title' => t('Select invoice'), - '#options' => $options, - '#default_value' => $invoice_nid, - '#description' => t('This item will be included in the chosen invoice.'), - ); - - } - return $form; } -function _worklog_invoice_form(&$node) { +function worklog_invoice_form(&$node) { $form['title'] = array('#type' => 'textfield', '#title' => t('Title'), '#required' => TRUE, '#default_value' => $node->title); - $form['worklog'] = array('#tree' => true, - '#weight' => -1, - ); + $form['worklog'] = array('#tree' => true, '#weight' => -1,); $form['worklog']['closed'] = array('#type' => 'checkbox', '#title' => t('Closed to new entries'), '#default_value' => $node->worklog->closed, '#description' => t('Check this box when you will not add more worklog entries to this invoice. For example, after you have sent the invoice to a client.'), ); - $form['body'] = array('#type' => 'textarea', '#title' => t('Description'), '#default_value' => $node->body, '#rows' => 5, '#required' => false); $form['format'] = filter_form($node->format); - // on invoice form, allow choice of all non-invoiced worklogs - $result = db_query(db_rewrite_sql('SELECT n.title, w.* FROM {node} n LEFT JOIN {worklog} w ON n.nid = w.nid LEFT JOIN {worklog_invoice_map} wim ON wim.worklog_nid = n.nid WHERE n.type=\'worklog\' AND n.status = 1 AND (wim.invoice_nid IS NULL OR wim.invoice_nid = %d)'), $node->nid); - $options = array(); - while ($row = db_fetch_object($result)) { - // TODO: show more than title, perhaps build a table. - $options[$row->nid] = t('%title (%hours @ %rate = %amount)', - array('%title' =>$row->title, - '%hours' => _worklog_format_duration($row->elapsed), - '%rate' => $row->rate, - '%amount' => _worklog_calculate_bill($row->elapsed, $row->rate) - )); - } - $form['worklog_invoice'] = - array('#type' => 'fieldset', - '#title' => t('Invoice items'), - '#tree' => TRUE, - '#collapsible' => TRUE, - ); - if (count($options)) { - //drupal_set_message(dprint_r($form['#node'], 1)); - $form['worklog_invoice']['worklog_nids'] = - array('#type' => 'checkboxes', - '#title' => t('Select items'), - '#options' => $options, - '#default_value' => $node->worklog->worklog_nids, - '#description' => t('Choose the items to include in this invoice.'), - ); - } - else { - $form['worklog_invoice']['#description'] = t('There are no worklog entries to include in this invoice.'); - } - return $form; } @@ -401,89 +264,103 @@ define('WORKLOG_BUTTON_RESUME', t('Resume')); define('WORKLOG_BUTTON_SAVE', t('Save')); +function worklog_forms() { + $forms['worklog_paused_form']= array( + 'callback' => 'worklog_paused_form', + 'callback arguments' => array('worklog_paused_form'), + ); + $forms['worklog_stop_form']= array( + 'callback' => 'worklog_stop', + 'callback arguments' => array('worklog_stop_form'), + ); + $forms['worklog_start_form']= array( + 'callback' => 'worklog_start', + 'callback arguments' => array('worklog_start_form'), + ); + return $forms; +} + +function worklog_stop_form($timer) { + $form['name'] = array('#type' => 'markup', + '#value' => "

$timer->name

" + ); + $form['wlid'] = array('#type' => 'hidden', + '#value' => $timer->wlid); + $form['buttons'][] = array('#type' => 'submit', + '#name' => 'op', + '#value' => WORKLOG_BUTTON_PAUSE + ); + $form['buttons'][] = array('#type' => 'submit', + '#name' => 'op', + '#value' => WORKLOG_BUTTON_STOP + ); + return $form; +} +function worklog_start_form() { + // the form to start a new timer + $form['name'] = array('#type' => 'textfield', + '#title' => t('Task name'), + '#size' => 20, + ); + $form['submit'] = array('#type' => 'submit', + '#value' => t('Start Timer') + ); + // $form['#attributes'] = array('target' => '_blank'); // new window + return $form; +} + +function worklog_paused_form($timer) { + $form[$timer->wlid] = array('#type' => 'fieldset'); + $form[$timer->wlid][] = array('#type' => 'markup', '#value' => "
$timer->name "._worklog_format_duration($timer->elapsed)."
"); + $form[$timer->wlid][] = array('#type' => 'submit', '#name' => 'worklog_'.$timer->wlid, '#value' => WORKLOG_BUTTON_RESUME, '#attributes' => $resume_attrs, ); + $form[$timer->wlid][] = array('#type' => 'submit', '#name' => 'worklog_'.$timer->wlid, '#value' => WORKLOG_BUTTON_SAVE); + return $form; +} + /** * Define the blocks. Implementation of hook_block() */ -function worklog_block($op = 'list', $delta=0, $edit=array()) { +function worklog_block($op = 'list', $delta=0) { switch ($op) { case 'list': - $items[WORKLOG_BLOCK_TIMER]['info'] = - t('Worklog: start a worklog timer'); - $items[WORKLOG_BLOCK_PAUSED]['info'] = - t('Worklog: paused timers'); - $items[WORKLOG_BLOCK_OP]['info'] = - t('Worklog: operations'); - return $items; + $blocks[WORKLOG_BLOCK_TIMER]['info'] = t('Worklog: start a worklog timer'); + $blocks[WORKLOG_BLOCK_PAUSED]['info'] = t('Worklog: paused timers'); + $blocks[WORKLOG_BLOCK_OP]['info'] = t('Worklog: operations'); + return $blocks; case 'view': switch ($delta) { - case WORKLOG_BLOCK_TIMER: - if (!user_access(WORKLOG_PERM_CREATE)) - return; - - if ($timer = _worklog_current_timer()) { - $form['name'] = array('#type' => 'markup', - '#value' => "

$timer->name

"); - $form['wlid'] = array('#type' => 'hidden', - '#value' => $timer->wlid); - $form['buttons'][] = array('#type' => 'submit', - '#name' => 'op', - '#value' => WORKLOG_BUTTON_PAUSE, - ); - $form['buttons'][] = array('#type' => 'submit', - '#name' => 'op', - '#value' => WORKLOG_BUTTON_STOP, - ); - $block['content'] = drupal_get_form('worklog_stop_form', $form); - $block['subject'] = t('Worklog Timer'); - } - else { - // the form to start a new timer - $form['name'] = array('#type' => 'textfield', - '#title' => t('Task name'), - '#size' => 20, - ); - $form['submit'] = array('#type' => 'submit', - '#value' => t('Start Timer') - ); - // $form['#attributes'] = array('target' => '_blank'); // new window - $block['content'] = drupal_get_form('worklog_start_form', $form); - $block['subject'] = t('Worklog New Timer'); - } - return $block; - case WORKLOG_BLOCK_PAUSED: + case WORKLOG_BLOCK_TIMER && user_access(WORKLOG_PERM_CREATE): + if($timer = _worklog_current_timer()) { + $block['content'] = drupal_get_form('worklog_stop_form',$timer); + } + else { + $block['content'] = drupal_get_form('worklog_start_form'); + } + $block['subject'] = t('Worklog New Timer'); + return $block; + case WORKLOG_BLOCK_PAUSED && user_access(WORKLOG_PERM_EDIT): global $user; - if (!user_access(WORKLOG_PERM_EDIT)) - return; - // give user control over paused timers $result = db_query("SELECT * FROM {worklog} WHERE nid IS NULL AND timer_start = 0 AND uid=%d", $user->uid); if (!db_num_rows($result)) return; - - $form = array(); $current_timer = _worklog_current_timer(); if ($current_timer) - $resume_attrs = array('disabled' => 1); + $resume_attrs = array('disabled' => 1); while ($timer = db_fetch_object($result)) { - $form[$timer->wlid] = array('#type' => 'fieldset'); - $form[$timer->wlid][] = array('#type' => 'markup', - '#value' => "
$timer->name "._worklog_format_duration($timer->elapsed)."
"); - $form[$timer->wlid][] = array('#type' => 'submit', - '#name' => 'worklog_'.$timer->wlid, - '#value' => WORKLOG_BUTTON_RESUME, - '#attributes' => $resume_attrs, - ); - $form[$timer->wlid][] = array('#type' => 'submit', - '#name' => 'worklog_'.$timer->wlid, - '#value' => WORKLOG_BUTTON_SAVE); - } - $block['content'] .= drupal_get_form('worklog_paused_form', $form); + $block['content'] .= drupal_get_form('worklog_paused_form',$timer); + } $block['subject'] = t('Worklog: Paused Timers'); return $block; } } } - +/** +* Theme the block worklog form. +*/ +function theme_worklog_block_form($form) { +//return drupal_render($form); +} /** * Our pause form presents buttons for each paused timer. * Here we figure out which timer to act on and perform the necessary action. @@ -715,7 +592,7 @@ function worklog_view(&$node, $teaser=false, $page=false) { if ($node->type == 'worklog') return _worklog_view($node, $teaser, $pager); - else if ($node->type == 'worklog-invoice') { + else if ($node->type == 'worklog_invoice') { return _worklog_invoice_view($node, $teaser, $pager); } } @@ -737,8 +614,7 @@ function _worklog_invoice_view(&$node, $teaser, $page) { $node = node_prepare($node, $teaser); - if (($vid = variable_get('worklog_invoice_view', 'worklog_invoice')) && - function_exists('views_get_view')) { + if ($vid = variable_get('worklog_invoice_view', 0)) { // use a view to render invoice items $view = views_get_view($vid); $node->body .= views_build_view('embed', $view, array($node->nid), @@ -773,10 +649,10 @@ if ($invoice_nid = $node->worklog->invoice_nid) { $invoice = node_load($invoice_nid); if ($invoice->status) - $items[] = l($invoice->title, "node/$invoice_nid"); + $links['worklog_invoice_$invoice_nid'] = array('title' => t($invoice->title), 'href' => "node/$invoice_nid"); } } - return $items; + return $links; } function worklog_views_tables() { @@ -831,7 +707,7 @@ if ($op == 'summary') { $query->add_field('title'); $query->add_field('nid'); - $query->add_where("node.type = 'worklog-invoice'"); + $query->add_where("node.type = 'worklog_invoice'"); return array('field' => 'node.title'); } else if ($op == 'title') { @@ -882,6 +758,43 @@ return theme('worklog_price', $billable); } +/** + * theme function called by views module + */ +/* XXX +function theme_views_view_worklog($view, $type, $data) { + // TODO: break data up into weekly chunks + + if ($type == 'page') { + drupal_set_title(views_get_title($view)); + } + if ($view->header) { + $header = check_markup($view->header, $view->header_format, false); + $output = "
$header
\n"; + } + + $output .= theme('views_view_table', $view, $data); + + // compute totals + $total_elapsed = 0; + $total_bill = 0; + foreach ($data as $datum) { + //drupal_set_message(theme('debug', $datum)); + $elapsed = _worklog_round_duration($datum->worklog_elapsed); + $total_elapsed += $elapsed; + if ($datum->worklog_rate) { + $total_bill += _worklog_round_bill(($datum->worklog_rate * $elapsed) / (60 * 60)); + } + } + + $output .= "
\n
".t("Total Time")."
".theme('worklog_duration', $total_elapsed)."
\n"; + // TODO: format nicely + $output .= "
".t("Total Bill")."
".$total_bill."
\n"; + $output .= "
\n"; + + return $output; +} +*/ /** * Display seconds as hours @@ -895,15 +808,146 @@ return worklog_format_price($amount); } +/////////////////////////////////////////////////////////////////////////// +// functions for invoices + +/** + * Use hook_form_alter to manage the one-to-many relationship between invoices + * and worklog entries + */ +function worklog_form_alter($form_id, &$form) { + if (isset($form['type']) && + isset($form['type']['#value'])) { + $type = $form['type']['#value']; + if ($type . '_node_form' == $form_id) { + // it's a node form + $nid = $form['nid']['#value']; + if ($type == 'worklog_invoice') { + // on invoice form, allow choice of all non-invoiced worklogs + $result = db_query(db_rewrite_sql('SELECT n.title, w.* FROM {node} n LEFT JOIN {worklog} w ON n.nid = w.nid LEFT JOIN {worklog_invoice_map} wim ON wim.worklog_nid = n.nid WHERE n.type=\'worklog\' AND n.status = 1 AND (wim.invoice_nid IS NULL OR wim.invoice_nid = %d)'), $nid); + $options = array(); + while ($row = db_fetch_object($result)) { + // TODO: show more than title, perhaps build a table. + $options[$row->nid] = t('%title (%hours @ %rate = %amount)', + array('%title' =>$row->title, + '%hours' => _worklog_format_duration($row->elapsed), + '%rate' => $row->rate, + '%amount' => _worklog_calculate_bill($row->elapsed, $row->rate) + )); + } + $form['worklog_invoice'] = + array('#type' => 'fieldset', + '#title' => t('Invoice items'), + '#tree' => TRUE, + '#collapsible' => TRUE, + ); + //drupal_set_message(dprint_r($form['#node'], 1)); + $form['worklog_invoice']['worklog_nids'] = + array('#type' => 'checkboxes', + '#title' => t('Select items'), + '#options' => $options, + '#default_value' => $form['#node']->worklog->worklog_nids, + '#description' => t('Choose the items to include in this invoice.'), + ); + + // callback to perform invoice to worklog mapping + $form['#submit'] = array('_worklog_invoice_map_form_submit' => array()) + (array)$form['#submit']; + + } + else if ($type == 'worklog') { + $invoice_nid = $form['#node']->worklog->invoice_nid; + $invoice = new stdClass(); + if ($invoice_nid) { + $invoice = node_load($invoice_nid); + if ($invoice->worklog->closed) { + drupal_set_message(t('This worklog entry may have already been invoiced.')); + $form['worklog_invoice'] = + array('#type' => 'fieldset', + '#title' => t('Invoice'), + '#description' => t('This worklog entry is included in the invoice %invoice_link. The invoice has been marked closed. It is recommended not to make any changes to this entry.', + array('%invoice_link' => $invoice->title)), + ); + } + } + if (!$invoice_nid || !$invoice->worklog->closed) { + // let user assign a worklog to an invoice + $form['worklog_invoice'] = + array('#type' => 'fieldset', + '#title' => t('Invoice'), + '#tree' => TRUE, + '#collapsible' => TRUE, + ); + $result = db_query('SELECT n.title, n.nid FROM {node} n LEFT JOIN {worklog_invoice} wi ON n.nid = wi.nid WHERE n.type=\'%s\' AND n.status = 1 AND (wi.closed = 0)',array('%s'=>'worklog_invoice')); + $options = array(0 => t('no invoice')); + while ($row = db_fetch_object($result)) { + $options[$row->nid] = t('%title', + array('%title' =>$row->title, + ) + ); + } + $form['worklog_invoice']['invoice_nid'] = + array('#type' => 'radios', + '#title' => t('Select invoice'), + '#options' => $options, + '#default_value' => $invoice_nid, + '#description' => t('This item will be included in the chosen invoice.'), + ); + + } + // callback to perform invoice to worklog mapping + $form['#submit'] = array('_worklog_map_form_submit' => array()) + (array)$form['#submit']; + + + } + } + } +} + +function _worklog_invoice_map_form_submit($form_id, $values) { + //drupal_set_message("_worklog_invoice_map_form_submit($form_id)" . dprint_r($values, 1)); + $invoice_nid = $values['nid']; + db_query('DELETE FROM {worklog_invoice_map} WHERE invoice_nid = %d', $invoice_nid); + if (count($values['worklog_invoice']) && + count($values['worklog_invoice']['worklog_nids'])) { + foreach ($values['worklog_invoice']['worklog_nids'] as $worklog_nid => $checked) { + if ($checked) + db_query('INSERT INTO {worklog_invoice_map} (invoice_nid, worklog_nid) VALUES (%d, %d)', $invoice_nid, $worklog_nid); + } + } +} +function _worklog_map_form_submit($form_id, $values) { + //drupal_set_message("_worklog_map_form_submit($form_id)" . dprint_r($values, 1)); + $worklog_nid = $values['nid']; + db_query('DELETE FROM {worklog_invoice_map} WHERE worklog_nid = %d', $worklog_nid); + if (count($values['worklog_invoice'])) { + if ($invoice_nid = $values['worklog_invoice']['invoice_nid']) { + db_query('INSERT INTO {worklog_invoice_map} (invoice_nid, worklog_nid) VALUES (%d, %d)', $invoice_nid, $worklog_nid); + } + } +} function worklog_settings() { + $form['worklog_invoice'] = + array('#type' => 'fieldset', + '#title' => t('Invoice settings'), + ); + $options = array(0 => '<' . t('none') . '>') + + _worklog_get_views(); + $form['worklog_invoice']['worklog_invoice_view'] = + array('#type' => 'select', + '#title' => t('Worklog view'), + '#description' => t('Use the Views module to define a view showing all the entries in an invoice. The view\'s first argument should be a worklog invoice ID. Select the view here, and it will be included when viewing an invoice.'), + '#options' => $options, + '#default_value' => variable_get('worklog_invoice_view', 0), + ); + // Begin price format section $form['price_format'] = array( '#type' => 'fieldset', '#title' => t('Price Formatting'), '#collapsible' => TRUE, - '#collapsed' => FALSE, + '#collapsed' => TRUE, ); $form['price_format']['worklog_symbol'] = array( '#type' => 'textfield', @@ -941,10 +985,30 @@ '#size' => 3, '#maxlength' => 5, '#desciption' => t('How many slots are needed after the decimal?') ); + return system_settings_form($form); +} - - - return $form; +/** + * Fetches a list of all views from the database. + * + * Unfortunately the views module does not provide a helper for us, so we have to use some knowledge of the views database schema. + * + * @return + * An array of views, where each key is the view's ID, and each value is its + * description (not its title). + */ +function _worklog_get_views() { + $views = array(); + + if (function_exists('views_build_view')) { + // views module is installed + $result = db_query("SELECT vid, name FROM {view_view} ORDER BY description"); + while ($view = db_fetch_object($result)) { + $views[$view->vid] = $view->name; + } + } + + return $views; } /** @@ -958,83 +1022,4 @@ return (variable_get('worklog_symbol_position', 1) == 1) ? variable_get('worklog_symbol', '$') . $price : $price . variable_get('worklog_symbol', '$'); } -//////////////////////////////////////////////////////////////// -// default views - -/** - * worklog_invoice view is included in each invoice. It displays a summary of - * each worklog entry in the invoice. - */ -function worklog_views_default_views() { - $view = new stdClass(); - $view->name = 'worklog_invoice'; - $view->description = 'Display worklog items in an invoice'; - $view->access = array ( -); - $view->view_args_php = ''; - $view->page = TRUE; - $view->page_title = 'Worklog invoice items %1'; - $view->page_header = ''; - $view->page_header_format = '1'; - $view->page_footer = ''; - $view->page_footer_format = '1'; - $view->page_empty = 'No items'; - $view->page_empty_format = '1'; - $view->page_type = 'table'; - $view->url = 'worklog_invoice'; - $view->use_pager = TRUE; - $view->nodes_per_page = '99'; - $view->sort = array ( - array ( - 'tablename' => 'worklog', - 'field' => 'started', - 'sortorder' => 'ASC', - 'options' => '', - ), - ); - $view->argument = array ( - array ( - 'type' => '0', - 'argdefault' => '6', - 'title' => '', - 'options' => '', - 'wildcard' => '', - 'wildcard_substitution' => '', - ), - ); - $view->field = array ( - array ( - 'tablename' => 'node', - 'field' => 'title', - 'label' => 'item', - 'handler' => 'views_handler_field_nodelink', - 'sortable' => '1', - ), - array ( - 'tablename' => 'worklog', - 'field' => 'elapsed', - 'label' => 'time', - 'sortable' => '1', - ), - array ( - 'tablename' => 'worklog', - 'field' => 'rate', - 'label' => 'rate', - 'sortable' => '1', - ), - array ( - 'tablename' => 'worklog', - 'field' => 'bill', - 'label' => 'amount', - ), - ); - $view->filter = array ( - ); - $view->exposed_filter = array ( - ); - $view->requires = array(worklog, node); - $views[$view->name] = $view; - - return $views; -} -?> \ Pas de fin de ligne à la fin du fichier. +?>