WEB-INF/templates_c/*.php
WEB-INF/templates_c/*.png
WEB-INF/lib/tcpdf/
-nbproject/
\ No newline at end of file
+nbproject/
+upload/
+.vscode/
\ No newline at end of file
return (int)@$time_a[1] + ((int)@$time_a[0]) * 60;
}
- // toDuration - calculates duration between start and finish times in 00:00 format.
- static function toDuration($start, $finish) {
- $duration_minutes = ttTimeHelper::toMinutes($finish) - ttTimeHelper::toMinutes($start);
- if ($duration_minutes <= 0) return false;
-
- $hours = (string)((int)($duration_minutes / 60));
- $mins = (string)($duration_minutes % 60);
+ // fromMinutes - converts a number of minutes to format 00:00
+ static function fromMinutes($minutes){
+ $hours = (string)((int)($minutes / 60));
+ $mins = (string)(abs($minutes % 60));
if (strlen($hours) == 1)
$hours = '0'.$hours;
if (strlen($mins) == 1)
return $hours.':'.$mins;
}
+ // toDuration - calculates duration between start and finish times in 00:00 format.
+ static function toDuration($start, $finish) {
+ $duration_minutes = ttTimeHelper::toMinutes($finish) - ttTimeHelper::toMinutes($start);
+ if ($duration_minutes <= 0) return false;
+
+ return ttTimeHelper::fromMinutes($duration_minutes);
+ }
+
// The to12HourFormat function converts a 24-hour time value (such as 15:23) to 12 hour format (03:23 PM).
static function to12HourFormat($value) {
if ('24:00' == $value) return '12:00 AM';
return 0;
}
+ // getTimeForMonth - gets total time for a user for a given month.
+ static function getTimeForMonth($user_id, $date){
+ import('Period');
+ $mdb2 = getConnection();
+
+ $period = new Period(INTERVAL_THIS_MONTH, $date);
+ $sql = "select sum(time_to_sec(duration)) as sm from tt_log where user_id = $user_id and date >= '".$period->getBeginDate(DB_DATEFORMAT)."' and date <= '".$period->getEndDate(DB_DATEFORMAT)."' and status = 1";
+ $res = $mdb2->query($sql);
+ if (!is_a($res, 'PEAR_Error')) {
+ $val = $res->fetchRow();
+ return sec_to_time_fmt_hm($val['sm']);
+ }
+ return 0;
+ }
+
// getUncompleted - retrieves an uncompleted record for user, if one exists.
static function getUncompleted($user_id) {
$mdb2 = getConnection();
'label.cost' => 'Kosten',
'label.week_total' => 'Summe (Woche)',
'label.day_total' => 'Summe (Tag)',
+// 'label.month_total' => 'Month total',
+// 'label.month_left' => 'Time until quota is met',
+// 'label.month_over' => 'Over monthly quota',
'label.today' => 'Heute',
'label.total_hours' => 'Gesamtstunden',
'label.total_cost' => 'Totale Kosten',
// TODO: translate the following strings.
// 'label.cron_schedule' => 'Cron schedule',
// 'label.what_is_it' => 'What is it?',
+// 'label.year' => 'Year',
+// 'label.month' => 'Month',
+// 'label.quota' => 'Quota',
// Form titles.
'title.login' => 'Anmelden',
// 'title.add_notification' => 'Adding Notification',
// 'title.edit_notification' => 'Editing Notification',
// 'title.delete_notification' => 'Deleting Notification',
+// 'title.monthly_quota' => 'Monthly quota',
'title.export' => 'Daten exportieren',
'title.import' => 'Daten importieren',
'title.options' => 'Optionen',
'label.cost' => 'Cost',
'label.week_total' => 'Week total',
'label.day_total' => 'Day total',
+'label.month_total' => 'Month total',
+'label.month_left' => 'Time until quota is met',
+'label.month_over' => 'Over monthly quota',
'label.today' => 'Today',
'label.total_hours' => 'Total hours',
'label.total_cost' => 'Total cost',
'label.fav_report' => 'Favorite report',
'label.cron_schedule' => 'Cron schedule',
'label.what_is_it' => 'What is it?',
+'label.year' => 'Year',
+'label.month' => 'Month',
+'label.quota' => 'Quota',
// Form titles.
'title.login' => 'Login',
'title.add_notification' => 'Adding Notification',
'title.edit_notification' => 'Editing Notification',
'title.delete_notification' => 'Deleting Notification',
+'title.monthly_quota' => 'Monthly quota',
'title.export' => 'Exporting Team Data',
'title.import' => 'Importing Team Data',
'title.options' => 'Options',
// 'label.cost' => 'Cost',
// 'label.week_total' => 'Week total',
// 'label.day_total' => 'Day total',
+// 'label.month_total' => 'Month total',
+// 'label.month_left' => 'Time until quota is met',
+// 'label.month_over' => 'Over monthly quota',
'label.today' => 'Hoy',
'label.total_hours' => 'Horas totales',
// TODO: translate the following strings.
// TODO: translate the following strings.
// 'label.cron_schedule' => 'Cron schedule',
// 'label.what_is_it' => 'What is it?',
+// 'label.year' => 'Year',
+// 'label.month' => 'Month',
+// 'label.quota' => 'Quota',
// Form titles.
'title.login' => 'Sesión iniciada',
// 'title.add_notification' => 'Adding Notification',
// 'title.edit_notification' => 'Editing Notification',
// 'title.delete_notification' => 'Deleting Notification',
+// 'title.monthly_quota' => 'Monthly quota',
'title.export' => 'Exportar datos',
'title.import' => 'Importar datos',
'title.options' => 'Opciones',
'label.cost' => 'هزینه',
'label.week_total' => 'کل هفته',
'label.day_total' => 'کل روز',
+// 'label.month_total' => 'Month total',
+// 'label.month_left' => 'Time until quota is met',
+// 'label.month_over' => 'Over monthly quota',
'label.today' => 'امروز',
'label.total_hours' => 'مجموع ساعت',
'label.total_cost' => 'مجموع هزینه ها',
// TODO: translate the following strings.
// 'label.cron_schedule' => 'Cron schedule',
// 'label.what_is_it' => 'What is it?',
+// 'label.year' => 'Year',
+// 'label.month' => 'Month',
+// 'label.quota' => 'Quota',
// Form titles.
'title.login' => 'ورود',
// 'title.add_notification' => 'Adding Notification',
// 'title.edit_notification' => 'Editing Notification',
// 'title.delete_notification' => 'Deleting Notification',
+// 'title.monthly_quota' => 'Monthly quota',
'title.export' => 'پشتیانی گرفتن از اطلاعات تیم',
'title.import' => 'وارد کردن اطلاعات تیم',
'title.options' => 'گزینه ها',
'label.cost' => 'Hinta',
'label.week_total' => 'Viikko yhteensä',
'label.day_total' => 'Päivä yhteensä',
+// 'label.month_total' => 'Month total',
+// 'label.month_left' => 'Time until quota is met',
+// 'label.month_over' => 'Over monthly quota',
'label.today' => 'Tänään',
'label.total_hours' => 'Tunnit yhteensä',
'label.total_cost' => 'Hinta yhteensä',
'label.fav_report' => 'Raporttipohja',
'label.cron_schedule' => 'Cron-ajoitus',
'label.what_is_it' => 'Mikä se on?',
+// 'label.year' => 'Year',
+// 'label.month' => 'Month',
+// 'label.quota' => 'Quota',
// TODO? missing?
'label.page' => 'Sivu',
'title.add_notification' => 'Ilmoituksen lisäys',
'title.edit_notification' => 'Ilmoituksen muokkaus',
'title.delete_notification' => 'Ilmoituksen poisto',
+// 'title.monthly_quota' => 'Monthly quota',
'title.export' => 'Tiimitietojen vienti',
'title.import' => 'Tiimitietojen tunti',
'title.options' => 'Optiot',
'label.week_total' => 'Total hebdomadaire',
// TODO: translate the following string.
// 'label.day_total' => 'Day total',
+// 'label.month_total' => 'Month total',
+// 'label.month_left' => 'Time until quota is met',
+// 'label.month_over' => 'Over monthly quota',
'label.today' => 'Aujourd\\\'hui',
'label.total_hours' => 'Total d\\\'heures',
'label.total_cost' => 'Coût total',
// TODO: translate the following strings.
// 'label.cron_schedule' => 'Cron schedule',
// 'label.what_is_it' => 'What is it?',
+// 'label.year' => 'Year',
+// 'label.month' => 'Month',
+// 'label.quota' => 'Quota',
// Form titles.
'title.login' => 'Connexion',
// 'title.add_notification' => 'Adding Notification',
// 'title.edit_notification' => 'Editing Notification',
// 'title.delete_notification' => 'Deleting Notification',
+// 'title.monthly_quota' => 'Monthly quota',
'title.export' => 'Exporter les données', // TODO: use a noun.
'title.import' => 'Importer les données', // TODO: use a noun.
'title.options' => 'Options',
'label.cost' => 'עלות',
'label.week_total' => 'סיכום שבועי',
'label.day_total' => 'סיכום יומי',
+// 'label.month_total' => 'Month total',
+// 'label.month_left' => 'Time until quota is met',
+// 'label.month_over' => 'Over monthly quota',
'label.today' => 'היום',
'label.total_hours' => 'סך הכל שעות',
'label.total_cost' => 'סך הכל עלות',
// TODO: translate the following strings.
// 'label.cron_schedule' => 'Cron schedule',
// 'label.what_is_it' => 'What is it?',
+// 'label.year' => 'Year',
+// 'label.month' => 'Month',
+// 'label.quota' => 'Quota',
// Form titles.
'title.login' => 'כניסה',
// 'title.add_notification' => 'Adding Notification',
// 'title.edit_notification' => 'Editing Notification',
// 'title.delete_notification' => 'Deleting Notification',
+// 'title.monthly_quota' => 'Monthly quota',
'title.export' => 'ייצוא נתוני צוות',
'title.import' => 'ייבוא נתוני צוות',
'title.options' => 'אפשרויות',
'label.cost' => 'Kosten',
'label.week_total' => 'Week totaal',
'label.day_total' => 'Dag totaal',
+// 'label.month_total' => 'Month total',
+// 'label.month_left' => 'Time until quota is met',
+// 'label.month_over' => 'Over monthly quota',
'label.today' => 'Vandaag',
'label.total_hours' => 'Uren totaal',
'label.total_cost' => 'Totale kosten',
'label.fav_report' => 'Standaard rapport',
'label.cron_schedule' => 'Cron schema',
'label.what_is_it' => 'Wat betekent dit?',
+// 'label.year' => 'Year',
+// 'label.month' => 'Month',
+// 'label.quota' => 'Quota',
// Form titles.
'title.login' => 'Aanmelden',
'title.add_notification' => 'Notificatie toevoegen',
'title.edit_notification' => 'Notificatie bewerken',
'title.delete_notification' => 'Notificatie verwijderen',
+// 'title.monthly_quota' => 'Monthly quota',
'title.export' => 'Exporteer teamgegevens',
'title.import' => 'Importeer teamgegevens',
'title.options' => 'Opties',
'label.cost' => 'Koszt',
'label.week_total' => 'W tym tygodniu',
'label.day_total' => 'Dziś',
+// 'label.month_total' => 'Month total',
+// 'label.month_left' => 'Time until quota is met',
+// 'label.month_over' => 'Over monthly quota',
'label.today' => 'Dziś',
'label.total_hours' => 'Całkowita liczba godzin',
'label.total_cost' => 'Koszt całkowity',
'label.fav_report' => 'Ulubiony raport',
'label.cron_schedule' => 'Harmonogram crona',
'label.what_is_it' => 'Co to jest?',
+// 'label.year' => 'Year',
+// 'label.month' => 'Month',
+// 'label.quota' => 'Quota',
// Form titles.
'title.login' => 'Logowanie',
'title.add_notification' => 'Dodawanie powiadomienia',
'title.edit_notification' => 'Edytowanie powiadomienia',
'title.delete_notification' => 'Usuwanie powiadomienia',
+// 'title.monthly_quota' => 'Monthly quota',
'title.export' => 'Eksport danych zespołu',
'title.import' => 'Import danych zespołu',
'title.options' => 'Opcje',
'label.cost' => 'Custo',
'label.week_total' => 'Total semanal',
'label.day_total' => 'Total diário',
+// 'label.month_total' => 'Month total',
+// 'label.month_left' => 'Time until quota is met',
+// 'label.month_over' => 'Over monthly quota',
'label.today' => 'Hoje',
'label.total_hours' => 'Total de horas',
'label.total_cost' => 'Custo total',
'label.fav_report' => 'Relatório favorito',
'label.cron_schedule' => 'Agenda cron',
'label.what_is_it' => 'O que é?',
+// 'label.year' => 'Year',
+// 'label.month' => 'Month',
+// 'label.quota' => 'Quota',
// Form titles.
'title.login' => 'Login',
'title.add_notification' => 'Adicionando notificação',
'title.edit_notification' => 'Editando notificação',
'title.delete_notification' => 'Apagando notificação',
+// 'title.monthly_quota' => 'Monthly quota',
'title.export' => 'Exportando dados de equipe',
'title.import' => 'Importando dados de equipe',
'title.options' => 'Opções',
'label.cost' => 'Стоимость',
'label.week_total' => 'Итог за неделю',
'label.day_total' => 'Итог за день',
+// 'label.month_total' => 'Month total',
+// 'label.month_left' => 'Time until quota is met',
+// 'label.month_over' => 'Over monthly quota',
'label.today' => 'Сегодня',
'label.total_hours' => 'Итого часов',
'label.total_cost' => 'Итоговая стоимость',
'label.fav_report' => 'Стандартный отчёт',
'label.cron_schedule' => 'Расписание cron',
'label.what_is_it' => 'Что это?',
+// 'label.year' => 'Year',
+// 'label.month' => 'Month',
+// 'label.quota' => 'Quota',
// Form titles.
'title.login' => 'Вход в систему',
'title.add_notification' => 'Добавление уведомления',
'title.edit_notification' => 'Редактирование уведомления',
'title.delete_notification' => 'Удаление уведомления',
+// 'title.monthly_quota' => 'Monthly quota',
'title.export' => 'Экспортирование данных команды',
'title.import' => 'Импортирование данных команды',
'title.options' => 'Опции',
'label.week_total' => 'Týždeň celkom',
// TODO: translate the following string.
// 'label.day_total' => 'Day total',
+// 'label.month_total' => 'Month total',
+// 'label.month_left' => 'Time until quota is met',
+// 'label.month_over' => 'Over monthly quota',
'label.today' => 'Dnes',
'label.total_hours' => 'Hodín celkom',
'label.total_cost' => 'Náklady celkom',
// TODO: translate the following strings.
// 'label.cron_schedule' => 'Cron schedule',
// 'label.what_is_it' => 'What is it?',
+// 'label.year' => 'Year',
+// 'label.month' => 'Month',
+// 'label.quota' => 'Quota',
// Form titles.
'title.login' => 'Prihlásenie',
// 'title.add_notification' => 'Adding Notification',
// 'title.edit_notification' => 'Editing Notification',
// 'title.delete_notification' => 'Deleting Notification',
+// 'title.monthly_quota' => 'Monthly quota',
'title.export' => 'Exportovanie údajov o tíme',
'title.import' => 'Importovanie údajov o tíme',
'title.options' => 'Nastavenia',
'label.cost' => 'Cena',
'label.week_total' => 'Zbir časova nedeljno',
'label.day_total' => 'Zbir časova dnevno',
+// 'label.month_total' => 'Month total',
+// 'label.month_left' => 'Time until quota is met',
+// 'label.month_over' => 'Over monthly quota',
'label.today' => 'Danas',
'label.total_hours' => 'Ukupno časova',
'label.total_cost' => 'Ukupna cena',
'label.fav_report' => 'Omiljeni izveštaji',
'label.cron_schedule' => 'Sredi raspored',
'label.what_is_it' => 'Šta je ovo?',
+// 'label.year' => 'Year',
+// 'label.month' => 'Month',
+// 'label.quota' => 'Quota',
// Form titles.
'title.login' => 'Prijava',
'title.add_notification' => 'Dodavanje napomene',
'title.edit_notification' => 'Izmena napomene',
'title.delete_notification' => 'Brisanje napomene',
+// 'title.monthly_quota' => 'Monthly quota',
'title.export' => 'Izvoz podataka tim-a',
'title.import' => 'Uvoz podataka tim-a',
'title.options' => 'Opcije',
--- /dev/null
+{$forms.monthlyQuotaForm.open}
+<table>
+ <tr>
+ <td>{$i18n.label.year}</td>
+ <td>{$forms.monthlyQuotaForm.years.control}</td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <table>
+ <tr>
+ <td class="tableHeader">{$i18n.label.month}</td>
+ <td class="tableHeader">{$i18n.label.quota}</td>
+ </tr>
+ {foreach $months as $month}
+ <tr>
+ <td>{$month}</td>
+ <td>{$forms.monthlyQuotaForm.$month.control}</td>
+ </tr>
+ {/foreach}
+ <tr>
+ <td colspan="2" style="text-align:center;">
+ <input type="submit" value="{$i18n.button.save}">
+ </td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</table>
+{$forms.monthlyQuotaForm.close}
+<script>
+function yearChange(value){
+ var url = window.location.href;
+
+ if (url.indexOf('?') > 0){
+ var parameter = url.substring(url.indexOf('?') + 1, url.length);
+ url = url.replace(parameter, 'year=' + value);
+ } else {
+ url = '?year=' + value;
+ }
+
+ window.location = url;
+}
+</script>
\ No newline at end of file
} else {
configureLabel.style.visibility = "hidden";
}
+
+ var monthlyQuotaCheckBox = document.getElementById("monthly_quota");
+ configureLabel = document.getElementById("monthly_quota_config");
+ if (monthlyQuotaCheckBox.checked){
+ configureLabel.style.visibility = "visible";
+ } else {
+ configureLabel.style.visibility = "hidden";
+ }
+
}
</script>
</tr>
<tr>
<td align="right" nowrap>{$forms.profileForm.locking.control}</td>
- <td><label for="notifications">{$i18n.title.locking}</label> <span id="locking_config"><a href="locking.php">{$i18n.label.configure}</a></span></td>
+ <td><label for="locking">{$i18n.title.locking}</label> <span id="locking_config"><a href="locking.php">{$i18n.label.configure}</a></span></td>
+ </tr>
+ <tr>
+ <td align="right" nowrap>{$forms.profileForm.monthly_quota.control}</td>
+ <td><label for="monthly_quota">{$i18n.title.monthly_quota}</label> <span id="monthly_quota_config"><a href="cf_monthly_quota.php">{$i18n.label.configure}</a></span></td>
</tr>
{/if}
<td align="left">{$i18n.label.week_total}: {$week_total}</td>
<td align="right">{$i18n.label.day_total}: {$day_total}</td>
</tr>
+ {if $month_total}
+ <tr>
+ <td align="left">{$i18n.label.month_total}: {$month_total}</td>
+ {if $month_left|strpos:'-' === 0}
+ <td align="right">{$i18n.label.month_over}: <span style="color: green;">{$month_left|substr:1}</span></td>
+ {else}
+ <td align="right">{$i18n.label.month_left}: <span style="color: red;">{$month_left}</span></td>
+ {/if}
+ </tr>
+ {/if}
</table>
{/if}
{$forms.timeRecordForm.close}
--- /dev/null
+<?php
+
+require_once('initialize.php');
+require_once('plugins/MonthlyQuota.class.php');
+import('form.Form');
+
+// Access check.
+if (!ttAccessCheck(right_manage_team)) {
+ header('Location: access_denied.php');
+ exit();
+}
+
+$form = new Form('monthlyQuotaForm');
+// months are zero indexed
+$months = $i18n->monthNames;
+$years = array();
+for ($i=1990; $i < 2040; $i++) {
+ array_push($years, array('id'=>$i, 'name'=>$i));
+}
+
+$year = $request->getParameter("year");
+if (!$year or !ttValidInteger($year)){
+ $year = date("Y");
+}else {
+ $year = intval($year);
+}
+
+$quota = new MonthlyQuota();
+
+if ($request->isPost()){
+ $postedYear = $request->getParameter("years");
+ $year = intval($postedYear);
+ for ($i=0; $i < count($months); $i++){
+ $quota->update($postedYear, $i+1, $request->getParameter($months[$i]));
+ }
+}
+
+// returns months where January is month 1, not 0
+$monthsData = $quota->get($year);
+
+$form->addInput(array('type'=>'combobox', 'name'=>'years', 'data'=>$years, 'datakeys'=>array('id', 'name'), 'value'=>$year, 'onchange'=>'yearChange(this.value);'));
+for ($i=0; $i < count($months); $i++) {
+ $value = "";
+ if (array_key_exists($i+1, $monthsData)){
+ $value = $monthsData[$i+1];
+ }
+ $name = $months[$i];
+ $form->addInput(array('type'=>'text', 'name'=>$name, 'maxlength'=>3, 'value'=> $value, 'style'=>'width:50px'));
+}
+$smarty->assign('months', $months);
+$smarty->assign('forms', array($form->getName()=>$form->toArray()));
+$smarty->assign('content_page_name', 'cf_monthly_quota.tpl');
+$smarty->display('index.tpl');
setChange("ALTER TABLE tt_teams ADD COLUMN lock_spec varchar(255) default NULL");
setChange("ALTER TABLE tt_teams DROP locktime");
}
+
+ if ($_POST["convert1900to1930"]){
+ setChange("CREATE TABLE `timetracker`.`tt_monthly_quota` ( `year` SMALLINT UNSIGNED NOT NULL , `month` TINYINT UNSIGNED NOT NULL , `quota` SMALLINT UNSIGNED NOT NULL , PRIMARY KEY (`year`, `month`))");
+ }
// The update_clients function updates projects field in tt_clients table.
if ($_POST["update_clients"]) {
<h2>DB Install</h2>
<table width="80%" border="1" cellpadding="10" cellspacing="0">
<tr>
- <td width="80%"><b>Create database structure (v1.9)</b>
+ <td width="80%"><b>Create database structure (v1.9.30)</b>
<br>(applies only to new installations, do not execute when updating)</br></td><td><input type="submit" name="crstructure" value="Create"></td>
</tr>
</table>
<td>Update database structure (v1.6 to v1.9)</td>
<td><input type="submit" name="convert1600to1900" value="Update"><br></td>
</tr>
+ <tr valign="top">
+ <td>Update database structure (v1.9 to v1.9.30)</td>
+ <td><input type="submit" name="convert1900to1930" value="Update"><br></td>
+ </tr>
</table>
<h2>DB Maintenance</h2>
create index client_idx on tt_expense_items(client_id);
create index project_idx on tt_expense_items(project_id);
create index invoice_idx on tt_expense_items(invoice_id);
+
+#
+# Structure for table tt_monthly_quota.
+# This table lists expense items.
+#
+
+CREATE TABLE `tt_monthly_quota` (
+ `year` SMALLINT UNSIGNED NOT NULL , # year we'setting monthly quota for
+ `month` TINYINT UNSIGNED NOT NULL , # month we're settng monthly quota for
+ `quota` SMALLINT UNSIGNED NOT NULL , # the monthly quota
+ PRIMARY KEY (`year`, `month`)
+);
--- /dev/null
+<?php
+
+class MonthlyQuota {
+
+ var $db;
+ var $holidays;
+ // Old style constructors are DEPRECATED in PHP 7.0, and will be removed in a future version. You should always use __construct() in new code.
+ function __construct() {
+ $this->db = getConnection();
+ $i18n = $GLOBALS['I18N'];
+ $this->holidays = $i18n->holidays;
+ }
+
+ public function update($year, $month, $quota) {
+ $deleteSql = "DELETE FROM tt_monthly_quota WHERE year = $year AND month = $month";
+ $this->db->exec($deleteSql);
+ $insertSql = "INSERT INTO tt_monthly_quota (year, month, quota) values ($year, $month, $quota)";
+ $affected = $this->db->exec($insertSql);
+ return (!is_a($affected, 'PEAR_Error'));
+ }
+
+ public function get($year, $month) {
+
+ if (is_null($month)){
+ return $this->getMany($year);
+ }
+
+ return $this->getSingle($year, $month);
+ }
+
+ private function getSingle($year, $month) {
+
+ $sql = "SELECT quota FROM tt_monthly_quota WHERE year = $year AND month = $month";
+ $reader = $this->db->query($sql);
+ if (is_a($reader, 'PEAR_Error')) {
+ return false;
+ }
+
+ $row = $reader->fetchRow();
+
+ // if we don't find a record, return calculated monthly quota
+ if (is_null($row)){
+
+ $holidaysWithYear = array();
+ foreach ($this->holidays as $day) {
+ $parts = explode("/", $day);
+ $holiday = "$year-$parts[0]-$parts[1]";
+ array_push($holidaysWithYear, $holiday);
+ }
+
+ $daysInMonth = cal_days_in_month(CAL_GREGORIAN, $month, $year);
+ return $this->getWorkingDays("$year-$month-01", "$year-$month-$daysInMonth", $holidaysWithYear) * 8;
+ }
+
+ return $row["quota"];
+ }
+
+ private function getMany($year){
+ $sql = "SELECT year, month, quota FROM tt_monthly_quota WHERE year = $year";
+ $result = array();
+ $res = $this->db->query($sql);
+ if (is_a($res, 'PEAR_Error')) {
+ return false;
+ }
+
+ while ($val = $res->fetchRow()) {
+ $result[$val["month"]] = $val["quota"];
+ // $result[] = $val;
+ }
+
+ return $result;
+ }
+
+ //The function returns the no. of business days between two dates and it skips the holidays
+ private function getWorkingDays($startDate, $endDate, $holidays) {
+ // do strtotime calculations just once
+ $endDate = strtotime($endDate);
+ $startDate = strtotime($startDate);
+
+ //The total number of days between the two dates. We compute the no. of seconds and divide it to 60*60*24
+ //We add one to inlude both dates in the interval.
+ $days = ($endDate - $startDate) / 86400 + 1;
+
+ $noOfFullWeeks = floor($days / 7);
+ $noOfRemainingDays = fmod($days, 7);
+
+ //It will return 1 if it's Monday,.. ,7 for Sunday
+ $firstDayofWeek = date("N", $startDate);
+ $lastDayofWeek = date("N", $endDate);
+
+ //---->The two can be equal in leap years when february has 29 days, the equal sign is added here
+ //In the first case the whole interval is within a week, in the second case the interval falls in two weeks.
+ if ($firstDayofWeek <= $lastDayofWeek) {
+ if ($firstDayofWeek <= 6 && 6 <= $lastDayofWeek) {
+ $noOfRemainingDays--;
+ }
+
+ if ($firstDayofWeek <= 7 && 7 <= $lastDayofWeek) {
+ $noOfRemainingDays--;
+ }
+ }
+ else {
+ // (edit by Tokes to fix an edge case where the start day was a Sunday
+ // and the end day was NOT a Saturday)
+
+ // the day of the week for start is later than the day of the week for end
+ if ($firstDayofWeek == 7) {
+ // if the start date is a Sunday, then we definitely subtract 1 day
+ $noOfRemainingDays--;
+
+ if ($lastDayofWeek == 6) {
+ // if the end date is a Saturday, then we subtract another day
+ $noOfRemainingDays--;
+ }
+ }
+ else {
+ // the start date was a Saturday (or earlier), and the end date was (Mon..Fri)
+ // so we skip an entire weekend and subtract 2 days
+ $noOfRemainingDays -= 2;
+ }
+ }
+
+ //T he no. of business days is: (number of weeks between the two dates) * (5 working days) + the remainder
+ // ---->february in none leap years gave a remainder of 0 but still calculated weekends between first and last day, this is one way to fix it
+ $workingDays = $noOfFullWeeks * 5;
+ if ($noOfRemainingDays > 0 ) {
+ $workingDays += $noOfRemainingDays;
+ }
+
+ // We subtract the holidays
+ foreach($holidays as $holiday){
+ $timeStamp = strtotime($holiday);
+ // If the holiday doesn't fall in weekend
+ // TODO: add handling for countries where they move non working day to first working day if holiday is on weekends
+ if ($startDate <= $timeStamp && $timeStamp <= $endDate && date("N", $timeStamp) != 6 && date("N", $timeStamp ) != 7)
+ $workingDays--;
+ }
+
+ return $workingDays;
+ }
+}
\ No newline at end of file
$cl_tax_expenses = $request->getParameter('tax_expenses');
$cl_notifications = $request->getParameter('notifications');
$cl_locking = $request->getParameter('locking');
+ $cl_monthly_quota = $request->getParameter('monthly_quota');
}
} else {
$cl_name = $user->name;
$cl_clients = in_array('cl', $plugins);
$cl_client_required = in_array('cm', $plugins);
$cl_invoices = in_array('iv', $plugins);
- $cl_custom_fields = in_array('cf', $plugins);
+ $cl_custom_fields = in_array('cf', $plugins);
$cl_expenses = in_array('ex', $plugins);
$cl_tax_expenses = in_array('et', $plugins);
$cl_notifications = in_array('no', $plugins);
$cl_locking = in_array('lk', $plugins);
+ $cl_monthly_quota = in_array('mq', $plugins);
}
}
$form->addInput(array('type'=>'checkbox','name'=>'tax_expenses','data'=>1,'value'=>$cl_tax_expenses));
$form->addInput(array('type'=>'checkbox','name'=>'notifications','data'=>1,'value'=>$cl_notifications,'onchange'=>'handlePluginCheckboxes()'));
$form->addInput(array('type'=>'checkbox','name'=>'locking','data'=>1,'value'=>$cl_locking,'onchange'=>'handlePluginCheckboxes()'));
+ $form->addInput(array('type'=>'checkbox','name'=>'monthly_quota','data'=>1,'value'=>$cl_monthly_quota,'onchange'=>'handlePluginCheckboxes()'));
}
$form->addInput(array('type'=>'submit','name'=>'btn_save','value'=>$i18n->getKey('button.save')));
$plugins .= ',no';
if ($cl_locking)
$plugins .= ',lk';
+ if ($cl_monthly_quota)
+ $plugins .= ',mq';
$plugins = trim($plugins, ',');
$update_result = ttTeamHelper::update($user->team_id, array(
$smarty->assign('custom_fields', $custom_fields);
}
+if ($user->isPluginEnabled('mq')){
+ require_once('plugins/MonthlyQuota.class.php');
+ $quota = new MonthlyQuota();
+ $monthlyQuota = $quota->get($selected_date->mYear, $selected_date->mMonth);
+ $month_total = ttTimeHelper::getTimeForMonth($user->getActiveUser(), $selected_date);
+ $minutesLeft = ttTimeHelper::toMinutes($monthlyQuota) - ttTimeHelper::toMinutes($month_total);
+
+ $smarty->assign('month_total', $month_total);
+ $smarty->assign('month_left', ttTimeHelper::fromMinutes($minutesLeft));
+}
+
// Initialize variables.
$cl_start = trim($request->getParameter('start'));
$cl_finish = trim($request->getParameter('finish'));