]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/Calendar/Calendar.php
Release 6.1.4
[Github/sugarcrm.git] / modules / Calendar / Calendar.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38 /*********************************************************************************
39
40  ********************************************************************************/
41
42
43 require_once('modules/Calendar/DateTimeUtil.php');
44
45 require_once('include/utils/activity_utils.php');
46
47 function sort_func_by_act_date($act0,$act1)
48 {
49         if ($act0->start_time->ts == $act1->start_time->ts)
50         {
51                 return 0;
52         }
53
54         return ($act0->start_time->ts < $act1->start_time->ts) ? -1 : 1;
55 }
56
57 class Calendar
58 {
59         var $view = 'month';
60         var $date_time;
61         var $slices_arr = array();
62         // for monthly calendar view, if you want to see all the
63         // days in the grid, otherwise you only see that months
64         var $show_only_current_slice = false;
65         var $show_activities = true;
66         var $show_tasks = true;
67         var $activity_focus;
68         var $show_week_on_month_view = true;
69         var $use_24 = 1;
70         var $toggle_appt = true;
71         var $slice_hash = array();
72         var $shared_users_arr = array();
73
74         function Calendar($view,$time_arr=array())
75         {
76                 global $current_user;
77                 global $sugar_config;
78                 if ( $current_user->getPreference('time'))
79                 {
80                         $time = $current_user->getPreference('time');
81                 }
82                 else
83                 {
84                         $time = $sugar_config['default_time_format'];
85                 }
86
87                 if( substr_count($time, 'h') > 0)
88                 {
89                         $this->use_24 = 0;
90                 }
91
92                 $this->view = $view;
93
94                 if ( isset($time_arr['activity_focus']))
95                 {
96                         $this->activity_focus =  new CalendarActivity($time_arr['activity_focus']);
97                         $this->date_time =  $this->activity_focus->start_time;
98                 }
99                 else
100                 {
101                         $this->date_time = new DateTimeUtil($time_arr,true);
102                 }
103
104                 if (!( $view == 'day' || $view == 'month' || $view == 'year' || $view == 'week' || $view == 'shared') )
105                 {
106                         sugar_die ("view needs to be one of: day, week, month, shared, or year");
107                 }
108
109                 if ( empty($this->date_time->year))
110                 {
111                         sugar_die ("all views: year was not set");
112                 }
113                 else if ( $this->view == 'month' &&  empty($this->date_time->month))
114                 {
115                         sugar_die ("month view: month was not set");
116                 }
117                 else if ( $this->view == 'week' && empty($this->date_time->week))
118                 {
119                         sugar_die ("week view: week was not set");
120                 }
121                 else if ( $this->view == 'shared' && empty($this->date_time->week))
122                 {
123                         sugar_die ("shared view: shared was not set");
124                 }
125                 else if ( $this->view == 'day' &&  empty($this->date_time->day) && empty($this->date_time->month))
126                 {
127                         sugar_die ("day view: day and month was not set");
128                 }
129
130                 $this->create_slices();
131
132         }
133         function add_shared_users(&$shared_users_arr)
134         {
135                 $this->shared_users_arr = $shared_users_arr;
136         }
137
138         function get_view_name($view)
139         {
140                 if ($view == 'month')
141                 {
142                         return "MONTH";
143                 }
144                 else if ($view == 'week')
145                 {
146                         return "WEEK";
147                 }
148                 else if ($view == 'day')
149                 {
150                         return "DAY";
151                 }
152                 else if ($view == 'year')
153                 {
154                         return "YEAR";
155                 }
156                 else if ($view == 'shared')
157                 {
158                         return "SHARED";
159                 }
160                 else
161                 {
162                         sugar_die ("get_view_name: view ".$this->view." not supported");
163                 }
164         }
165
166     function isDayView() {
167         return $this->view == 'day';
168     }
169
170         function get_slices_arr()
171         {
172                 return $this->slices_arr;
173         }
174
175
176         function create_slices()
177         {
178
179                 global $current_user;
180
181
182                 if ( $this->view == 'month')
183                 {
184                         $days_in_month = $this->date_time->days_in_month;
185
186
187                         $first_day_of_month = $this->date_time->get_day_by_index_this_month(0);
188                         $num_of_prev_days = $first_day_of_month->day_of_week;
189                         // do 42 slices (6x7 grid)
190
191                         for($i=0;$i < 42;$i++)
192                         {
193                                 $slice = new Slice('day',$this->date_time->get_day_by_index_this_month($i-$num_of_prev_days));
194                                 $this->slice_hash[$slice->start_time->get_mysql_date()] = $slice;
195                                 array_push($this->slices_arr,  $slice->start_time->get_mysql_date());
196                         }
197
198                 }
199                 else if ( $this->view == 'week' || $this->view == 'shared')
200                 {
201                         $days_in_week = 7;
202
203                         for($i=0;$i<$days_in_week;$i++)
204                         {
205                                 $slice = new Slice('day',$this->date_time->get_day_by_index_this_week($i));
206                                 $this->slice_hash[$slice->start_time->get_mysql_date()] = $slice;
207                                 array_push($this->slices_arr,  $slice->start_time->get_mysql_date());
208                         }
209                 }
210                 else if ( $this->view == 'day')
211                 {
212                         $hours_in_day = 24;
213
214                         for($i=0;$i<$hours_in_day;$i++)
215                         {
216                                 $slice = new Slice('hour',$this->date_time->get_datetime_by_index_today($i));
217                                 $this->slice_hash[$slice->start_time->get_mysql_date().":".$slice->start_time->hour ] = $slice;
218                                 $this->slices_arr[] =  $slice->start_time->get_mysql_date().":".$slice->start_time->hour;
219                         }
220                 }
221                 else if ( $this->view == 'year')
222                 {
223
224                         for($i=0;$i<12;$i++)
225                         {
226                                 $slice = new Slice('month',$this->date_time->get_day_by_index_this_year($i));
227                                 $this->slice_hash[$slice->start_time->get_mysql_date()] = $slice;
228                                 array_push($this->slices_arr,  $slice->start_time->get_mysql_date());
229                         }
230                 }
231                 else
232                 {
233                         sugar_die("not a valid view:".$this->view);
234                 }
235
236         }
237
238         function add_activities($user,$type='sugar') {
239                 if ( $this->view == 'week' || $this->view == 'shared') {
240                         $end_date_time = $this->date_time->get_first_day_of_next_week();
241                 } else {
242                         $end_date_time = $this->date_time;
243                 }
244
245                 $acts_arr = array();
246         if($type == 'vfb') {
247                         $acts_arr = CalendarActivity::get_freebusy_activities($user, $this->date_time, $end_date_time);
248         } else {
249                         $acts_arr = CalendarActivity::get_activities($user->id, $this->show_tasks, $this->date_time, $end_date_time, $this->view);
250         }
251
252             // loop thru each activity for this user
253                 for ($i = 0;$i < count($acts_arr);$i++) {
254                         $act = $acts_arr[$i];
255                         // get "hashed" time slots for the current activity we are looping through
256                         $hash_list =DateTimeUtil::getHashList($this->view,$act->start_time,$act->end_time);
257
258                         for($j=0;$j < count($hash_list); $j++) {
259                                 if(!isset($this->slice_hash[$hash_list[$j]]) || !isset($this->slice_hash[$hash_list[$j]]->acts_arr[$user->id])) {
260                                         $this->slice_hash[$hash_list[$j]]->acts_arr[$user->id] = array();
261                                 }
262                                 $this->slice_hash[$hash_list[$j]]->acts_arr[$user->id][] = $act;
263                         }
264                 }
265         }
266
267         function occurs_within_slice(&$slice,&$act)
268         {
269                 // if activity starts within this slice
270                 // OR activity ends within this slice
271                 // OR activity starts before and ends after this slice
272                 if ( ( $act->start_time->ts >= $slice->start_time->ts &&
273                          $act->start_time->ts <= $slice->end_time->ts )
274                         ||
275                         ( $act->end_time->ts >= $slice->start_time->ts &&
276                         $act->end_time->ts <= $slice->end_time->ts )
277                         ||
278                         ( $act->start_time->ts <= $slice->start_time->ts &&
279                         $act->end_time->ts >= $slice->end_time->ts )
280                 )
281                 {
282                         //print "act_start:{$act->start_time->ts}<BR>";
283                         //print "act_end:{$act->end_time->ts}<BR>";
284                         //print "slice_start:{$slice->start_time->ts}<BR>";
285                         //print "slice_end:{$slice->end_time->ts}<BR>";
286                         return true;
287                 }
288
289                 return false;
290
291         }
292
293         function get_previous_date_str()
294         {
295                 if ($this->view == 'month')
296                 {
297                         $day = $this->date_time->get_first_day_of_last_month();
298                 }
299                 else if ($this->view == 'week' || $this->view == 'shared')
300                 {
301                         $day = $this->date_time->get_first_day_of_last_week();
302                 }
303                 else if ($this->view == 'day')
304                 {
305                         $day = $this->date_time->get_yesterday();
306                 }
307                 else if ($this->view == 'year')
308                 {
309                         $day = $this->date_time->get_first_day_of_last_year();
310                 }
311                 else
312                 {
313                         return "get_previous_date_str: notdefined for this view";
314                 }
315                 return $day->get_date_str();
316         }
317
318         function get_next_date_str()
319         {
320                 if ($this->view == 'month')
321                 {
322                         $day = $this->date_time->get_first_day_of_next_month();
323                 }
324                 else
325                 if ($this->view == 'week' || $this->view == 'shared' )
326                 {
327                         $day = $this->date_time->get_first_day_of_next_week();
328                 }
329                 else
330                 if ($this->view == 'day')
331                 {
332                         $day = $this->date_time->get_tomorrow();
333                 }
334                 else
335                 if ($this->view == 'year')
336                 {
337                         $day = $this->date_time->get_first_day_of_next_year();
338                 }
339                 else
340                 {
341                         sugar_die("get_next_date_str: not defined for view");
342                 }
343                 return $day->get_date_str();
344         }
345
346         function get_start_slice_idx()
347         {
348
349                 if ($this->isDayView())
350                 {
351                         $start_at = 8;
352
353                         for($i=0;$i < 8; $i++)
354                         {
355                                 if (count($this->slice_hash[$this->slices_arr[$i]]->acts_arr) > 0)
356                                 {
357                                         $start_at = $i;
358                                         break;
359                                 }
360                         }
361                         return $start_at;
362                 }
363                 else
364                 {
365                         return 0;
366                 }
367         }
368         function get_end_slice_idx()
369         {
370                 if ( $this->view == 'month')
371                 {
372                         return $this->date_time->days_in_month - 1;
373                 }
374                 else if ( $this->view == 'week' || $this->view == 'shared')
375                 {
376                         return 6;
377                 }
378                 else if ($this->isDayView())
379                 {
380                         $end_at = 18;
381
382                         for($i=$end_at;$i < 23; $i++)
383                         {
384                                 if (count($this->slice_hash[$this->slices_arr[$i+1]]->acts_arr) > 0)
385                                 {
386                                         $end_at = $i + 1;
387                                 }
388                         }
389
390
391                         return $end_at;
392
393                 }
394                 else
395                 {
396                         return 1;
397                 }
398         }
399
400
401 }
402
403 class Slice
404 {
405         var $view = 'day';
406         var $start_time;
407         var $end_time;
408         var $acts_arr = array();
409
410         function Slice($view,$time)
411         {
412                 $this->view = $view;
413                 $this->start_time = $time;
414
415                 if ( $view == 'day')
416                 {
417                         $this->end_time = $this->start_time->get_day_end_time();
418                 }
419                 if ( $view == 'hour')
420                 {
421                         $this->end_time = $this->start_time->get_hour_end_time();
422                 }
423
424         }
425         function get_view()
426         {
427                 return $this->view;
428         }
429
430 }
431
432 // global to switch on the offet
433
434 $DO_USER_TIME_OFFSET = false;
435
436 class CalendarActivity
437 {
438         var $sugar_bean;
439         var $start_time;
440         var $end_time;
441
442         function CalendarActivity($args)
443         {
444     // if we've passed in an array, then this is a free/busy slot
445     // and does not have a sugarbean associated to it
446                 global $DO_USER_TIME_OFFSET;
447
448     if ( is_array ( $args ))
449     {
450        $this->start_time = $args[0];
451        $this->end_time = $args[1];
452        $this->sugar_bean = null;
453        return;
454     }
455
456     // else do regular constructor..
457
458         $sugar_bean = $args;
459                 global $timedate;
460                 $this->sugar_bean = $sugar_bean;
461
462
463                 if ($sugar_bean->object_name == 'Task')
464                 {
465
466                         $newdate = $timedate->merge_date_time($this->sugar_bean->date_due, $this->sugar_bean->time_due);
467                         $tempdate  = $timedate->to_db_date($newdate,$DO_USER_TIME_OFFSET);
468
469                         if($newdate != $tempdate){
470                                 $this->sugar_bean->date_due = $tempdate;
471                         }
472                         $temptime = $timedate->to_db_time($newdate, $DO_USER_TIME_OFFSET);
473                         if($newdate != $temptime){
474                                 $this->sugar_bean->time_due = $temptime;
475                         }
476                         $this->start_time =DateTimeUtil::get_time_start(
477                                 $this->sugar_bean->date_due,
478                                 $this->sugar_bean->time_due
479                         );
480                         if ( empty($this->start_time))
481                         {
482                                 return null;
483                         }
484
485                         $this->end_time = $this->start_time;
486                 }
487                 else
488                 {
489             // Convert it back to database time so we can properly manage it for getting the proper start and end dates
490             $dbDate = $timedate->to_db($this->sugar_bean->date_start);
491             $this->start_time =DateTimeUtil::get_time_start($dbDate);
492                     $this->end_time =DateTimeUtil::get_time_end(
493                             $this->start_time,
494                         $this->sugar_bean->duration_hours,
495                         $this->sugar_bean->duration_minutes
496                         );
497                 }
498
499         }
500
501         function get_occurs_within_where_clause($table_name, $rel_table, $start_ts_obj, $end_ts_obj, $field_name='date_start', $view) {
502                 global $timedate;
503                 $dtUtilArr = array();
504                 switch ($view) {
505                         case 'month':
506                                 $start_ts = $start_ts_obj->get_first_day_of_this_month();
507                                 $end_ts = $end_ts_obj->get_first_day_of_next_month();
508                                 break;
509                         default:
510                                 // Date for the past 5 days as that is the maximum duration of a single activity
511                                 $dtUtilArr['ts'] = $start_ts_obj->ts - (86400*5);
512                                 $start_ts = new DateTimeUtil($dtUtilArr, false);
513                                 // Date for the next 5 days as that is the maximum duration of a single activity
514                                 $dtUtilArr['ts'] = $end_ts_obj->ts + (86400*5);
515                                 $end_ts = new DateTimeUtil($dtUtilArr, false);
516                                 break;
517                 }
518
519                 $start_day = $timedate->getDayStartEndGMT(date($timedate->get_date_format(), $start_ts->ts));
520                 $end_day = $timedate->getDayStartEndGMT(date($timedate->get_date_format(), $end_ts->ts));
521
522                 $field_date = $GLOBALS['db']->convert($table_name.'.'.$field_name,'datetime');
523
524                 $where = "($field_date >= '{$start_day['start']}' AND $field_date < '{$end_day['start']}'";
525         if($rel_table != '') {
526             $where .= " AND $rel_table.accept_status != 'decline'";
527         }
528                 
529                 $where .= ")";
530                 return $where;
531         }
532
533   function get_freebusy_activities(&$user_focus,&$start_date_time,&$end_date_time)
534   {
535
536
537                   $act_list = array();
538       $vcal_focus = new vCal();
539       $vcal_str = $vcal_focus->get_vcal_freebusy($user_focus);
540
541       $lines = explode("\n",$vcal_str);
542
543       foreach ($lines as $line)
544       {
545         $dates_arr = array();
546         if ( preg_match('/^FREEBUSY.*?:([^\/]+)\/([^\/]+)/i',$line,$matches))
547         {
548           $dates_arr[] =DateTimeUtil::parse_utc_date_time($matches[1]);
549           $dates_arr[] =DateTimeUtil::parse_utc_date_time($matches[2]);
550           $act_list[] = new CalendarActivity($dates_arr);
551         }
552       }
553                   usort($act_list,'sort_func_by_act_date');
554       return $act_list;
555   }
556
557
558         function get_activities($user_id, $show_tasks, &$view_start_time, &$view_end_time, $view) {
559                 global $current_user;
560                 $act_list = array();
561                 $seen_ids = array();
562
563
564                 // get all upcoming meetings, tasks due, and calls for a user
565                 if(ACLController::checkAccess('Meetings', 'list', $current_user->id == $user_id)) {
566                         $meeting = new Meeting();
567
568                         if($current_user->id  == $user_id) {
569                                 $meeting->disable_row_level_security = true;
570                         }
571
572                         $where = CalendarActivity::get_occurs_within_where_clause($meeting->table_name, $meeting->rel_users_table, $view_start_time, $view_end_time, 'date_start', $view);
573                         $focus_meetings_list = build_related_list_by_user_id($meeting,$user_id,$where);
574                         foreach($focus_meetings_list as $meeting) {
575                                 if(isset($seen_ids[$meeting->id])) {
576                                         continue;
577                                 }
578
579                                 $seen_ids[$meeting->id] = 1;
580                                 $act = new CalendarActivity($meeting);
581
582                                 if(!empty($act)) {
583                                         $act_list[] = $act;
584                                 }
585                         }
586                 }
587
588                 if(ACLController::checkAccess('Calls', 'list',$current_user->id  == $user_id)) {
589                         $call = new Call();
590
591                         if($current_user->id  == $user_id) {
592                                 $call->disable_row_level_security = true;
593                         }
594
595                         $where = CalendarActivity::get_occurs_within_where_clause($call->table_name, $call->rel_users_table, $view_start_time, $view_end_time, 'date_start', $view);
596                         $focus_calls_list = build_related_list_by_user_id($call,$user_id,$where);
597
598                         foreach($focus_calls_list as $call) {
599                                 if(isset($seen_ids[$call->id])) {
600                                         continue;
601                                 }
602                                 $seen_ids[$call->id] = 1;
603
604                                 $act = new CalendarActivity($call);
605                                 if(!empty($act)) {
606                                         $act_list[] = $act;
607                                 }
608                         }
609                 }
610
611
612                 if($show_tasks) {
613                         if(ACLController::checkAccess('Tasks', 'list',$current_user->id == $user_id)) {
614                                 $task = new Task();
615
616                                 $where = CalendarActivity::get_occurs_within_where_clause('tasks', '', $view_start_time, $view_end_time, 'date_due', $view);
617                                 $where .= " AND tasks.assigned_user_id='$user_id' ";
618
619                                 $focus_tasks_list = $task->get_full_list("", $where,true);
620
621                                 if(!isset($focus_tasks_list)) {
622                                         $focus_tasks_list = array();
623                                 }
624
625                                 foreach($focus_tasks_list as $task) {
626                                         $act = new CalendarActivity($task);
627                                         if(!empty($act)) {
628                                                 $act_list[] = $act;
629                                         }
630                                 }
631                         }
632                 }
633
634                 usort($act_list,'sort_func_by_act_date');
635                 return $act_list;
636         }
637 }