if ($user->isClient()) $client_part = "and ts.client_id = $user->client_id";
$sql = "select ts.id, ts.user_id, u.name as user_name, ts.client_id, c.name as client_name,".
- " ts.name, ts.submitter_comment, ts.submit_status from tt_timesheets ts".
+ " ts.name, ts.submitter_comment, ts.submit_status, ts.approval_status, ts.manager_comment from tt_timesheets ts".
" left join tt_users u on (u.id = ts.user_id)".
" left join tt_clients c on (c.id = ts.client_id)".
" where ts.id = $timesheet_id and ts.group_id = $group_id and ts.org_id = $org_id $client_part and ts.status is not null";
}
return $approvers;
}
+
+ // submitTimesheet marks a timesheet as submitted and sends an email to an approver.
+ static function submitTimesheet($fields) {
+ global $user;
+ $mdb2 = getConnection();
+
+ $group_id = $user->getGroup();
+ $org_id = $user->org_id;
+
+ // First, mark a timesheet as submitted.
+ // Even if mail part below does not work, this will get us a functioning workflow
+ // (without email notifications).
+ $timesheet_id = $fields['timesheet_id'];
+ $sql = "update tt_timesheets set submit_status = 1".
+ " where id = $timesheet_id and group_id = $group_id and org_id = $org_id";
+ $affected = $mdb2->exec($sql);
+ if (is_a($affected, 'PEAR_Error')) return false;
+
+ // TODO: send email to approver here...
+ // $approver_id = $fields['approver_id'];
+
+ return true;
+ }
}
// TODO: translate the following.
// 'button.close' => 'Close',
// 'button.stop' => 'Stop',
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
// TODO: translate the following.
// 'button.close' => 'Close',
// 'button.stop' => 'Stop',
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
'button.import' => 'Importer team', // TODO: replace "team" with "group".
'button.close' => 'Luk',
'button.stop' => 'Stop',
+// TODO: translate the following.
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'Team navn', // TODO: replace "team" with "group".
'button.import' => 'Gruppe importieren',
'button.close' => 'Schließen',
'button.stop' => 'Stop',
+// TODO: translate the following.
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'Gruppenname',
'button.import' => 'Import group',
'button.close' => 'Close',
'button.stop' => 'Stop',
+'button.approve' => 'Approve',
+'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'Group name',
// TODO: translate the following.
// 'button.close' => 'Close',
// 'button.stop' => 'Stop',
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
'button.import' => 'Impordi grupp',
'button.close' => 'Sulge',
'button.stop' => 'Stopp',
+// TODO: translate the following.
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
+
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'Grupi nimi',
'button.import' => 'وارد کردن تیم', // TODO: replace "team" with "group".
'button.close' => 'بستن',
'button.stop' => 'توقف',
+// TODO: translate the following.
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'نام تیم', // TODO: replace "team" with "group".
'button.import' => 'Tuo tiimi', // TODO: replace "team" with "group".
'button.close' => 'Sulje',
'button.stop' => 'Lopeta',
+// TODO: translate the following.
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'Tiimin nimi', // TODO: replace "team" with "group".
'button.import' => 'Importer une équipe', // TODO: replace "team" with "group".
'button.close' => 'Fermer',
'button.stop' => 'Arrêter',
+// TODO: translate the following.
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'Nom équipe', // TODO: replace "team" with "group".
'button.import' => 'Εισαγωγή ομάδας',
'button.close' => 'Κλείσιμο',
'button.stop' => 'Τέλος',
+// TODO: translate the following.
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'Όνομα ομάδας',
'button.import' => 'ייבא צוות', // TODO: replace "team" with "group".
'button.close' => 'סגור',
'button.stop' => 'עצור',
+// TODO: translate the following.
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'שם הצוות', // TODO: replace "team" with "group".
// TODO: translate the following.
// 'button.close' => 'Close',
// 'button.stop' => 'Stop',
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
'button.import' => 'Importa gruppo',
'button.close' => 'Chiudi',
'button.stop' => 'Stop',
+// TODO: translate the following.
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'Nome del gruppo',
// TODO: translate the following.
// 'button.close' => 'Close',
// 'button.stop' => 'Stop',
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
// TODO: translate the following.
// 'button.close' => 'Close',
// 'button.stop' => 'Stop',
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
'button.import' => 'Groep importeren',
'button.close' => 'Sluiten',
'button.stop' => 'Stop',
+// TODO: translate the following.
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'Groepsnaam',
'button.close' => 'Lukk',
// TODO: translate the following.
// 'button.stop' => 'Stop',
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
'button.import' => 'Importuj zespół', // TODO: replace "team" with "group".
'button.close' => 'Zamknij',
'button.stop' => 'Zatrzymaj',
+// TODO: translate the following.
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'Nazwa zespołu', // TODO: replace "team" with "group".
'button.import' => 'Importar equipe', // TODO: replace "team" with "group".
'button.close' => 'Fechar',
'button.stop' => 'Parar',
+// TODO: translate the following.
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'Nome da equipe', // TODO: replace "team" with "group".
// 'button.import' => 'Import group',
// 'button.close' => 'Close',
// 'button.stop' => 'Stop',
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
// TODO: translate the following.
// 'button.close' => 'Close',
// 'button.stop' => 'Stop',
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
'button.import' => 'Импортировать группу',
'button.close' => 'Закрыть',
'button.stop' => 'Завершить',
+'button.approve' => 'Одобрить',
+'button.disapprove' => 'Не одобрить',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'Название группы',
'button.close' => 'Zatvoriť',
// TODO: translate the following.
// 'button.stop' => 'Stop',
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'Názov tímu', // TODO: replace "team" with "group".
// TODO: translate the following.
// 'button.close' => 'Close',
// 'button.stop' => 'Stop',
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
'button.import' => 'Uvezi tim', // TODO: replace "team" with "group".
'button.close' => 'Zatvori',
'button.stop' => 'Stani',
+// TODO: translate the following.
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'Naziv tim-a', // TODO: replace "team" with "group".
'button.import' => 'Importera grupp',
'button.close' => 'Stäng',
'button.stop' => 'Avsluta',
+// TODO: translate the following.
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => 'Namn på grupp',
// TODO: translate the following.
// 'button.close' => 'Close',
// 'button.stop' => 'Stop',
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
'button.close' => '关闭',
// TODO: translate the following.
// 'button.stop' => 'Stop',
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
'label.group_name' => '团队名称', // TODO: replace "team" with "group".
// TODO: translate the following.
// 'button.close' => 'Close',
// 'button.stop' => 'Stop',
+// 'button.approve' => 'Approve',
+// 'button.disapprove' => 'Disapprove',
// Labels for controls on forms. Labels in this section are used on multiple forms.
// TODO: translate the following.
<br>
<table cellspacing="0" cellpadding="4" width="100%" border="0">
<tr>
- <td align="center"> Anuko Time Tracker 1.18.37.4752 | Copyright © <a href="https://www.anuko.com/lp/tt_3.htm" target="_blank">Anuko</a> |
+ <td align="center"> Anuko Time Tracker 1.18.37.4753 | Copyright © <a href="https://www.anuko.com/lp/tt_3.htm" target="_blank">Anuko</a> |
<a href="https://www.anuko.com/lp/tt_4.htm" target="_blank">{$i18n.footer.credits}</a> |
<a href="https://www.anuko.com/lp/tt_5.htm" target="_blank">{$i18n.footer.license}</a> |
<a href="https://www.anuko.com/lp/tt_7.htm" target="_blank">{$i18n.footer.improve}</a>
{if $timesheet['submitter_comment']}
<tr><td align="left"><b>{$i18n.label.comment}:</b> {$timesheet['submitter_comment']|escape}</td></tr>
{/if}
+ {if $timesheet['submit_status']}
+ <tr><td align="left"><b>{$i18n.label.approved}:</b> {if $timesheet.approval_status != null}{if $timesheet.approval_status}{$i18n.label.yes}{else}{$i18n.label.no}{/if}</td></tr>{/if}
+ {/if}
+ {if $timesheet['manager_comment']}
+ <tr><td align="left"><b>{$i18n.label.note}:</b> {$timesheet['manager_comment']|escape}</td></tr>
+ {/if}
{/if}
</table>
</td>
<td nowrap class="cellRightAlignedSubtotal">{$user->currency|escape} {if $user->can('manage_invoices') || $user->isClient()}{$totals['cost']}{else}{$totals['expenses']}{/if}</td>
</tr>
</table>
+
+{$forms.timesheetForm.open}
+ {if $show_submit}
+ <table width="720" cellspacing="0" cellpadding="0" border="0">
+ <tr>
+ <td align="center">
+ <table>
+ <tr><td>{$i18n.form.mail.to}: {$forms.timesheetForm.approver.control} {$forms.timesheetForm.btn_submit.control}</td></tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ {/if}
+ {if $show_approve}
+ <table width="720" cellspacing="0" cellpadding="0" border="0">
+ <tr>
+ <td align="center">
+ <table>
+ <tr><td>{$forms.timesheetForm.btn_approve.control} {$forms.timesheetForm.btn_disapprove.control}</td></tr>
+ </table>
+ </td>
+ </tr>
+ </table>
+ {/if}
+{$forms.timesheetForm.close}
+
</td>
</tr>
</table>
exit();
}
// TODO: add other checks here for timesheet being appropriate for user role.
+// TODO: if this is a timeheet submit, validate approver id, too.
// End of access checks.
$options = ttTimesheetHelper::getReportOptions($timesheet);
$totals = ttReportHelper::getTotals($options);
$notClient = !$user->isClient();
-// Determine managers we can submit this timesheet for approval to.
-$approvers = ttTimesheetHelper::getApprovers($timesheet['user_id']);
+// Determine which controls to show and obtain date for them.
+$showSubmit = $notClient && !$timesheet['submit_status'];
+if ($showSubmit) $approvers = ttTimesheetHelper::getApprovers($timesheet['user_id']);
+$canApprove = $user->can('approve_timesheets') || $user_>can('approve_all_timesheets');
+$showApprove = $notClient && $timesheet['submit_status'] && !$timesheet['approval_status'];
+
+// Add a form with controls.
+$form = new Form('timesheetForm');
+$form->addInput(array('type'=>'hidden','name'=>'id','value'=>$timesheet['id']));
+
+if ($showSubmit) {
+ if (count($approvers) >= 1) {
+ $form->addInput(array('type'=>'combobox',
+ 'name'=>'approver',
+ 'style'=>'width: 200px;',
+ 'data'=>$approvers,
+ 'datakeys'=>array('id','name')));
+ }
+ $form->addInput(array('type'=>'submit','name'=>'btn_submit','value'=>$i18n->get('button.submit')));
+}
+
+if ($showApprove) {
+ $form->addInput(array('type'=>'submit','name'=>'btn_approve','value'=>$i18n->get('button.approve')));
+ $form->addInput(array('type'=>'submit','name'=>'btn_disapprove','value'=>$i18n->get('button.disapprove')));
+}
+
+// Submit.
+if ($request->isPost()) {
+ if ($request->getParameter('btn_submit')) {
+ $fields = array('timesheet_id' => $timesheet['id'],
+ 'approver_id' => $approver_id); // TODO: obtain (and check) approver id above during access checks.
+ if (ttTimesheetHelper::submitTimesheet($fields)) {
+ // Redirect to self.
+ header('Location: timesheet_view.php?id='.$timesheet['id']);
+ exit();
+ } else
+ $err->add($i18n->get('error.db'));
+ }
+}
$smarty->assign('not_client', $notClient);
$smarty->assign('group_by_header', ttReportHelper::makeGroupByHeader($options));
$smarty->assign('timesheet', $timesheet);
$smarty->assign('subtotals', $subtotals);
$smarty->assign('totals', $totals);
+$smarty->assign('show_submit', $showSubmit);
+$smarty->assign('show_approve', $showApprove);
+$smarty->assign('forms', array($form->getName()=>$form->toArray()));
$smarty->assign('title', $i18n->get('title.timesheet'));
$smarty->assign('content_page_name', 'timesheet_view.tpl');
$smarty->display('index.tpl');