2 // +----------------------------------------------------------------------+
3 // | Anuko Time Tracker
4 // +----------------------------------------------------------------------+
5 // | Copyright (c) Anuko International Ltd. (https://www.anuko.com)
6 // +----------------------------------------------------------------------+
7 // | LIBERAL FREEWARE LICENSE: This source code document may be used
8 // | by anyone for any purpose, and freely redistributed alone or in
9 // | combination with other software, provided that the license is obeyed.
11 // | There are only two ways to violate the license:
13 // | 1. To redistribute this code in source form, with the copyright
14 // | notice or license removed or altered. (Distributing in compiled
15 // | forms without embedded copyright notices is permitted).
17 // | 2. To redistribute modified versions of this code in *any* form
18 // | that bears insufficient indications that the modifications are
19 // | not the work of the original author(s).
21 // | This license applies to this document only, not any other software
22 // | that it may be combined with.
24 // +----------------------------------------------------------------------+
26 // | https://www.anuko.com/time_tracker/credits.htm
27 // +----------------------------------------------------------------------+
29 import('ttTimeHelper');
31 // MontlyQuota class implements handling of work hour quotas.
34 var $db; // Database connection.
35 var $group_id; // Group id.
36 var $org_id; // Organization id.
38 function __construct() {
39 $this->db = getConnection();
41 $this->group_id = $user->getGroup();
42 $this->org_id = $user->org_id;
45 // update - deletes a quota, then inserts a new one.
46 public function update($year, $month, $minutes) {
47 $deleteSql = "delete from tt_monthly_quotas".
48 " where year = $year and month = $month and group_id = $this->group_id and org_id = $this->org_id";
49 $this->db->exec($deleteSql);
51 $insertSql = "insert into tt_monthly_quotas (group_id, org_id, year, month, minutes)".
52 " values ($this->group_id, $this->org_id, $year, $month, $minutes)";
53 $affected = $this->db->exec($insertSql);
54 return (!is_a($affected, 'PEAR_Error'));
59 // get - obtains either a single month quota or an array of quotas for an entire year.
60 // Month starts with 1 for January, not 0.
61 public function get($year, $month = null) {
63 return $this->getMany($year);
65 return $this->getSingle($year, $month);
68 // getSingle - obtains a quota for a single month.
69 private function getSingle($year, $month) {
70 $sql = "select minutes from tt_monthly_quotas".
71 " where year = $year and month = $month and group_id = $this->group_id and org_id = $this->org_id";
72 $reader = $this->db->query($sql);
73 if (is_a($reader, 'PEAR_Error')) {
77 $row = $reader->fetchRow();
79 return $row['minutes'];
81 // If we did not find a record, return a calculated monthly quota.
82 $numWorkdays = $this->getNumWorkdays($month, $year);
84 return $numWorkdays * $user->getWorkdayMinutes();
87 // getUserQuota - obtains a quota for user for a single month.
88 // This quota is adjusted by quota_percent value for user.
89 public function getUserQuota($year, $month) {
92 $minutes = $this->getSingle($year, $month);
93 $userMinutes = (int) $minutes * $user->getQuotaPercent() / 100;
97 // getMany - returns an array of quotas for a given year for group.
98 private function getMany($year){
99 $sql = "select month, minutes from tt_monthly_quotas".
100 " where year = $year and group_id = $this->group_id and org_id = $this->org_id";
102 $res = $this->db->query($sql);
103 if (is_a($res, 'PEAR_Error')) {
107 while ($val = $res->fetchRow()) {
108 $result[$val['month']] = $val['minutes'];
114 // getNumWorkdays returns a number of work days in a given month.
115 private function getNumWorkdays($month, $year) {
117 $daysInMonth = cal_days_in_month(CAL_GREGORIAN, $month, $year); // Number of calendar days in month.
119 $workdaysInMonth = 0;
120 // Iterate through the entire month.
121 for ($i = 1; $i <= $daysInMonth; $i++) {
122 $date = "$year-$month-$i";
123 if (!ttTimeHelper::isWeekend($date) && !ttTimeHelper::isHoliday($date)) {
127 return $workdaysInMonth;
130 // isValidQuota validates a localized value as an hours quota string (in hours and minutes).
131 public function isValidQuota($value) {
133 if (strlen($value) == 0 || !isset($value)) return true;
135 if (preg_match('/^[0-9]{1,3}h?$/', $value )) { // 000 - 999
139 if (preg_match('/^[0-9]{1,3}:[0-5][0-9]$/', $value )) { // 000:00 - 999:59
144 $localizedPattern = '/^([0-9]{1,3})?['.$user->getDecimalMark().'][0-9]{1,4}h?$/';
145 if (preg_match($localizedPattern, $value )) { // decimal values like 000.5, 999.25h, ... .. 999.9999h (or with comma)
152 // quotaToFloat converts a valid quota value to a float.
153 public function quotaToFloat($value) {
155 if (preg_match('/^[0-9]{1,3}h?$/', $value )) { // 000 - 999
156 return (float) $value;
159 if (preg_match('/^[0-9]{1,3}:[0-5][0-9]$/', $value )) { // 000:00 - 999:59
160 $minutes = ttTimeHelper::toMinutes($value);
161 return ($minutes / 60.0);
165 $localizedPattern = '/^([0-9]{1,3})?['.$user->getDecimalMark().'][0-9]{1,4}h?$/';
166 if (preg_match($localizedPattern, $value )) { // decimal values like 000.5, 999.25h, ... .. 999.9999h (or with comma)
167 // Strip optional h in the end.
168 $value = trim($value, 'h');
169 if ($user->getDecimalMark() == ',')
170 $value = str_replace(',', '.', $value);
171 return (float) $value;