Fixed fav reports to include paid status.
[timetracker.git] / WEB-INF / lib / ttTeamHelper.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('ttUserHelper');
30 import('DateAndTime');
31
32 // Class ttTeamHelper - contains helper functions that operate with teams.
33 class ttTeamHelper {
34
35   // The getUserCount function returns number of people in team.
36   static function getUserCount($team_id) {
37     $mdb2 = getConnection();
38
39     $sql = "select count(id) as cnt from tt_users where team_id = $team_id and status = 1";
40     $res = $mdb2->query($sql);
41
42     if (!is_a($res, 'PEAR_Error')) {
43       $val = $res->fetchRow();
44       return $val['cnt'];
45     }
46     return false;
47   }
48
49   // The getUsersForClient obtains all active and inactive users in a team that are relevant to a client.
50   static function getUsersForClient() {
51     global $user;
52     $mdb2 = getConnection();
53
54     $sql = "select u.id, u.name from tt_user_project_binds upb
55       inner join tt_client_project_binds cpb on (upb.project_id = cpb.project_id and cpb.client_id = $user->client_id)
56       inner join tt_users u on (u.id = upb.user_id)
57       where (u.status = 1 or u.status = 0)
58       group by u.id
59       order by upper(u.name)";
60     $res = $mdb2->query($sql);
61     $user_list = array();
62     if (is_a($res, 'PEAR_Error'))
63       return false;
64     while ($val = $res->fetchRow()) {
65       $user_list[] = $val;
66     }
67     return $user_list;
68   }
69
70   // The getActiveUsers obtains all active users in a given team.
71   static function getActiveUsers($options = null) {
72     global $user;
73     $mdb2 = getConnection();
74
75     if (isset($options['getAllFields']))
76       $sql = "select * from tt_users where team_id = $user->team_id and status = 1 order by upper(name)";
77     else
78       $sql = "select id, name from tt_users where team_id = $user->team_id and status = 1 order by upper(name)";
79     $res = $mdb2->query($sql);
80     $user_list = array();
81     if (is_a($res, 'PEAR_Error'))
82       return false;
83     while ($val = $res->fetchRow()) {
84       $user_list[] = $val;
85     }
86
87     if (isset($options['putSelfFirst'])) {
88       // Put own entry at the front.
89       $cnt = count($user_list);
90       for($i = 0; $i < $cnt; $i++) {
91         if ($user_list[$i]['id'] == $user->id) {
92           $self = $user_list[$i]; // Found self.
93           array_unshift($user_list, $self); // Put own entry at the front.
94           array_splice($user_list, $i+1, 1); // Remove duplicate.
95         }
96       }
97     }
98     return $user_list;
99   }
100
101   // The getUsers obtains all active and inactive (but not deleted) users in a given team.
102   static function getUsers() {
103     global $user;
104     $mdb2 = getConnection();
105
106     $sql = "select id, name from tt_users where team_id = $user->team_id and (status = 1 or status = 0) order by upper(name)";
107     $res = $mdb2->query($sql);
108     $user_list = array();
109     if (is_a($res, 'PEAR_Error'))
110       return false;
111     while ($val = $res->fetchRow()) {
112       $user_list[] = $val;
113     }
114
115     return $user_list;
116   }
117
118   // The getInactiveUsers obtains all inactive users in a given team.
119   static function getInactiveUsers($team_id, $all_fields = false) {
120     $mdb2 = getConnection();
121
122     if ($all_fields)
123       $sql = "select * from tt_users where team_id = $team_id and status = 0 order by upper(name)";
124     else
125       $sql = "select id, name from tt_users where team_id = $team_id and status = 0 order by upper(name)";
126     $res = $mdb2->query($sql);
127     $result = array();
128     if (!is_a($res, 'PEAR_Error')) {
129       while ($val = $res->fetchRow()) {
130         $result[] = $val;
131       }
132       return $result;
133     }
134     return false;
135   }
136
137   // The getAllUsers obtains all users in a given team.
138   static function getAllUsers($team_id, $all_fields = false) {
139     $mdb2 = getConnection();
140
141     if ($all_fields)
142       $sql = "select * from tt_users where team_id = $team_id order by upper(name)";
143     else
144       $sql = "select id, name from tt_users where team_id = $team_id order by upper(name)";
145     $res = $mdb2->query($sql);
146     $result = array();
147     if (!is_a($res, 'PEAR_Error')) {
148       while ($val = $res->fetchRow()) {
149         $result[] = $val;
150       }
151       return $result;
152     }
153     return false;
154   }
155
156   // getActiveProjects - returns an array of active projects for team.
157   static function getActiveProjects($team_id)
158   {
159     $result = array();
160     $mdb2 = getConnection();
161
162     $sql = "select id, name, description, tasks from tt_projects
163       where team_id = $team_id and status = 1 order by upper(name)";
164     $res = $mdb2->query($sql);
165     $result = array();
166     if (!is_a($res, 'PEAR_Error')) {
167       while ($val = $res->fetchRow()) {
168         $result[] = $val;
169       }
170     }
171     return $result;
172   }
173
174   // getInactiveProjects - returns an array of inactive projects for team.
175   static function getInactiveProjects($team_id)
176   {
177     $result = array();
178     $mdb2 = getConnection();
179
180     $sql = "select id, name, description, tasks from tt_projects
181       where team_id = $team_id and status = 0 order by upper(name)";
182     $res = $mdb2->query($sql);
183     $result = array();
184     if (!is_a($res, 'PEAR_Error')) {
185       while ($val = $res->fetchRow()) {
186         $result[] = $val;
187       }
188     }
189     return $result;
190   }
191
192   // The getAllProjects obtains all projects in a given team.
193   static function getAllProjects($team_id, $all_fields = false) {
194     $mdb2 = getConnection();
195
196     if ($all_fields)
197       $sql = "select * from tt_projects where team_id = $team_id order by status, upper(name)";
198     else
199       $sql = "select id, name from tt_projects where team_id = $team_id order by status, upper(name)";
200     $res = $mdb2->query($sql);
201     $result = array();
202     if (!is_a($res, 'PEAR_Error')) {
203       while ($val = $res->fetchRow()) {
204         $result[] = $val;
205       }
206       return $result;
207     }
208     return false;
209   }
210
211   // getActiveTasks - returns an array of active tasks for team.
212   static function getActiveTasks($team_id)
213   {
214     $result = array();
215     $mdb2 = getConnection();
216
217     $sql = "select id, name, description from tt_tasks where team_id = $team_id and status = 1 order by upper(name)";
218     $res = $mdb2->query($sql);
219     $result = array();
220     if (!is_a($res, 'PEAR_Error')) {
221       while ($val = $res->fetchRow()) {
222         $result[] = $val;
223       }
224     }
225     return $result;
226   }
227
228   // getInactiveTasks - returns an array of inactive tasks for team.
229   static function getInactiveTasks($team_id)
230   {
231     $result = array();
232     $mdb2 = getConnection();
233
234     $sql = "select id, name, description from tt_tasks
235       where team_id = $team_id and status = 0 order by upper(name)";
236     $res = $mdb2->query($sql);
237     $result = array();
238     if (!is_a($res, 'PEAR_Error')) {
239       while ($val = $res->fetchRow()) {
240         $result[] = $val;
241       }
242     }
243     return $result;
244   }
245
246   // The getAllTasks obtains all tasks in a given team.
247   static function getAllTasks($team_id, $all_fields = false) {
248     $mdb2 = getConnection();
249
250     if ($all_fields)
251       $sql = "select * from tt_tasks where team_id = $team_id order by status, upper(name)";
252     else
253       $sql = "select id, name from tt_tasks where team_id = $team_id order by status, upper(name)";
254     $res = $mdb2->query($sql);
255     $result = array();
256     if (!is_a($res, 'PEAR_Error')) {
257       while ($val = $res->fetchRow()) {
258         $result[] = $val;
259       }
260       return $result;
261     }
262     return false;
263   }
264
265   // The getActiveClients returns an array of active clients for team.
266   static function getActiveClients($team_id, $all_fields = false)
267   {
268     $result = array();
269     $mdb2 = getConnection();
270
271     if ($all_fields)
272       $sql = "select * from tt_clients where team_id = $team_id and status = 1 order by upper(name)";
273     else
274       $sql = "select id, name from tt_clients where team_id = $team_id and status = 1 order by upper(name)";
275
276     $res = $mdb2->query($sql);
277     $result = array();
278     if (!is_a($res, 'PEAR_Error')) {
279       while ($val = $res->fetchRow()) {
280         $result[] = $val;
281       }
282     }
283     return $result;
284   }
285
286   // The getInactiveClients returns an array of inactive clients for team.
287   static function getInactiveClients($team_id, $all_fields = false)
288   {
289     $result = array();
290     $mdb2 = getConnection();
291
292     if ($all_fields)
293       $sql = "select * from tt_clients where team_id = $team_id and status = 0 order by upper(name)";
294     else
295       $sql = "select id, name from tt_clients where team_id = $team_id and status = 0 order by upper(name)";
296
297     $res = $mdb2->query($sql);
298     $result = array();
299     if (!is_a($res, 'PEAR_Error')) {
300       while ($val = $res->fetchRow()) {
301         $result[] = $val;
302       }
303     }
304     return $result;
305   }
306
307   // The getAllClients obtains all clients in a given team.
308   static function getAllClients($team_id, $all_fields = false) {
309     $mdb2 = getConnection();
310
311     if ($all_fields)
312       $sql = "select * from tt_clients where team_id = $team_id order by status, upper(name)";
313     else
314       $sql = "select id, name from tt_clients where team_id = $team_id order by status, upper(name)";
315
316     $res = $mdb2->query($sql);
317     $result = array();
318     if (!is_a($res, 'PEAR_Error')) {
319       while ($val = $res->fetchRow()) {
320         $result[] = $val;
321       }
322       return $result;
323     }
324     return false;
325   }
326
327   // The getActiveInvoices returns an array of active invoices for team.
328   static function getActiveInvoices($localizeDates = true)
329   {
330     global $user;
331
332     $result = array();
333     $mdb2 = getConnection();
334
335     if (ROLE_CLIENT == $user->role && $user->client_id)
336       $client_part = " and i.client_id = $user->client_id";
337
338     $sql = "select i.id, i.name, i.date, i.client_id, i.status, c.name as client_name from tt_invoices i
339       left join tt_clients c on (c.id = i.client_id)
340       where i.status = 1 and i.team_id = $user->team_id $client_part order by i.name";
341     $res = $mdb2->query($sql);
342     $result = array();
343     if (!is_a($res, 'PEAR_Error')) {
344       $dt = new DateAndTime(DB_DATEFORMAT);
345       while ($val = $res->fetchRow()) {
346         if ($localizeDates) {
347           $dt->parseVal($val['date']);
348           $val['date'] = $dt->toString($user->date_format);
349         }
350         $result[] = $val;
351       }
352     }
353     return $result;
354   }
355
356   // The getAllInvoices returns an array of all invoices for team.
357   static function getAllInvoices()
358   {
359     global $user;
360
361     $result = array();
362     $mdb2 = getConnection();
363
364     $sql = "select * from tt_invoices where team_id = $user->team_id";
365     $res = $mdb2->query($sql);
366     $result = array();
367     if (!is_a($res, 'PEAR_Error')) {
368       $dt = new DateAndTime(DB_DATEFORMAT);
369       while ($val = $res->fetchRow()) {
370         $result[] = $val;
371       }
372     }
373     return $result;
374   }
375
376   // The getRecentInvoices returns an array of recent invoices (max 3) for a client.
377   static function getRecentInvoices($team_id, $client_id)
378   {
379     global $user;
380
381     $result = array();
382     $mdb2 = getConnection();
383
384     $sql = "select i.id, i.name from tt_invoices i
385       left join tt_clients c on (c.id = i.client_id)
386       where i.team_id = $team_id and i.status = 1 and c.id = $client_id
387       order by i.id desc limit 3";
388     $res = $mdb2->query($sql);
389     $result = array();
390     if (!is_a($res, 'PEAR_Error')) {
391       $dt = new DateAndTime(DB_DATEFORMAT);
392       while ($val = $res->fetchRow()) {
393         $result[] = $val;
394       }
395     }
396     return $result;
397   }
398
399   // getUserToProjectBinds - obtains all user to project binds for a team.
400   static function getUserToProjectBinds($team_id) {
401     $mdb2 = getConnection();
402
403     $result = array();
404     $sql = "select * from tt_user_project_binds where user_id in (select id from tt_users where team_id = $team_id) order by user_id, status, project_id";
405     $res = $mdb2->query($sql);
406     $result = array();
407     if (!is_a($res, 'PEAR_Error')) {
408       while ($val = $res->fetchRow()) {
409         $result[] = $val;
410       }
411       return $result;
412     }
413     return false;
414   }
415
416   // The getAllCustomFields obtains all custom fields in a given team.
417   static function getAllCustomFields($team_id) {
418     $mdb2 = getConnection();
419
420     $sql = "select * from tt_custom_fields where team_id = $team_id order by status";
421
422     $res = $mdb2->query($sql);
423     $result = array();
424     if (!is_a($res, 'PEAR_Error')) {
425       while ($val = $res->fetchRow()) {
426         $result[] = $val;
427       }
428       return $result;
429     }
430     return false;
431   }
432
433   // The getAllCustomFieldOptions obtains all custom field options in a given team.
434   static function getAllCustomFieldOptions($team_id) {
435     $mdb2 = getConnection();
436
437     $sql = "select * from tt_custom_field_options where field_id in (select id from tt_custom_fields where team_id = $team_id) order by id";
438
439     $res = $mdb2->query($sql);
440     $result = array();
441     if (!is_a($res, 'PEAR_Error')) {
442       while ($val = $res->fetchRow()) {
443         $result[] = $val;
444       }
445       return $result;
446     }
447     return false;
448   }
449
450   // The getCustomFieldLog obtains all custom field log entries for a given team.
451   static function getCustomFieldLog($team_id) {
452     $mdb2 = getConnection();
453
454     $sql = "select * from tt_custom_field_log where field_id in (select id from tt_custom_fields where team_id = $team_id) order by id";
455
456     $res = $mdb2->query($sql);
457     $result = array();
458     if (!is_a($res, 'PEAR_Error')) {
459       while ($val = $res->fetchRow()) {
460         $result[] = $val;
461       }
462       return $result;
463     }
464     return false;
465   }
466
467   // getFavReports - obtains all favorite reports for all users in team.
468   static function getFavReports($team_id) {
469     $mdb2 = getConnection();
470
471     $result = array();
472     $sql = "select * from tt_fav_reports where user_id in (select id from tt_users where team_id = $team_id)";
473     $res = $mdb2->query($sql);
474     $result = array();
475     if (!is_a($res, 'PEAR_Error')) {
476       while ($val = $res->fetchRow()) {
477         $result[] = $val;
478       }
479       return $result;
480     }
481     return false;
482   }
483
484   // getExpenseItems - obtains all expense items for all users in team.
485   static function getExpenseItems($team_id) {
486     $mdb2 = getConnection();
487
488     $result = array();
489     $sql = "select * from tt_expense_items where user_id in (select id from tt_users where team_id = $team_id)";
490     $res = $mdb2->query($sql);
491     $result = array();
492     if (!is_a($res, 'PEAR_Error')) {
493       while ($val = $res->fetchRow()) {
494         $result[] = $val;
495       }
496       return $result;
497     }
498     return false;
499   }
500
501   // getPredefinedExpenses - obtains predefined expenses for team.
502   static function getPredefinedExpenses($team_id) {
503     global $user;
504     $replaceDecimalMark = ('.' != $user->decimal_mark);
505
506     $mdb2 = getConnection();
507
508     $result = array();
509     $sql = "select id, name, cost from tt_predefined_expenses where team_id = $team_id";
510     $res = $mdb2->query($sql);
511     $result = array();
512     if (!is_a($res, 'PEAR_Error')) {
513       while ($val = $res->fetchRow()) {
514         if ($replaceDecimalMark)
515           $val['cost'] = str_replace('.', $user->decimal_mark, $val['cost']);
516         $result[] = $val;
517       }
518       return $result;
519     }
520     return false;
521   }
522
523   // getNotifications - obtains notification descriptions for team.
524   static function getNotifications($team_id) {
525     $mdb2 = getConnection();
526
527     $result = array();
528     $sql = "select c.id, c.cron_spec, c.email, c.report_condition, fr.name from tt_cron c
529       left join tt_fav_reports fr on (fr.id = c.report_id)
530       where c.team_id = $team_id and c.status = 1 and fr.status = 1";
531     $res = $mdb2->query($sql);
532     $result = array();
533     if (!is_a($res, 'PEAR_Error')) {
534       while ($val = $res->fetchRow()) {
535         $result[] = $val;
536       }
537       return $result;
538     }
539     return false;
540   }
541
542   // getMonthlyQuotas - obtains monthly quotas for team.
543   static function getMonthlyQuotas($team_id) {
544     $mdb2 = getConnection();
545
546     $result = array();
547     $sql = "select year, month, quota from tt_monthly_quotas where team_id = $team_id";
548     $res = $mdb2->query($sql);
549     $result = array();
550     if (!is_a($res, 'PEAR_Error')) {
551       while ($val = $res->fetchRow()) {
552         $result[] = $val;
553       }
554       return $result;
555     }
556     return false;
557   }
558
559   // The getTeams function returns an array of all active teams on the server.
560   static function getTeams() {
561     $result = array();
562     $mdb2 = getConnection();
563
564     $sql =  "select id, name, lang, timestamp from tt_teams where status = 1 order by id desc";
565     $res = $mdb2->query($sql);
566     $result = array();
567     if (!is_a($res, 'PEAR_Error')) {
568       while ($val = $res->fetchRow()) {
569         $val['date'] = substr($val['timestamp'], 0, 10); // Strip the time.
570         $result[] = $val;
571       }
572       return $result;
573     }
574     return false;
575   }
576
577   // The markDeleted function marks the team and everything in it as deleted.
578   static function markDeleted($team_id) {
579
580     // Iterate through team users and mark them as deleted.
581     $users = ttTeamHelper::getAllUsers($team_id);
582     foreach ($users as $one_user) {
583       if (!ttUserHelper::markDeleted($one_user['id'])) return false;
584     }
585
586     // Mark tasks deleted.
587     if (!ttTeamHelper::markTasksDeleted($team_id)) return false;
588
589     $mdb2 = getConnection();
590
591     // Mark projects deleted.
592     $sql = "update tt_projects set status = NULL where team_id = $team_id";
593     $affected = $mdb2->exec($sql);
594     if (is_a($affected, 'PEAR_Error')) return false;
595
596     // Mark clients deleted.
597     $sql = "update tt_clients set status = NULL where team_id = $team_id";
598     $affected = $mdb2->exec($sql);
599     if (is_a($affected, 'PEAR_Error')) return false;
600
601     // Mark custom fields deleted.
602     $sql = "update tt_custom_fields set status = NULL where team_id = $team_id";
603     $affected = $mdb2->exec($sql);
604     if (is_a($affected, 'PEAR_Error')) return false;
605
606     // Mark team deleted.
607     $sql = "update tt_teams set status = NULL where id = $team_id";
608     $affected = $mdb2->exec($sql);
609     if (is_a($affected, 'PEAR_Error')) return false;
610
611     return true;
612   }
613
614   // The getTeamDetails function returns team details.
615   static function getTeamDetails($team_id) {
616     $result = array();
617     $mdb2 = getConnection();
618
619     $role_manager = ROLE_MANAGER;
620     $sql = "select t.name as team_name, u.id as manager_id, u.name as manager_name, u.login as manager_login, u.email as manager_email
621       from tt_teams t
622       inner join tt_users u on (u.team_id = t.id and u.role = $role_manager)
623       where t.id = $team_id";
624
625     $res = $mdb2->query($sql);
626     if (!is_a($res, 'PEAR_Error')) {
627       $val = $res->fetchRow();
628       return $val;
629     }
630
631     return false;
632   }
633
634   // The insert function creates a new team.
635   static function insert($fields) {
636
637     $mdb2 = getConnection();
638
639     $decimal_mark = $fields['decimal_mark'];
640     if ($decimal_mark !== null) {
641       $decimal_mark_f = ', decimal_mark';
642       $decimal_mark_v = ', ' . $mdb2->quote($decimal_mark);
643     } else {
644       $decimal_mark_f = '';
645       $decimal_mark_v = '';
646     }
647
648     $lang = $fields['lang'];
649     if (!$lang) {
650       global $i18n;
651       $lang = $i18n->lang;
652     }
653
654     $date_format = $fields['date_format'];
655     if ($date_format !== null) {
656       $date_format_f = ', date_format';
657       $date_format_v = ', ' . $mdb2->quote($date_format);
658     } elseif (defined('DATE_FORMAT_DEFAULT')) {
659       $date_format_f = ', date_format';
660       $date_format_v = ', ' . $mdb2->quote(DATE_FORMAT_DEFAULT);
661     } else {
662       $date_format_f = '';
663       $date_format_v = '';
664     }
665
666     $time_format = $fields['time_format'];
667     if ($time_format !== null) {
668       $time_format_f = ', time_format';
669       $time_format_v = ', ' . $mdb2->quote($time_format);
670     } elseif (defined('TIME_FORMAT_DEFAULT')) {
671       $time_format_f = ', time_format';
672       $time_format_v = ', ' . $mdb2->quote(TIME_FORMAT_DEFAULT);
673     } else {
674       $time_format_f = '';
675       $time_format_v = '';
676     }
677
678     $week_start = $fields['week_start'];
679     if ($week_start !== null) {
680       $week_start_f = ', week_start';
681       $week_start_v = ', ' . (int)$week_start;
682     } elseif (defined('WEEK_START_DEFAULT')) {
683       $week_start_f = ', week_start';
684       $week_start_v = ', ' . (int)WEEK_START_DEFAULT;
685     } else {
686       $week_start_f = '';
687       $week_start_v = '';
688     }
689
690     $tracking_mode = $fields['tracking_mode'];
691     if ($tracking_mode !== null) {
692       $tracking_mode_f = ', tracking_mode';
693       $tracking_mode_v = ', ' . (int)$tracking_mode;
694     } else {
695       $tracking_mode_f = '';
696       $tracking_mode_v = '';
697     }
698
699     $project_required = $fields['project_required'];
700     if ($project_required !== null) {
701       $project_required_f = ', project_required';
702       $project_required_v = ', ' . (int)$project_required;
703     } else {
704       $project_required_f = '';
705       $project_required_v = '';
706     }
707
708     $task_required = $fields['task_required'];
709     if ($task_required !== null) {
710       $task_required_f = ', task_required';
711       $task_required_v = ', ' . (int)$task_required;
712     } else {
713       $task_required_f = '';
714       $task_required_v = '';
715     }
716
717     $record_type = $fields['record_type'];
718     if ($record_type !== null) {
719       $record_type_f = ', record_type';
720       $record_type_v = ', ' . (int)$record_type;
721     } else {
722       $record_type_f = '';
723       $record_type_v = '';
724     }
725
726     $uncompleted_indicators = $fields['uncompleted_indicators'];
727     if ($uncompleted_indicators !== null) {
728       $uncompleted_indicators_f = ', uncompleted_indicators';
729       $uncompleted_indicators_v = ', ' . (int)$uncompleted_indicators;
730     } else {
731       $uncompleted_indicators_f = '';
732       $uncompleted_indicators_v = '';
733     }
734
735     $bcc_email = $fields['bcc_email'];
736     if ($bcc_email !== null) {
737       $bcc_email_f = ', bcc_email';
738       $bcc_email_v = ', ' . $mdb2->quote($bcc_email);
739     } else {
740       $bcc_email_f = '';
741       $bcc_email_v = '';
742     }
743
744     $plugins = $fields['plugins'];
745     if ($plugins !== null) {
746       $plugins_f = ', plugins';
747       $plugins_v = ', ' . $mdb2->quote($plugins);
748     } else {
749       $plugins_f = '';
750       $plugins_v = '';
751     }
752
753     $lock_spec = $fields['lock_spec'];
754     if ($lock_spec !== null) {
755       $lockspec_f = ', lock_spec';
756       $lockspec_v = ', ' . $mdb2->quote($lock_spec);
757     } else {
758       $lockspec_f = '';
759       $lockspec_v = '';
760     }
761
762     $workday_hours = $fields['workday_hours'];
763     if ($workday_hours !== null) {
764       $workday_hours_f = ', workday_hours';
765       $workday_hours_v = ', ' . (int)$workday_hours;
766     } else {
767       $workday_hours_f = '';
768       $workday_hours_v = '';
769     }
770
771     $sql = "insert into tt_teams (name, currency $decimal_mark_f, lang $date_format_f $time_format_f $week_start_f $tracking_mode_f $project_required_f $task_required_f $record_type_f $uncompleted_indicators_f $bcc_email_f $plugins_f $lockspec_f $workday_hours_f)
772       values(".$mdb2->quote(trim($fields['name'])).
773       ", ".$mdb2->quote(trim($fields['currency']))." $decimal_mark_v, ".$mdb2->quote($lang).
774       "$date_format_v $time_format_v $week_start_v $tracking_mode_v $project_required_v $task_required_v $record_type_v $uncompleted_indicators_v $bcc_email_v $plugins_v $lockspec_v $workday_hours_v)";
775     $affected = $mdb2->exec($sql);
776
777     if (!is_a($affected, 'PEAR_Error')) {
778       $team_id = $mdb2->lastInsertID('tt_teams', 'id');
779       return $team_id;
780     }
781
782     return false;
783   }
784
785   // The update function updates team information.
786   static function update($team_id, $fields)
787   {
788     $mdb2 = getConnection();
789     $name_part = 'name = '.$mdb2->quote($fields['name']);
790     $currency_part = '';
791     $lang_part = '';
792     $decimal_mark_part = '';
793     $date_format_part = '';
794     $time_format_part = '';
795     $week_start_part = '';
796     $tracking_mode_part = '';
797     $task_required_part = ' , task_required = '.intval($fields['task_required']);
798     $record_type_part = '';
799     $uncompleted_indicators_part = '';
800     $bcc_email_part = '';
801     $plugins_part = '';
802     $lock_spec_part = '';
803     $workday_hours_part = '';
804
805     if (isset($fields['currency'])) $currency_part = ', currency = '.$mdb2->quote($fields['currency']);
806     if (isset($fields['lang'])) $lang_part = ', lang = '.$mdb2->quote($fields['lang']);
807     if (isset($fields['decimal_mark'])) $decimal_mark_part = ', decimal_mark = '.$mdb2->quote($fields['decimal_mark']);
808     if (isset($fields['date_format'])) $date_format_part = ', date_format = '.$mdb2->quote($fields['date_format']);
809     if (isset($fields['time_format'])) $time_format_part = ', time_format = '.$mdb2->quote($fields['time_format']);
810     if (isset($fields['week_start'])) $week_start_part = ', week_start = '.intval($fields['week_start']);
811     if (isset($fields['tracking_mode'])) $tracking_mode_part = ', tracking_mode = '.intval($fields['tracking_mode']);
812     if (isset($fields['record_type'])) $record_type_part = ', record_type = '.intval($fields['record_type']);
813     if (isset($fields['uncompleted_indicators'])) $uncompleted_indicators_part = ', uncompleted_indicators = '.intval($fields['uncompleted_indicators']);
814     if (isset($fields['bcc_email'])) $bcc_email_part = ', bcc_email = '.$mdb2->quote($fields['bcc_email']);
815     if (isset($fields['plugins'])) $plugins_part = ', plugins = '.$mdb2->quote($fields['plugins']);
816     if (isset($fields['lock_spec'])) $lock_spec_part = ', lock_spec = '.$mdb2->quote($fields['lock_spec']);
817     if (isset($fields['workday_hours'])) $workday_hours_part = ', workday_hours = '.$mdb2->quote($fields['workday_hours']);
818
819     $sql = "update tt_teams set $name_part $currency_part $lang_part $decimal_mark_part
820       $date_format_part $time_format_part $week_start_part $tracking_mode_part $task_required_part $record_type_part
821       $uncompleted_indicators_part $bcc_email_part $plugins_part $lock_spec_part $workday_hours_part where id = $team_id";
822     $affected = $mdb2->exec($sql);
823     if (is_a($affected, 'PEAR_Error')) return false;
824
825     return true;
826   }
827
828   // The getInactiveTeams is a maintenance function that returns an array of inactive team ids (max 100).
829   static function getInactiveTeams() {
830     $inactive_teams = array();
831     $mdb2 = getConnection();
832
833     // Get all team ids for teams created or modified more than 6 months ago.
834     // $ts = date('Y-m-d', strtotime('-1 year'));
835     $ts = date('Y-m-d', strtotime('-6 month'));
836     $sql =  "select id from tt_teams where timestamp < '$ts' order by id";
837     $res = $mdb2->query($sql);
838
839     $count = 0;
840     if (!is_a($res, 'PEAR_Error')) {
841       while ($val = $res->fetchRow()) {
842         $team_id = $val['id'];
843         if (ttTeamHelper::isTeamActive($team_id) == false) {
844           $count++;
845           $inactive_teams[] = $team_id;
846           // Limit the array size for perfomance by allowing this operation on small chunks only.
847           if ($count >= 100) break;
848         }
849       }
850       return $inactive_teams;
851     }
852     return false;
853   }
854
855   // The isTeamActive determines if a team is using Time Tracker or abandoned it.
856   static function isTeamActive($team_id) {
857     $users = array();
858
859     $mdb2 = getConnection();
860     $sql = "select id from tt_users where team_id = $team_id";
861     $res = $mdb2->query($sql);
862     if (is_a($res, 'PEAR_Error')) die($res->getMessage());
863     while ($val = $res->fetchRow()) {
864       $users[] = $val['id'];
865     }
866     $user_list = implode(',', $users); // This is a comma-separated list of user ids.
867     if (!$user_list)
868       return false; // No users in team.
869
870     $count = 0;
871     $ts = date('Y-m-d', strtotime('-2 years'));
872     $sql = "select count(*) as cnt from tt_log where user_id in ($user_list) and timestamp > '$ts'";
873     $res = $mdb2->query($sql);
874     if (!is_a($res, 'PEAR_Error')) {
875       if ($val = $res->fetchRow()) {
876         $count = $val['cnt'];
877       }
878     }
879
880     if ($count == 0)
881       return false;  // No time entries for the last 2 years.
882
883     if ($count <= 5) {
884       // We will consider a team inactive if it has 5 or less time entries made more than 1 year ago.
885       $count_last_year = 0;
886       $ts = date('Y-m-d', strtotime('-1 year'));
887       $sql = "select count(*) as cnt from tt_log where user_id in ($user_list) and timestamp > '$ts'";
888       $res = $mdb2->query($sql);
889       if (!is_a($res, 'PEAR_Error')) {
890         if ($val = $res->fetchRow()) {
891           $count_last_year = $val['cnt'];
892         }
893         if ($count_last_year == 0)
894           return false;  // No time entries for the last year and only a few entries before that.
895       }
896     }
897     return true;
898   }
899
900   // The delete function permanently deletes all data for a team.
901   static function delete($team_id) {
902     $mdb2 = getConnection();
903
904     // Delete users.
905     $sql = "select id from tt_users where team_id = $team_id";
906     $res = $mdb2->query($sql);
907     if (is_a($res, 'PEAR_Error')) return false;
908     while ($val = $res->fetchRow()) {
909       $user_id = $val['id'];
910       if (!ttUserHelper::delete($user_id)) return false;
911     }
912
913     // Delete tasks.
914     if (!ttTeamHelper::deleteTasks($team_id)) return false;
915
916     // Delete client to project binds.
917     $sql = "delete from tt_client_project_binds where client_id in (select id from tt_clients where team_id = $team_id)";
918     $affected = $mdb2->exec($sql);
919     if (is_a($affected, 'PEAR_Error')) return false;
920
921     // Delete projects.
922     $sql = "delete from tt_projects where team_id = $team_id";
923     $affected = $mdb2->exec($sql);
924     if (is_a($affected, 'PEAR_Error')) return false;
925
926     // Delete clients.
927     $sql = "delete from tt_clients where team_id = $team_id";
928     $affected = $mdb2->exec($sql);
929     if (is_a($affected, 'PEAR_Error')) return false;
930
931     // Delete invoices.
932     $sql = "delete from tt_invoices where team_id = $team_id";
933     $affected = $mdb2->exec($sql);
934     if (is_a($affected, 'PEAR_Error')) return false;
935
936     // Delete custom fields.
937     if (!ttTeamHelper::deleteCustomFields($team_id)) return false;
938
939     // Delete team.
940     $sql = "delete from tt_teams where id = $team_id";
941     $affected = $mdb2->exec($sql);
942     if (is_a($affected, 'PEAR_Error')) return false;
943
944     return true;
945   }
946
947   // The markTasksDeleted deletes task binds and marks the tasks as deleted for a team.
948   static function markTasksDeleted($team_id) {
949     $mdb2 = getConnection();
950     $sql = "select id from tt_tasks where team_id = $team_id";
951     $res = $mdb2->query($sql);
952     if (is_a($res, 'PEAR_Error')) return false;
953
954     while ($val = $res->fetchRow()) {
955
956       // Delete task binds.
957       $task_id = $val['id'];
958       $sql = "delete from tt_project_task_binds where task_id = $task_id";
959       $affected = $mdb2->exec($sql);
960       if (is_a($affected, 'PEAR_Error')) return false;
961
962       // Mark task as deleted.
963       $sql = "update tt_tasks set status = NULL where id = $task_id";
964       $affected = $mdb2->exec($sql);
965       if (is_a($affected, 'PEAR_Error')) return false;
966     }
967
968     return true;
969   }
970
971   // The deleteTasks deletes all tasks and task binds for an inactive team.
972   static function deleteTasks($team_id) {
973     $mdb2 = getConnection();
974     $sql = "select id from tt_tasks where team_id = $team_id";
975     $res = $mdb2->query($sql);
976     if (is_a($res, 'PEAR_Error')) return false;
977
978     while ($val = $res->fetchRow()) {
979
980       // Delete task binds.
981       $task_id = $val['id'];
982       $sql = "delete from tt_project_task_binds where task_id = $task_id";
983       $affected = $mdb2->exec($sql);
984       if (is_a($affected, 'PEAR_Error')) return false;
985
986       // Delete task.
987       $sql = "delete from tt_tasks where id = $task_id";
988       $affected = $mdb2->exec($sql);
989       if (is_a($affected, 'PEAR_Error')) return false;
990     }
991
992     return true;
993   }
994
995   // The deleteCustomFields cleans up tt_custom_field_log, tt_custom_field_options and tt_custom_fields tables for an inactive team.
996   static function deleteCustomFields($team_id) {
997     $mdb2 = getConnection();
998     $sql = "select id from tt_custom_fields where team_id = $team_id";
999     $res = $mdb2->query($sql);
1000     if (is_a($res, 'PEAR_Error')) return false;
1001
1002     while ($val = $res->fetchRow()) {
1003       $field_id = $val['id'];
1004
1005       // Clean up tt_custom_field_log.
1006       $sql = "delete from tt_custom_field_log where field_id = $field_id";
1007       $affected = $mdb2->exec($sql);
1008       if (is_a($affected, 'PEAR_Error')) return false;
1009
1010       // Clean up tt_custom_field_options.
1011       $sql = "delete from tt_custom_field_options where field_id = $field_id";
1012       $affected = $mdb2->exec($sql);
1013       if (is_a($affected, 'PEAR_Error')) return false;
1014
1015       // Delete custom field.
1016       $sql = "delete from tt_custom_fields where id = $field_id";
1017       $affected = $mdb2->exec($sql);
1018       if (is_a($affected, 'PEAR_Error')) return false;
1019     }
1020
1021     return true;
1022   }
1023 }