A bit of cleanup.
[timetracker.git] / plugins / MonthlyQuota.class.php
1 <?php
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.
10 // |
11 // | There are only two ways to violate the license:
12 // |
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).
16 // |
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).
20 // |
21 // | This license applies to this document only, not any other software
22 // | that it may be combined with.
23 // |
24 // +----------------------------------------------------------------------+
25 // | Contributors:
26 // | https://www.anuko.com/time_tracker/credits.htm
27 // +----------------------------------------------------------------------+
28
29 import('ttTimeHelper');
30
31 // MontlyQuota class implements handling of work hour quotas.
32 class MonthlyQuota {
33
34   var $db;       // Database connection.
35   var $group_id; // Group id.
36
37   function __construct() {
38     $this->db = getConnection();
39     global $user;
40     $this->group_id = $user->group_id;
41   }
42
43   // update - deletes a quota, then inserts a new one.
44   public function update($year, $month, $minutes) {
45     $group_id = $this->group_id;
46     $deleteSql = "DELETE FROM tt_monthly_quotas WHERE year = $year AND month = $month AND group_id = $group_id";
47     $this->db->exec($deleteSql);
48     if ($minutes){
49       $insertSql = "INSERT INTO tt_monthly_quotas (group_id, year, month, minutes) values ($group_id, $year, $month, $minutes)";
50       $affected = $this->db->exec($insertSql);
51       return (!is_a($affected, 'PEAR_Error'));
52     }
53     return true;
54   }
55
56   // get - obtains either a single month quota or an array of quotas for an entire year.
57   // Month starts with 1 for January, not 0.
58   public function get($year, $month = null) {
59     if (is_null($month)){
60       return $this->getMany($year);
61     }
62     return $this->getSingle($year, $month);
63   }
64
65   // getSingle - obtains a quota for a single month.
66   private function getSingle($year, $month) {
67     $group_id = $this->group_id;
68     $sql = "SELECT minutes FROM tt_monthly_quotas WHERE year = $year AND month = $month AND group_id = $group_id";
69     $reader = $this->db->query($sql);
70     if (is_a($reader, 'PEAR_Error')) {
71       return false;
72     }
73
74     $row = $reader->fetchRow();
75     if ($row)
76       return $row['minutes'];
77
78     // If we did not find a record, return a calculated monthly quota.
79     $numWorkdays = $this->getNumWorkdays($month, $year);
80     global $user;
81     return $numWorkdays * $user->workday_minutes;
82   }
83
84   // getMany - returns an array of quotas for a given year for group.
85   private function getMany($year){
86     $group_id = $this->group_id;
87     $sql = "SELECT month, minutes FROM tt_monthly_quotas WHERE year = $year AND group_id = $group_id";
88     $result = array();
89     $res = $this->db->query($sql);
90     if (is_a($res, 'PEAR_Error')) {
91       return false;
92     }
93
94     while ($val = $res->fetchRow()) {
95       $result[$val['month']] = $val['minutes'];
96     }
97
98     return $result;
99   }
100
101   // getNumWorkdays returns a number of work days in a given month.
102   private function getNumWorkdays($month, $year) {
103
104     $daysInMonth = cal_days_in_month(CAL_GREGORIAN, $month, $year); // Number of calendar days in month.
105
106     $workdaysInMonth = 0;
107     // Iterate through the entire month.
108     for ($i = 1; $i <= $daysInMonth; $i++) {
109       $date = "$year-$month-$i";
110       if (!ttTimeHelper::isWeekend($date) && !ttTimeHelper::isHoliday($date)) {
111         $workdaysInMonth++;
112       }
113     }
114     return $workdaysInMonth;
115   }
116
117   // isValidQuota validates a localized value as an hours quota string (in hours and minutes).
118   public function isValidQuota($value) {
119
120     if (strlen($value) == 0 || !isset($value)) return true;
121
122     if (preg_match('/^[0-9]{1,3}h?$/', $value )) { // 000 - 999
123       return true;
124     }
125
126     if (preg_match('/^[0-9]{1,3}:[0-5][0-9]$/', $value )) { // 000:00 - 999:59
127       return true;
128     }
129
130     global $user;
131     $localizedPattern = '/^([0-9]{1,3})?['.$user->decimal_mark.'][0-9]{1,4}h?$/';
132     if (preg_match($localizedPattern, $value )) { // decimal values like 000.5, 999.25h, ... .. 999.9999h (or with comma)
133       return true;
134     }
135
136     return false;
137   }
138
139   // quotaToFloat converts a valid quota value to a float.
140   public function quotaToFloat($value) {
141
142     if (preg_match('/^[0-9]{1,3}h?$/', $value )) { // 000 - 999
143       return (float) $value;
144     }
145
146     if (preg_match('/^[0-9]{1,3}:[0-5][0-9]$/', $value )) { // 000:00 - 999:59
147       $minutes = ttTimeHelper::toMinutes($value);
148       return ($minutes / 60.0);
149     }
150
151     global $user;
152     $localizedPattern = '/^([0-9]{1,3})?['.$user->decimal_mark.'][0-9]{1,4}h?$/';
153     if (preg_match($localizedPattern, $value )) { // decimal values like 000.5, 999.25h, ... .. 999.9999h (or with comma)
154       // Strip optional h in the end.
155       $value = trim($value, 'h');
156       if ($user->decimal_mark == ',')
157         $value = str_replace(',', '.', $value);
158       return (float) $value;
159     }
160
161     return null;
162   }
163 }