1<?php
2/* Copyright (C) 2001-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2003      Eric Seigne          <erics@rycks.com>
4 * Copyright (C) 2004-2018 Laurent Destailleur  <eldy@users.sourceforge.net>
5 * Copyright (C) 2005-2012 Regis Houssin        <regis.houssin@inodbox.com>
6 * Copyright (C) 2011      Juanjo Menent        <jmenent@2byte.es>
7 * Copyright (C) 2014      Cedric GROSS         <c.gross@kreiz-it.fr>
8 * Copyright (C) 2015      Marcos García        <marcosgdf@gmail.com>
9 * Copyright (C) 2017      Open-DSI             <support@open-dsi.fr>
10 * Copyright (C) 2018      Frédéric France      <frederic.france@netlogic.fr>
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <https://www.gnu.org/licenses/>.
24 */
25
26
27/**
28 *  \file       htdocs/comm/action/index.php
29 *  \ingroup    agenda
30 *  \brief      Home page of calendar events
31 */
32
33require '../../main.inc.php';
34require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php';
35require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php';
36require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
37require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
38require_once DOL_DOCUMENT_ROOT.'/core/lib/agenda.lib.php';
39if (!empty($conf->projet->enabled)) {
40	require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
41}
42
43if (!isset($conf->global->AGENDA_MAX_EVENTS_DAY_VIEW)) $conf->global->AGENDA_MAX_EVENTS_DAY_VIEW = 3;
44
45if (empty($conf->global->AGENDA_EXT_NB)) $conf->global->AGENDA_EXT_NB = 5;
46$MAXAGENDA = $conf->global->AGENDA_EXT_NB;
47
48$filter = GETPOST("search_filter", 'alpha', 3) ?GETPOST("search_filter", 'alpha', 3) : GETPOST("filter", 'alpha', 3);
49$filtert = GETPOST("search_filtert", "int", 3) ?GETPOST("search_filtert", "int", 3) : GETPOST("filtert", "int", 3);
50$usergroup = GETPOST("search_usergroup", "int", 3) ?GETPOST("search_usergroup", "int", 3) : GETPOST("usergroup", "int", 3);
51$showbirthday = empty($conf->use_javascript_ajax) ?GETPOST("showbirthday", "int") : 1;
52
53// If not choice done on calendar owner (like on left menu link "Agenda"), we filter on user.
54if (empty($filtert) && empty($conf->global->AGENDA_ALL_CALENDARS))
55{
56	$filtert = $user->id;
57}
58
59$sortfield = GETPOST("sortfield", 'alpha');
60$sortorder = GETPOST("sortorder", 'alpha');
61$page = GETPOSTISSET('pageplusone') ? (GETPOST('pageplusone') - 1) : GETPOST("page", 'int');
62if (empty($page) || $page == -1) { $page = 0; }     // If $page is not defined, or '' or -1
63$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
64$offset = $limit * $page;
65if (!$sortorder) $sortorder = "ASC";
66if (!$sortfield) $sortfield = "a.datec";
67
68// Security check
69$socid = GETPOST("search_socid", "int") ?GETPOST("search_socid", "int") : GETPOST("socid", "int");
70if ($user->socid) $socid = $user->socid;
71$result = restrictedArea($user, 'agenda', 0, '', 'myactions');
72if ($socid < 0) $socid = '';
73
74$canedit = 1;
75if (!$user->rights->agenda->myactions->read) accessforbidden();
76if (!$user->rights->agenda->allactions->read) $canedit = 0;
77if (!$user->rights->agenda->allactions->read || $filter == 'mine')  // If no permission to see all, we show only affected to me
78{
79	$filtert = $user->id;
80}
81
82$action = GETPOST('action', 'aZ09');
83$resourceid = GETPOST("search_resourceid", "int");
84$year = GETPOST("year", "int") ?GETPOST("year", "int") : date("Y");
85$month = GETPOST("month", "int") ?GETPOST("month", "int") : date("m");
86$week = GETPOST("week", "int") ?GETPOST("week", "int") : date("W");
87$day = GETPOST("day", "int") ?GETPOST("day", "int") : date("d");
88$pid = GETPOST("search_projectid", "int", 3) ?GETPOST("search_projectid", "int", 3) : GETPOST("projectid", "int", 3);
89$status = GETPOST("search_status", 'aZ09') ?GETPOST("search_status", 'aZ09') : GETPOST("status", 'aZ09'); // status may be 0, 50, 100, 'todo'
90$type = GETPOST("search_type", 'aZ09') ?GETPOST("search_type", 'aZ09') : GETPOST("type", 'aZ09');
91$maxprint = (isset($_GET["maxprint"]) ?GETPOST("maxprint") : $conf->global->AGENDA_MAX_EVENTS_DAY_VIEW);
92$optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print')
93
94$dateselect = dol_mktime(0, 0, 0, GETPOST('dateselectmonth', 'int'), GETPOST('dateselectday', 'int'), GETPOST('dateselectyear', 'int'));
95if ($dateselect > 0)
96{
97	$day = GETPOST('dateselectday', 'int');
98	$month = GETPOST('dateselectmonth', 'int');
99	$year = GETPOST('dateselectyear', 'int');
100}
101
102// Set actioncode (this code must be same for setting actioncode into peruser, listacton and index)
103if (GETPOST('search_actioncode', 'array'))
104{
105	$actioncode = GETPOST('search_actioncode', 'array', 3);
106	if (!count($actioncode)) $actioncode = '0';
107} else {
108	$actioncode = GETPOST("search_actioncode", "alpha", 3) ?GETPOST("search_actioncode", "alpha", 3) : (GETPOST("search_actioncode") == '0' ? '0' : (empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE) ? '' : $conf->global->AGENDA_DEFAULT_FILTER_TYPE));
109}
110if ($actioncode == '' && empty($actioncodearray)) $actioncode = (empty($conf->global->AGENDA_DEFAULT_FILTER_TYPE) ? '' : $conf->global->AGENDA_DEFAULT_FILTER_TYPE);
111
112if ($status == '' && !GETPOSTISSET('search_status')) $status = (empty($conf->global->AGENDA_DEFAULT_FILTER_STATUS) ? '' : $conf->global->AGENDA_DEFAULT_FILTER_STATUS);
113
114$defaultview = (empty($conf->global->AGENDA_DEFAULT_VIEW) ? 'show_month' : $conf->global->AGENDA_DEFAULT_VIEW);
115$defaultview = (empty($user->conf->AGENDA_DEFAULT_VIEW) ? $defaultview : $user->conf->AGENDA_DEFAULT_VIEW);
116if (empty($action) && !GETPOSTISSET('action')) $action = $defaultview;
117if ($action == 'default')	// When action is default, we want a calendar view and not the list
118{
119	$action = (($defaultview != 'show_list') ? $defaultview : 'show_month');
120}
121if (GETPOST('viewcal', 'restricthtml') && GETPOST('action', 'alpha') != 'show_day' && GETPOST('action', 'alpha') != 'show_week') {
122	$action = 'show_month'; $day = '';
123} // View by month
124if (GETPOST('viewweek', 'restricthtml') || GETPOST('action', 'alpha') == 'show_week') {
125	$action = 'show_week'; $week = ($week ? $week : date("W")); $day = ($day ? $day : date("d"));
126} // View by week
127if (GETPOST('viewday', 'restricthtml') || GETPOST('action', 'alpha') == 'show_day') {
128	$action = 'show_day'; $day = ($day ? $day : date("d"));
129} // View by day
130
131// Load translation files required by the page
132$langs->loadLangs(array('agenda', 'other', 'commercial'));
133
134// Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
135$hookmanager->initHooks(array('agenda'));
136
137
138/*
139 * Actions
140 */
141
142if (GETPOST("viewlist", 'alpha') || $action == 'show_list')
143{
144	$param = '';
145	if (is_array($_POST))
146	{
147		foreach ($_POST as $key => $val)
148		{
149			if ($key == 'token') continue;
150			$param .= '&'.$key.'='.urlencode($val);
151		}
152	}
153	if (!preg_match('/action=/', $param)) $param .= ($param ? '&' : '').'action=show_list';
154	//print $param;
155	header("Location: ".DOL_URL_ROOT.'/comm/action/list.php?'.$param);
156	exit;
157}
158
159if (GETPOST("viewperuser", 'alpha') || $action == 'show_peruser')
160{
161	$param = '';
162	if (is_array($_POST))
163	{
164		foreach ($_POST as $key => $val)
165		{
166			if ($key == 'token') continue;
167			$param .= '&'.$key.'='.urlencode($val);
168		}
169	}
170	//print $param;
171	header("Location: ".DOL_URL_ROOT.'/comm/action/peruser.php?'.$param);
172	exit;
173}
174
175if ($action == 'delete_action')
176{
177	$event = new ActionComm($db);
178	$event->fetch($actionid);
179	$event->fetch_optionals();
180	$event->fetch_userassigned();
181	$event->oldcopy = clone $event;
182
183	$result = $event->delete();
184}
185
186
187/*
188 * View
189 */
190$parameters = array(
191	'socid' => $socid,
192	'status' => $status,
193	'year' => $year,
194	'month' => $month,
195	'day' => $day,
196	'type' => $type,
197	'maxprint' => $maxprint,
198	'filter' => $filter,
199	'filtert' => $filtert,
200	'showbirthday' => $showbirthday,
201	'canedit' => $canedit,
202	'optioncss' => $optioncss,
203	'actioncode' => $actioncode,
204	'pid' => $pid,
205	'resourceid' => $resourceid,
206	'usergroup' => $usergroup,
207);
208$reshook = $hookmanager->executeHooks('beforeAgenda', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
209if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
210
211$help_url = 'EN:Module_Agenda_En|FR:Module_Agenda|ES:M&oacute;dulo_Agenda';
212llxHeader('', $langs->trans("Agenda"), $help_url);
213
214$form = new Form($db);
215$companystatic = new Societe($db);
216$contactstatic = new Contact($db);
217$userstatic = new User($db);
218
219$now = dol_now();
220$nowarray = dol_getdate($now);
221$nowyear = $nowarray['year'];
222$nowmonth = $nowarray['mon'];
223$nowday = $nowarray['mday'];
224
225$listofextcals = array();
226
227// Define list of external calendars (global admin setup)
228if (empty($conf->global->AGENDA_DISABLE_EXT))
229{
230	$i = 0;
231	while ($i < $MAXAGENDA)
232	{
233		$i++;
234		$source = 'AGENDA_EXT_SRC'.$i;
235		$name = 'AGENDA_EXT_NAME'.$i;
236		$offsettz = 'AGENDA_EXT_OFFSETTZ'.$i;
237		$color = 'AGENDA_EXT_COLOR'.$i;
238		$buggedfile = 'AGENDA_EXT_BUGGEDFILE'.$i;
239		if (!empty($conf->global->$source) && !empty($conf->global->$name))
240		{
241			// Note: $conf->global->buggedfile can be empty or 'uselocalandtznodaylight' or 'uselocalandtzdaylight'
242			$listofextcals[] = array('src'=>$conf->global->$source, 'name'=>$conf->global->$name, 'offsettz'=>$conf->global->$offsettz, 'color'=>$conf->global->$color, 'buggedfile'=>(isset($conf->global->buggedfile) ? $conf->global->buggedfile : 0));
243		}
244	}
245}
246// Define list of external calendars (user setup)
247if (empty($user->conf->AGENDA_DISABLE_EXT))
248{
249	$i = 0;
250	while ($i < $MAXAGENDA)
251	{
252		$i++;
253		$source = 'AGENDA_EXT_SRC_'.$user->id.'_'.$i;
254		$name = 'AGENDA_EXT_NAME_'.$user->id.'_'.$i;
255		$offsettz = 'AGENDA_EXT_OFFSETTZ_'.$user->id.'_'.$i;
256		$color = 'AGENDA_EXT_COLOR_'.$user->id.'_'.$i;
257		$enabled = 'AGENDA_EXT_ENABLED_'.$user->id.'_'.$i;
258		$buggedfile = 'AGENDA_EXT_BUGGEDFILE_'.$user->id.'_'.$i;
259		if (!empty($user->conf->$source) && !empty($user->conf->$name))
260		{
261			// Note: $conf->global->buggedfile can be empty or 'uselocalandtznodaylight' or 'uselocalandtzdaylight'
262			$listofextcals[] = array('src'=>$user->conf->$source, 'name'=>$user->conf->$name, 'offsettz'=>$user->conf->$offsettz, 'color'=>$user->conf->$color, 'buggedfile'=>(isset($user->conf->buggedfile) ? $user->conf->buggedfile : 0));
263		}
264	}
265}
266
267if (empty($action) || $action == 'show_month')
268{
269	$prev = dol_get_prev_month($month, $year);
270	$prev_year  = $prev['year'];
271	$prev_month = $prev['month'];
272	$next = dol_get_next_month($month, $year);
273	$next_year  = $next['year'];
274	$next_month = $next['month'];
275
276	$max_day_in_prev_month = date("t", dol_mktime(0, 0, 0, $prev_month, 1, $prev_year, 'gmt')); // Nb of days in previous month
277	$max_day_in_month = date("t", dol_mktime(0, 0, 0, $month, 1, $year)); // Nb of days in next month
278	// tmpday is a negative or null cursor to know how many days before the 1st to show on month view (if tmpday=0, 1st is monday)
279	$tmpday = -date("w", dol_mktime(12, 0, 0, $month, 1, $year, 'gmt')) + 2; // date('w') is 0 fo sunday
280	$tmpday += ((isset($conf->global->MAIN_START_WEEK) ? $conf->global->MAIN_START_WEEK : 1) - 1);
281	if ($tmpday >= 1) $tmpday -= 7; // If tmpday is 0 we start with sunday, if -6, we start with monday of previous week.
282	// Define firstdaytoshow and lastdaytoshow (warning: lastdaytoshow is last second to show + 1)
283	$firstdaytoshow = dol_mktime(0, 0, 0, $prev_month, $max_day_in_prev_month + $tmpday, $prev_year, 'tzuserrel');
284	$next_day = 7 - ($max_day_in_month + 1 - $tmpday) % 7;
285	if ($next_day < 6) $next_day += 7;
286	$lastdaytoshow = dol_mktime(0, 0, 0, $next_month, $next_day, $next_year, 'tzuserrel');
287}
288if ($action == 'show_week')
289{
290	$prev = dol_get_first_day_week($day, $month, $year);
291	$prev_year  = $prev['prev_year'];
292	$prev_month = $prev['prev_month'];
293	$prev_day   = $prev['prev_day'];
294	$first_day  = $prev['first_day'];
295	$first_month = $prev['first_month'];
296	$first_year = $prev['first_year'];
297
298	$week = $prev['week'];
299
300	$day = (int) $day;
301	$next = dol_get_next_week($first_day, $week, $first_month, $first_year);
302	$next_year  = $next['year'];
303	$next_month = $next['month'];
304	$next_day   = $next['day'];
305
306	// Define firstdaytoshow and lastdaytoshow (warning: lastdaytoshow is last second to show + 1)
307	$firstdaytoshow = dol_mktime(0, 0, 0, $first_month, $first_day, $first_year, 'tzuserrel');
308	$lastdaytoshow = dol_time_plus_duree($firstdaytoshow, 7, 'd');
309
310	$max_day_in_month = date("t", dol_mktime(0, 0, 0, $month, 1, $year, 'gmt'));
311
312	$tmpday = $first_day;
313}
314if ($action == 'show_day')
315{
316	$prev = dol_get_prev_day($day, $month, $year);
317	$prev_year  = $prev['year'];
318	$prev_month = $prev['month'];
319	$prev_day   = $prev['day'];
320	$next = dol_get_next_day($day, $month, $year);
321	$next_year  = $next['year'];
322	$next_month = $next['month'];
323	$next_day   = $next['day'];
324	// Define firstdaytoshow and lastdaytoshow (warning: lastdaytoshow is last second to show + 1)
325	$firstdaytoshow = dol_mktime(0, 0, 0, $prev_month, $prev_day, $prev_year, 'tzuserrel');
326	$lastdaytoshow = dol_mktime(0, 0, 0, $next_month, $next_day, $next_year, 'tzuserrel');
327}
328//print 'xx'.$prev_year.'-'.$prev_month.'-'.$prev_day;
329//print 'xx'.$next_year.'-'.$next_month.'-'.$next_day;
330//print dol_print_date($firstdaytoshow,'dayhour').' '.dol_print_date($lastdaytoshow,'dayhour');
331
332/*$title = $langs->trans("DoneAndToDoActions");
333if ($status == 'done') $title = $langs->trans("DoneActions");
334if ($status == 'todo') $title = $langs->trans("ToDoActions");
335*/
336
337$param = '';
338if ($actioncode || GETPOSTISSET('search_actioncode')) {
339	if (is_array($actioncode)) {
340		foreach ($actioncode as $str_action) $param .= "&search_actioncode[]=".urlencode($str_action);
341	} else $param .= "&search_actioncode=".urlencode($actioncode);
342}
343if ($resourceid > 0)  $param .= "&search_resourceid=".urlencode($resourceid);
344if ($status || GETPOSTISSET('status')) $param .= "&search_status=".urlencode($status);
345if ($filter)       $param .= "&search_filter=".urlencode($filter);
346if ($filtert)      $param .= "&search_filtert=".urlencode($filtert);
347if ($usergroup)    $param .= "&search_usergroup=".urlencode($usergroup);
348if ($socid)        $param .= "&search_socid=".urlencode($socid);
349if ($showbirthday) $param .= "&search_showbirthday=1";
350if ($pid)          $param .= "&search_projectid=".urlencode($pid);
351if ($type)         $param .= "&search_type=".urlencode($type);
352if ($action == 'show_day' || $action == 'show_week' || $action == 'show_month') $param .= '&action='.urlencode($action);
353$param .= "&maxprint=".urlencode($maxprint);
354
355// Show navigation bar
356if (empty($action) || $action == 'show_month')
357{
358	$nav = "<a href=\"?year=".$prev_year."&amp;month=".$prev_month.$param."\"><i class=\"fa fa-chevron-left\"></i></a> &nbsp;\n";
359	$nav .= " <span id=\"month_name\">".dol_print_date(dol_mktime(0, 0, 0, $month, 1, $year), "%b %Y");
360	$nav .= " </span>\n";
361	$nav .= " &nbsp; <a href=\"?year=".$next_year."&amp;month=".$next_month.$param."\"><i class=\"fa fa-chevron-right\"></i></a>\n";
362	if (empty($conf->dol_optimize_smallscreen)) {
363		$nav .= " &nbsp; <a href=\"?year=".$nowyear."&amp;month=".$nowmonth.$param."\">".$langs->trans("Today")."</a> ";
364	}
365	$picto = 'calendar';
366}
367if ($action == 'show_week')
368{
369	$nav = "<a href=\"?year=".$prev_year."&amp;month=".$prev_month."&amp;day=".$prev_day.$param."\"><i class=\"fa fa-chevron-left\" title=\"".dol_escape_htmltag($langs->trans("Previous"))."\"></i></a> &nbsp;\n";
370	$nav .= " <span id=\"month_name\">".dol_print_date(dol_mktime(0, 0, 0, $first_month, $first_day, $first_year), "%Y").", ".$langs->trans("Week")." ".$week;
371	$nav .= " </span>\n";
372	$nav .= " &nbsp; <a href=\"?year=".$next_year."&amp;month=".$next_month."&amp;day=".$next_day.$param."\"><i class=\"fa fa-chevron-right\" title=\"".dol_escape_htmltag($langs->trans("Next"))."\"></i></a>\n";
373	if (empty($conf->dol_optimize_smallscreen)) {
374		$nav .= " &nbsp; <a href=\"?year=".$nowyear."&amp;month=".$nowmonth."&amp;day=".$nowday.$param."\">".$langs->trans("Today")."</a> ";
375	}
376	$picto = 'calendarweek';
377}
378if ($action == 'show_day')
379{
380	$nav = "<a href=\"?year=".$prev_year."&amp;month=".$prev_month."&amp;day=".$prev_day.$param."\"><i class=\"fa fa-chevron-left\"></i></a> &nbsp;\n";
381	$nav .= " <span id=\"month_name\">".dol_print_date(dol_mktime(0, 0, 0, $month, $day, $year), "daytextshort");
382	$nav .= " </span>\n";
383	$nav .= " &nbsp; <a href=\"?year=".$next_year."&amp;month=".$next_month."&amp;day=".$next_day.$param."\"><i class=\"fa fa-chevron-right\"></i></a>\n";
384	if (empty($conf->dol_optimize_smallscreen)) {
385		$nav .= " &nbsp; <a href=\"?year=".$nowyear."&amp;month=".$nowmonth."&amp;day=".$nowday.$param."\">".$langs->trans("Today")."</a> ";
386	}
387	$picto = 'calendarday';
388}
389
390$nav .= $form->selectDate($dateselect, 'dateselect', 0, 0, 1, '', 1, 0);
391//$nav .= ' <input type="submit" name="submitdateselect" class="button" value="'.$langs->trans("Refresh").'">';
392$nav .= '<button type="submit" class="liste_titre button_search" name="button_search_x" value="x"><span class="fa fa-search"></span></button>';
393
394// Must be after the nav definition
395$param .= '&year='.$year.'&month='.$month.($day ? '&day='.$day : '');
396//print 'x'.$param;
397
398
399
400
401/*$tabactive = '';
402if ($action == 'show_month') $tabactive = 'cardmonth';
403if ($action == 'show_week') $tabactive = 'cardweek';
404if ($action == 'show_day')  $tabactive = 'cardday';
405if ($action == 'show_list') $tabactive = 'cardlist';
406if ($action == 'show_pertuser') $tabactive = 'cardperuser';
407if ($action == 'show_pertype') $tabactive = 'cardpertype';
408*/
409
410$paramnoaction = preg_replace('/action=[a-z_]+/', '', $param);
411
412$head = calendars_prepare_head($paramnoaction);
413
414print '<form method="POST" id="searchFormList" class="listactionsfilter" action="'.$_SERVER["PHP_SELF"].'">'."\n";
415if ($optioncss != '') print '<input type="hidden" name="optioncss" value="'.$optioncss.'">';
416print '<input type="hidden" name="token" value="'.newToken().'">';
417
418//print dol_get_fiche_head($head, $tabactive, $langs->trans('Agenda'), 0, 'action');
419//print_actions_filter($form, $canedit, $status, $year, $month, $day, $showbirthday, 0, $filtert, 0, $pid, $socid, $action, $listofextcals, $actioncode, $usergroup, '', $resourceid);
420//print dol_get_fiche_end();
421
422$viewmode = '';
423$viewmode .= '<a class="btnTitle reposition" href="'.DOL_URL_ROOT.'/comm/action/list.php?action=show_list&restore_lastsearch_values=1">';
424//$viewmode .= '<span class="fa paddingleft imgforviewmode valignmiddle btnTitle-icon">';
425$viewmode .= img_picto($langs->trans("List"), 'object_list-alt', 'class="pictoactionview block"');
426//$viewmode .= '</span>';
427$viewmode .= '<span class="valignmiddle text-plus-circle btnTitle-label hideonsmartphone">'.$langs->trans("ViewList").'</span></a>';
428
429$viewmode .= '<a class="btnTitle'.($action == 'show_month' ? ' btnTitleSelected' : '').' reposition" href="'.DOL_URL_ROOT.'/comm/action/index.php?action=show_month&year='.dol_print_date($object->datep, '%Y').'&month='.dol_print_date($object->datep, '%m').'&day='.dol_print_date($object->datep, '%d').'">';
430//$viewmode .= '<span class="fa paddingleft imgforviewmode valignmiddle btnTitle-icon">';
431$viewmode .= img_picto($langs->trans("ViewCal"), 'object_calendar', 'class="pictoactionview block"');
432//$viewmode .= '</span>';
433$viewmode .= '<span class="valignmiddle text-plus-circle btnTitle-label hideonsmartphone">'.$langs->trans("ViewCal").'</span></a>';
434
435$viewmode .= '<a class="btnTitle'.($action == 'show_week' ? ' btnTitleSelected' : '').' reposition" href="'.DOL_URL_ROOT.'/comm/action/index.php?action=show_week&year='.dol_print_date($object->datep, '%Y').'&month='.dol_print_date($object->datep, '%m').'&day='.dol_print_date($object->datep, '%d').'">';
436//$viewmode .= '<span class="fa paddingleft imgforviewmode valignmiddle btnTitle-icon">';
437$viewmode .= img_picto($langs->trans("ViewWeek"), 'object_calendarweek', 'class="pictoactionview block"');
438//$viewmode .= '</span>';
439$viewmode .= '<span class="valignmiddle text-plus-circle btnTitle-label hideonsmartphone">'.$langs->trans("ViewWeek").'</span></a>';
440
441$viewmode .= '<a class="btnTitle'.($action == 'show_day' ? ' btnTitleSelected' : '').' reposition" href="'.DOL_URL_ROOT.'/comm/action/index.php?action=show_day&year='.dol_print_date($object->datep, '%Y').'&month='.dol_print_date($object->datep, '%m').'&day='.dol_print_date($object->datep, '%d').'">';
442//$viewmode .= '<span class="fa paddingleft imgforviewmode valignmiddle btnTitle-icon">';
443$viewmode .= img_picto($langs->trans("ViewDay"), 'object_calendarday', 'class="pictoactionview block"');
444//$viewmode .= '</span>';
445$viewmode .= '<span class="valignmiddle text-plus-circle btnTitle-label hideonsmartphone">'.$langs->trans("ViewDay").'</span></a>';
446
447$viewmode .= '<a class="btnTitle reposition marginrightonly" href="'.DOL_URL_ROOT.'/comm/action/peruser.php?action=show_peruser&year='.dol_print_date($object->datep, '%Y').'&month='.dol_print_date($object->datep, '%m').'&day='.dol_print_date($object->datep, '%d').'">';
448//$viewmode .= '<span class="fa paddingleft imgforviewmode valignmiddle btnTitle-icon">';
449$viewmode .= img_picto($langs->trans("ViewPerUser"), 'object_calendarperuser', 'class="pictoactionview block"');
450//$viewmode .= '</span>';
451$viewmode .= '<span class="valignmiddle text-plus-circle btnTitle-label hideonsmartphone">'.$langs->trans("ViewPerUser").'</span></a>';
452
453$viewmode .= '<span class="marginrightonly"></span>';
454
455// Add more views from hooks
456$parameters = array(); $object = null;
457$reshook = $hookmanager->executeHooks('addCalendarView', $parameters, $object, $action);
458if (empty($reshook)) {
459	$viewmode .= $hookmanager->resPrint;
460} elseif ($reshook > 1) {
461	$viewmode = $hookmanager->resPrint;
462}
463
464
465$newcardbutton = '';
466if ($user->rights->agenda->myactions->create || $user->rights->agenda->allactions->create)
467{
468	$tmpforcreatebutton = dol_getdate(dol_now(), true);
469
470	$newparam .= '&month='.str_pad($month, 2, "0", STR_PAD_LEFT).'&year='.$tmpforcreatebutton['year'];
471
472	//$param='month='.$monthshown.'&year='.$year;
473	$hourminsec = '100000';
474	$newcardbutton .= dolGetButtonTitle($langs->trans("AddAction"), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/comm/action/card.php?action=create&datep='.sprintf("%04d%02d%02d", $tmpforcreatebutton['year'], $tmpforcreatebutton['mon'], $tmpforcreatebutton['mday']).$hourminsec.'&backtopage='.urlencode($_SERVER["PHP_SELF"].($newparam ? '?'.$newparam : '')));
475}
476
477// Define the legend/list of calendard to show
478$s = ''; $link = '';
479
480$showextcals = $listofextcals;
481
482if (!empty($conf->use_javascript_ajax))	// If javascript on
483{
484	$s .= "\n".'<!-- Div to calendars selectors -->'."\n";
485	$s .= '<script type="text/javascript">'."\n";
486	$s .= 'jQuery(document).ready(function () {'."\n";
487	$s .= 'jQuery(".check_birthday").click(function() { console.log("Toggle birthday"); jQuery(".family_birthday").toggle(); });'."\n";
488	$s .= 'jQuery(".family_birthday").toggle();'."\n";
489	if ($action == "show_week" || $action == "show_month" || empty($action))
490	{
491		// Code to enable drag and drop
492		$s .= 'jQuery( "div.sortable" ).sortable({connectWith: ".sortable", placeholder: "ui-state-highlight", items: "div.movable", receive: function( event, ui ) {'."\n";
493		// Code to submit form
494		$s .= 'console.log("submit form to record new event");'."\n";
495		//$s.='console.log(event.target);';
496		$s .= 'var newval = jQuery(event.target).closest("div.dayevent").attr("id");'."\n";
497		$s .= 'console.log("found parent div.dayevent with id = "+newval);'."\n";
498		$s .= 'var frm=jQuery("#searchFormList");'."\n";
499		$s .= 'var newurl = ui.item.find("a.cal_event").attr("href");'."\n";
500		$s .= 'console.log(newurl);'."\n";
501		$s .= 'frm.attr("action", newurl).children("#newdate").val(newval);frm.submit();}'."\n";
502		$s .= '});'."\n";
503	}
504	$s .= '});'."\n";
505	$s .= '</script>'."\n";
506
507	// Local calendar
508	$s .= '<div class="nowrap inline-block minheight30"><input type="checkbox" id="check_mytasks" name="check_mytasks" checked disabled> '.$langs->trans("LocalAgenda").' &nbsp; </div>';
509
510	// External calendars
511	if (is_array($showextcals) && count($showextcals) > 0)
512	{
513		$s .= '<script type="text/javascript">'."\n";
514		$s .= 'jQuery(document).ready(function () {
515				jQuery("div input[name^=\"check_ext\"]").click(function() {
516					var name = $(this).attr("name");
517					jQuery(".family_ext" + name.replace("check_ext", "")).toggle();
518				});
519			});' . "\n";
520		$s .= '</script>'."\n";
521
522		foreach ($showextcals as $val)
523		{
524			$htmlname = md5($val['name']);
525			$s .= '<div class="nowrap inline-block"><input type="checkbox" id="check_ext'.$htmlname.'" name="check_ext'.$htmlname.'" checked> <label for="check_ext'.$htmlname.'">'.$val['name'].'</label> &nbsp; </div>';
526		}
527	}
528
529	// Birthdays
530	$s .= '<div class="nowrap inline-block"><input type="checkbox" id="check_birthday" name="check_birthday" class="check_birthday"><label for="check_birthday"> <span class="check_birthday_text">'.$langs->trans("AgendaShowBirthdayEvents").'</span></label> &nbsp; </div>';
531
532	// Calendars from hooks
533	$parameters = array(); $object = null;
534	$reshook = $hookmanager->executeHooks('addCalendarChoice', $parameters, $object, $action);
535	if (empty($reshook))
536	{
537		$s .= $hookmanager->resPrint;
538	} elseif ($reshook > 1)
539	{
540		$s = $hookmanager->resPrint;
541	}
542} else // If javascript off
543{
544	$newparam = $param; // newparam is for birthday links
545	$newparam = preg_replace('/showbirthday=[0-1]/i', 'showbirthday='.(empty($showbirthday) ? 1 : 0), $newparam);
546	if (!preg_match('/showbirthday=/i', $newparam)) $newparam .= '&showbirthday=1';
547	$link = '<a href="'.dol_escape_htmltag($_SERVER['PHP_SELF']);
548	$link .= '?'.dol_escape_htmltag($newparam);
549	$link .= '">';
550	if (empty($showbirthday)) $link .= $langs->trans("AgendaShowBirthdayEvents");
551	else $link .= $langs->trans("AgendaHideBirthdayEvents");
552	$link .= '</a>';
553}
554
555// Load events from database into $eventarray
556$eventarray = array();
557
558$sql = 'SELECT ';
559if ($usergroup > 0) $sql .= " DISTINCT";
560$sql .= ' a.id, a.label,';
561$sql .= ' a.datep,';
562$sql .= ' a.datep2,';
563$sql .= ' a.percent,';
564$sql .= ' a.fk_user_author,a.fk_user_action,';
565$sql .= ' a.transparency, a.priority, a.fulldayevent, a.location,';
566$sql .= ' a.fk_soc, a.fk_contact, a.fk_project,';
567$sql .= ' a.fk_element, a.elementtype,';
568$sql .= ' ca.code as type_code, ca.libelle as type_label, ca.color as type_color';
569$sql .= ' FROM '.MAIN_DB_PREFIX.'c_actioncomm as ca, '.MAIN_DB_PREFIX."actioncomm as a";
570if (!$user->rights->societe->client->voir && !$socid) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON a.fk_soc = sc.fk_soc";
571// We must filter on resource table
572if ($resourceid > 0) $sql .= ", ".MAIN_DB_PREFIX."element_resources as r";
573// We must filter on assignement table
574if ($filtert > 0 || $usergroup > 0) $sql .= ", ".MAIN_DB_PREFIX."actioncomm_resources as ar";
575if ($usergroup > 0) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."usergroup_user as ugu ON ugu.fk_user = ar.fk_element";
576$sql .= ' WHERE a.fk_action = ca.id';
577$sql .= ' AND a.entity IN ('.getEntity('agenda').')';
578// Condition on actioncode
579if (!empty($actioncode))
580{
581	if (empty($conf->global->AGENDA_USE_EVENT_TYPE))
582	{
583		if ($actioncode == 'AC_NON_AUTO') $sql .= " AND ca.type != 'systemauto'";
584		elseif ($actioncode == 'AC_ALL_AUTO') $sql .= " AND ca.type = 'systemauto'";
585		else {
586			if ($actioncode == 'AC_OTH') $sql .= " AND ca.type != 'systemauto'";
587			if ($actioncode == 'AC_OTH_AUTO') $sql .= " AND ca.type = 'systemauto'";
588		}
589	} else {
590		if ($actioncode == 'AC_NON_AUTO') $sql .= " AND ca.type != 'systemauto'";
591		elseif ($actioncode == 'AC_ALL_AUTO') $sql .= " AND ca.type = 'systemauto'";
592		else {
593			if (is_array($actioncode))
594			{
595				$sql .= " AND ca.code IN ('".implode("','", $actioncode)."')";
596			} else {
597				$sql .= " AND ca.code IN ('".implode("','", explode(',', $actioncode))."')";
598			}
599		}
600	}
601}
602if ($resourceid > 0) $sql .= " AND r.element_type = 'action' AND r.element_id = a.id AND r.resource_id = ".$db->escape($resourceid);
603if ($pid) $sql .= " AND a.fk_project=".$db->escape($pid);
604if (!$user->rights->societe->client->voir && !$socid) $sql .= " AND (a.fk_soc IS NULL OR sc.fk_user = ".$user->id.")";
605if ($socid > 0) $sql .= ' AND a.fk_soc = '.$socid;
606// We must filter on assignement table
607if ($filtert > 0 || $usergroup > 0) $sql .= " AND ar.fk_actioncomm = a.id AND ar.element_type='user'";
608//var_dump($day.' '.$month.' '.$year);
609if ($action == 'show_day')
610{
611	$sql .= " AND (";
612	$sql .= " (a.datep BETWEEN '".$db->idate(dol_mktime(0, 0, 0, $month, $day, $year, 'tzuserrel'))."'";
613	$sql .= " AND '".$db->idate(dol_mktime(23, 59, 59, $month, $day, $year, 'tzuserrel'))."')";
614	$sql .= " OR ";
615	$sql .= " (a.datep2 BETWEEN '".$db->idate(dol_mktime(0, 0, 0, $month, $day, $year, 'tzuserrel'))."'";
616	$sql .= " AND '".$db->idate(dol_mktime(23, 59, 59, $month, $day, $year, 'tzuserrel'))."')";
617	$sql .= " OR ";
618	$sql .= " (a.datep < '".$db->idate(dol_mktime(0, 0, 0, $month, $day, $year, 'tzuserrel'))."'";
619	$sql .= " AND a.datep2 > '".$db->idate(dol_mktime(23, 59, 59, $month, $day, $year, 'tzuserrel'))."')";
620	$sql .= ')';
621} else {
622	// To limit array
623	$sql .= " AND (";
624	$sql .= " (a.datep BETWEEN '".$db->idate(dol_mktime(0, 0, 0, $month, 1, $year) - (60 * 60 * 24 * 7))."'"; // Start 7 days before
625	$sql .= " AND '".$db->idate(dol_mktime(23, 59, 59, $month, 28, $year) + (60 * 60 * 24 * 10))."')"; // End 7 days after + 3 to go from 28 to 31
626	$sql .= " OR ";
627	$sql .= " (a.datep2 BETWEEN '".$db->idate(dol_mktime(0, 0, 0, $month, 1, $year) - (60 * 60 * 24 * 7))."'";
628	$sql .= " AND '".$db->idate(dol_mktime(23, 59, 59, $month, 28, $year) + (60 * 60 * 24 * 10))."')";
629	$sql .= " OR ";
630	$sql .= " (a.datep < '".$db->idate(dol_mktime(0, 0, 0, $month, 1, $year) - (60 * 60 * 24 * 7))."'";
631	$sql .= " AND a.datep2 > '".$db->idate(dol_mktime(23, 59, 59, $month, 28, $year) + (60 * 60 * 24 * 10))."')";
632	$sql .= ')';
633}
634if ($type) $sql .= " AND ca.id = ".$type;
635if ($status == '0') { $sql .= " AND a.percent = 0"; }
636if ($status == '-1') { $sql .= " AND a.percent = -1"; }	// Not applicable
637if ($status == '50') { $sql .= " AND (a.percent > 0 AND a.percent < 100)"; }	// Running already started
638if ($status == 'done' || $status == '100') { $sql .= " AND (a.percent = 100)"; }
639if ($status == 'todo') { $sql .= " AND (a.percent >= 0 AND a.percent < 100)"; }
640// We must filter on assignement table
641if ($filtert > 0 || $usergroup > 0)
642{
643	$sql .= " AND (";
644	if ($filtert > 0) $sql .= "ar.fk_element = ".$filtert;
645	if ($usergroup > 0) $sql .= ($filtert > 0 ? " OR " : "")." ugu.fk_usergroup = ".$usergroup;
646	$sql .= ")";
647}
648// Sort on date
649$sql .= ' ORDER BY datep';
650//print $sql;
651
652
653dol_syslog("comm/action/index.php", LOG_DEBUG);
654$resql = $db->query($sql);
655if ($resql)
656{
657	$num = $db->num_rows($resql);
658
659	$MAXONSAMEPAGE = 10000; // Useless to have more. Protection to avoid memory overload when high number of event (for example after a mass import)
660	$i = 0;
661	while ($i < $num && $i < $MAXONSAMEPAGE)
662	{
663		$obj = $db->fetch_object($resql);
664
665		// Discard auto action if option is on
666		if (!empty($conf->global->AGENDA_ALWAYS_HIDE_AUTO) && $obj->type_code == 'AC_OTH_AUTO')
667		{
668			$i++;
669			continue;
670		}
671
672		// Create a new object action
673		$event = new ActionComm($db);
674
675		$event->id = $obj->id;
676		$event->ref = $event->id;
677
678		$event->datep = $db->jdate($obj->datep); // datep and datef are GMT date. Example: 1970-01-01 01:00:00, jdate will return 0 if TZ of PHP server is Europe/Berlin
679		$event->datef = $db->jdate($obj->datep2);
680		//$event->datep_formated_gmt = dol_print_date($event->datep, 'dayhour', 'gmt');
681		//var_dump($obj->datep);
682		//var_dump($event->datep);
683
684		$event->type_code = $obj->type_code;
685		$event->type_label = $obj->type_label;
686		$event->type_color = $obj->type_color;
687
688		$event->libelle = $obj->label; // deprecated
689		$event->label = $obj->label;
690		$event->percentage = $obj->percent;
691		$event->authorid = $obj->fk_user_author; // user id of creator
692		$event->userownerid = $obj->fk_user_action; // user id of owner
693		$event->fetch_userassigned(); // This load $event->userassigned
694		$event->priority = $obj->priority;
695		$event->fulldayevent = $obj->fulldayevent;
696		$event->location = $obj->location;
697		$event->transparency = $obj->transparency;
698		$event->fk_element = $obj->fk_element;
699		$event->elementtype = $obj->elementtype;
700
701		$event->fk_project = $obj->fk_project;
702
703		$event->thirdparty_id = $obj->fk_soc;
704		$event->contact_id = $obj->fk_contact;
705
706		// Defined date_start_in_calendar and date_end_in_calendar property
707		// They are date start and end of action but modified to not be outside calendar view.
708		$event->date_start_in_calendar = $event->datep;
709		if ($event->datef != '' && $event->datef >= $event->datep) $event->date_end_in_calendar = $event->datef;
710		else $event->date_end_in_calendar = $event->datep;
711		// Define ponctual property
712		if ($event->date_start_in_calendar == $event->date_end_in_calendar)
713		{
714			$event->ponctuel = 1;
715		}
716
717		// Check values
718		if ($event->date_end_in_calendar < $firstdaytoshow || $event->date_start_in_calendar >= $lastdaytoshow)	{
719			// This record is out of visible range
720		} else {
721			if ($event->date_start_in_calendar < $firstdaytoshow) $event->date_start_in_calendar = $firstdaytoshow;
722			if ($event->date_end_in_calendar >= $lastdaytoshow) $event->date_end_in_calendar = ($lastdaytoshow - 1);
723
724			// Add an entry in actionarray for each day
725			$daycursor = $event->date_start_in_calendar;
726			$annee = dol_print_date($daycursor, '%Y', 'tzuserrel');
727			$mois = dol_print_date($daycursor, '%m', 'tzuserrel');
728			$jour = dol_print_date($daycursor, '%d', 'tzuserrel');
729			//var_dump(dol_print_date($event->date_start_in_calendar, 'dayhour', 'gmt'));	// Hour at greenwich
730			//var_dump($annee.'-'.$mois.'-'.$jour);
731
732			// Loop on each day covered by action to prepare an index to show on calendar
733			$loop = true; $j = 0;
734			$daykey = dol_mktime(0, 0, 0, $mois, $jour, $annee, 'gmt');
735			do {
736				//if ($event->id==408)
737				//print 'daykey='.$daykey.' '.dol_print_date($daykey, 'dayhour', 'gmt').' '.$event->datep.' '.$event->datef.'<br>';
738
739				$eventarray[$daykey][] = $event;
740				$j++;
741
742				$daykey += 60 * 60 * 24;
743				if ($daykey > $event->date_end_in_calendar) $loop = false;
744			} while ($loop);
745
746			//print 'Event '.$i.' id='.$event->id.' (start='.dol_print_date($event->datep).'-end='.dol_print_date($event->datef);
747			//print ' startincalendar='.dol_print_date($event->date_start_in_calendar).'-endincalendar='.dol_print_date($event->date_end_in_calendar).') was added in '.$j.' different index key of array<br>';
748		}
749		$i++;
750	}
751} else {
752	dol_print_error($db);
753}
754//var_dump($eventarray);
755
756// Complete $eventarray with birthdates
757if ($showbirthday)
758{
759	// Add events in array
760	$sql = 'SELECT sp.rowid, sp.lastname, sp.firstname, sp.birthday';
761	$sql .= ' FROM '.MAIN_DB_PREFIX.'socpeople as sp';
762	$sql .= ' WHERE (priv=0 OR (priv=1 AND fk_user_creat='.$user->id.'))';
763	$sql .= " AND sp.entity IN (".getEntity('socpeople').")";
764	if ($action == 'show_day')
765	{
766		$sql .= ' AND MONTH(birthday) = '.$month;
767		$sql .= ' AND DAY(birthday) = '.$day;
768	} else {
769		$sql .= ' AND MONTH(birthday) = '.$month;
770	}
771	$sql .= ' ORDER BY birthday';
772
773	dol_syslog("comm/action/index.php", LOG_DEBUG);
774	$resql = $db->query($sql);
775	if ($resql)
776	{
777		$num = $db->num_rows($resql);
778		$i = 0;
779		while ($i < $num)
780		{
781			$obj = $db->fetch_object($resql);
782			$event = new ActionComm($db);
783
784			$event->id = $obj->rowid; // We put contact id in action id for birthdays events
785			$event->ref = $event->id;
786
787			$datebirth = dol_stringtotime($obj->birthday, 1);
788			//print 'ee'.$obj->birthday.'-'.$datebirth;
789			$datearray = dol_getdate($datebirth, true);
790			$event->datep = dol_mktime(0, 0, 0, $datearray['mon'], $datearray['mday'], $year, true); // For full day events, date are also GMT but they wont but converted during output
791			$event->datef = $event->datep;
792			$event->type_code = 'BIRTHDAY';
793			$event->label = $langs->trans("Birthday").' '.dolGetFirstLastname($obj->firstname, $obj->lastname);
794			$event->percentage = 100;
795			$event->fulldayevent = 1;
796
797			$event->date_start_in_calendar = $event->datep;
798			$event->date_end_in_calendar = $event->datef;
799			$event->ponctuel = 0;
800
801			// Add an entry in actionarray for each day
802			$daycursor = $event->date_start_in_calendar;
803			$annee = dol_print_date($daycursor, '%Y');
804			$mois = dol_print_date($daycursor, '%m');
805			$jour = dol_print_date($daycursor, '%d');
806
807			$loop = true;
808			$daykey = dol_mktime(0, 0, 0, $mois, $jour, $annee);
809			do {
810				$eventarray[$daykey][] = $event;
811				$daykey += 60 * 60 * 24;
812				if ($daykey > $event->date_end_in_calendar) $loop = false;
813			} while ($loop);
814			$i++;
815		}
816	} else {
817		dol_print_error($db);
818	}
819}
820
821if ($conf->global->AGENDA_SHOW_HOLIDAYS)
822{
823	$sql = "SELECT u.rowid as uid, u.lastname, u.firstname, u.statut, x.rowid, x.date_debut as date_start, x.date_fin as date_end, x.halfday, x.statut as status";
824	$sql .= " FROM ".MAIN_DB_PREFIX."holiday as x, ".MAIN_DB_PREFIX."user as u";
825	$sql .= " WHERE u.rowid = x.fk_user";
826	$sql .= " AND u.statut = '1'"; // Show only active users  (0 = inactive user, 1 = active user)
827	$sql .= " AND (x.statut = '2' OR x.statut = '3')"; // Show only public leaves (2 = leave wait for approval, 3 = leave approved)
828
829	if ($action == 'show_day') {
830		// Request only leaves for the current selected day
831		$sql .= " AND '".$db->escape($year)."-".$db->escape($month)."-".$db->escape($day)."' BETWEEN x.date_debut AND x.date_fin";	// date_debut and date_fin are date without time
832	} elseif ($action == 'show_week') {
833		// TODO: Add filter to reduce database request
834	} elseif ($action == 'show_month') {
835		// TODO: Add filter to reduce database request
836	}
837
838	$resql = $db->query($sql);
839	if ($resql)
840	{
841		$num = $db->num_rows($resql);
842		$i   = 0;
843
844		while ($i < $num)
845		{
846			$obj = $db->fetch_object($resql);
847
848			$dateStartArray = dol_getdate(dol_stringtotime($obj->date_start, 1), true);
849			$dateEndArray   = dol_getdate(dol_stringtotime($obj->date_end, 1), true);
850
851			$event = new ActionComm($db);
852
853			// Need the id of the leave object for link to it
854			$event->id                      = $obj->rowid;
855			$event->ref                     = $event->id;
856
857			$event->type_code               = 'HOLIDAY';
858			$event->datep                   = dol_mktime(0, 0, 0, $dateStartArray['mon'], $dateStartArray['mday'], $dateStartArray['year'], true);
859			$event->datef                   = dol_mktime(0, 0, 0, $dateEndArray['mon'], $dateEndArray['mday'], $dateEndArray['year'], true);
860			$event->date_start_in_calendar  = $event->datep;
861			$event->date_end_in_calendar    = $event->datef;
862
863			if ($obj->status == 3)
864			{
865				// Show no symbol for leave with state "leave approved"
866				$event->percentage = -1;
867			} elseif ($obj->status == 2)
868			{
869				// Show TO-DO symbol for leave with state "leave wait for approval"
870				$event->percentage = 0;
871			}
872
873			if ($obj->halfday == 1)
874			{
875				$event->label = $obj->lastname.' ('.$langs->trans("Morning").')';
876			} elseif ($obj->halfday == -1)
877			{
878				$event->label = $obj->lastname.' ('.$langs->trans("Afternoon").')';
879			} else {
880				$event->label = $obj->lastname;
881			}
882
883			$daycursor = $event->date_start_in_calendar;
884			$annee = dol_print_date($daycursor, '%Y');
885			$mois = dol_print_date($daycursor, '%m');
886			$jour = dol_print_date($daycursor, '%d');
887
888			$daykey = dol_mktime(0, 0, 0, $mois, $jour, $annee);
889
890			do {
891				$eventarray[$daykey][] = $event;
892
893				$daykey += 60 * 60 * 24;
894			} while ($daykey <= $event->date_end_in_calendar);
895
896			$i++;
897		}
898	}
899}
900
901// Complete $eventarray with external import Ical
902if (count($listofextcals))
903{
904	require_once DOL_DOCUMENT_ROOT.'/comm/action/class/ical.class.php';
905	foreach ($listofextcals as $extcal)
906	{
907		$url = $extcal['src']; // Example: https://www.google.com/calendar/ical/eldy10%40gmail.com/private-cde92aa7d7e0ef6110010a821a2aaeb/basic.ics
908		$namecal = $extcal['name'];
909		$offsettz = $extcal['offsettz'];
910		$colorcal = $extcal['color'];
911		$buggedfile = $extcal['buggedfile'];
912		//print "url=".$url." namecal=".$namecal." colorcal=".$colorcal." buggedfile=".$buggedfile;
913		$ical = new ICal();
914		$ical->parse($url);
915
916		// After this $ical->cal['VEVENT'] contains array of events, $ical->cal['DAYLIGHT'] contains daylight info, $ical->cal['STANDARD'] contains non daylight info, ...
917		//var_dump($ical->cal); exit;
918		$icalevents = array();
919		if (is_array($ical->get_event_list())) $icalevents = array_merge($icalevents, $ical->get_event_list()); // Add $ical->cal['VEVENT']
920		if (is_array($ical->get_freebusy_list())) $icalevents = array_merge($icalevents, $ical->get_freebusy_list()); // Add $ical->cal['VFREEBUSY']
921
922		if (count($icalevents) > 0)
923		{
924			// Duplicate all repeatable events into new entries
925			$moreicalevents = array();
926			foreach ($icalevents as $icalevent)
927			{
928				if (isset($icalevent['RRULE']) && is_array($icalevent['RRULE'])) //repeatable event
929				{
930					//if ($event->date_start_in_calendar < $firstdaytoshow) $event->date_start_in_calendar=$firstdaytoshow;
931					//if ($event->date_end_in_calendar > $lastdaytoshow) $event->date_end_in_calendar=($lastdaytoshow-1);
932					if ($icalevent['DTSTART;VALUE=DATE']) //fullday event
933					{
934						$datecurstart = dol_stringtotime($icalevent['DTSTART;VALUE=DATE'], 1);
935						$datecurend = dol_stringtotime($icalevent['DTEND;VALUE=DATE'], 1) - 1; // We remove one second to get last second of day
936					} elseif (is_array($icalevent['DTSTART']) && !empty($icalevent['DTSTART']['unixtime']))
937					{
938						$datecurstart = $icalevent['DTSTART']['unixtime'];
939						$datecurend = $icalevent['DTEND']['unixtime'];
940						if (!empty($ical->cal['DAYLIGHT']['DTSTART']) && $datecurstart)
941						{
942							//var_dump($ical->cal);
943							$tmpcurstart = $datecurstart;
944							$tmpcurend = $datecurend;
945							$tmpdaylightstart = dol_mktime(0, 0, 0, 1, 1, 1970, 1) + (int) $ical->cal['DAYLIGHT']['DTSTART'];
946							$tmpdaylightend = dol_mktime(0, 0, 0, 1, 1, 1970, 1) + (int) $ical->cal['STANDARD']['DTSTART'];
947							//var_dump($tmpcurstart);var_dump($tmpcurend); var_dump($ical->cal['DAYLIGHT']['DTSTART']);var_dump($ical->cal['STANDARD']['DTSTART']);
948							// Edit datecurstart and datecurend
949							if ($tmpcurstart >= $tmpdaylightstart && $tmpcurstart < $tmpdaylightend) $datecurstart -= ((int) $ical->cal['DAYLIGHT']['TZOFFSETTO']) * 36;
950							else $datecurstart -= ((int) $ical->cal['STANDARD']['TZOFFSETTO']) * 36;
951							if ($tmpcurend >= $tmpdaylightstart && $tmpcurstart < $tmpdaylightend) $datecurend -= ((int) $ical->cal['DAYLIGHT']['TZOFFSETTO']) * 36;
952							else $datecurend -= ((int) $ical->cal['STANDARD']['TZOFFSETTO']) * 36;
953						}
954						// datecurstart and datecurend are now GMT date
955						//var_dump($datecurstart); var_dump($datecurend); exit;
956					} else {
957						// Not a recongized record
958						dol_syslog("Found a not recognized repeatable record with unknown date start", LOG_ERR);
959						continue;
960					}
961					//print 'xx'.$datecurstart;exit;
962
963					$interval = (empty($icalevent['RRULE']['INTERVAL']) ? 1 : $icalevent['RRULE']['INTERVAL']);
964					$until = empty($icalevent['RRULE']['UNTIL']) ? 0 : dol_stringtotime($icalevent['RRULE']['UNTIL'], 1);
965					$maxrepeat = empty($icalevent['RRULE']['COUNT']) ? 0 : $icalevent['RRULE']['COUNT'];
966					if ($until && ($until + ($datecurend - $datecurstart)) < $firstdaytoshow) continue; // We discard repeatable event that end before start date to show
967					if ($datecurstart >= $lastdaytoshow) continue; // We discard repeatable event that start after end date to show
968
969					$numofevent = 0;
970					while (($datecurstart < $lastdaytoshow) && (empty($maxrepeat) || ($numofevent < $maxrepeat)))
971					{
972						if ($datecurend >= $firstdaytoshow)    // We add event
973						{
974							$newevent = $icalevent;
975							unset($newevent['RRULE']);
976							if ($icalevent['DTSTART;VALUE=DATE'])
977							{
978								$newevent['DTSTART;VALUE=DATE'] = dol_print_date($datecurstart, '%Y%m%d');
979								$newevent['DTEND;VALUE=DATE'] = dol_print_date($datecurend + 1, '%Y%m%d');
980							} else {
981								$newevent['DTSTART'] = $datecurstart;
982								$newevent['DTEND'] = $datecurend;
983							}
984							$moreicalevents[] = $newevent;
985						}
986						// Jump on next occurence
987						$numofevent++;
988						$savdatecurstart = $datecurstart;
989						if ($icalevent['RRULE']['FREQ'] == 'DAILY')
990						{
991							$datecurstart = dol_time_plus_duree($datecurstart, $interval, 'd');
992							$datecurend = dol_time_plus_duree($datecurend, $interval, 'd');
993						}
994						if ($icalevent['RRULE']['FREQ'] == 'WEEKLY')
995						{
996							$datecurstart = dol_time_plus_duree($datecurstart, $interval, 'w');
997							$datecurend = dol_time_plus_duree($datecurend, $interval, 'w');
998						} elseif ($icalevent['RRULE']['FREQ'] == 'MONTHLY')
999						{
1000							$datecurstart = dol_time_plus_duree($datecurstart, $interval, 'm');
1001							$datecurend = dol_time_plus_duree($datecurend, $interval, 'm');
1002						} elseif ($icalevent['RRULE']['FREQ'] == 'YEARLY')
1003						{
1004							$datecurstart = dol_time_plus_duree($datecurstart, $interval, 'y');
1005							$datecurend = dol_time_plus_duree($datecurend, $interval, 'y');
1006						}
1007						// Test to avoid infinite loop ($datecurstart must increase)
1008						if ($savdatecurstart >= $datecurstart)
1009						{
1010							dol_syslog("Found a rule freq ".$icalevent['RRULE']['FREQ']." not managed by dolibarr code. Assume 1 week frequency.", LOG_ERR);
1011							$datecurstart += 3600 * 24 * 7;
1012							$datecurend += 3600 * 24 * 7;
1013						}
1014					}
1015				}
1016			}
1017			$icalevents = array_merge($icalevents, $moreicalevents);
1018
1019			// Loop on each entry into cal file to know if entry is qualified and add an ActionComm into $eventarray
1020			foreach ($icalevents as $icalevent)
1021			{
1022				//var_dump($icalevent);
1023
1024				//print $icalevent['SUMMARY'].'->'.var_dump($icalevent).'<br>';exit;
1025				if (!empty($icalevent['RRULE'])) continue; // We found a repeatable event. It was already split into unitary events, so we discard general rule.
1026
1027				// Create a new object action
1028				$event = new ActionComm($db);
1029				$addevent = false;
1030				if (isset($icalevent['DTSTART;VALUE=DATE'])) // fullday event
1031				{
1032					// For full day events, date are also GMT but they wont but converted using tz during output
1033					$datestart = dol_stringtotime($icalevent['DTSTART;VALUE=DATE'], 1);
1034					$dateend = dol_stringtotime($icalevent['DTEND;VALUE=DATE'], 1) - 1; // We remove one second to get last second of day
1035					//print 'x'.$datestart.'-'.$dateend;exit;
1036					//print dol_print_date($dateend,'dayhour','gmt');
1037					$event->fulldayevent = 1;
1038					$addevent = true;
1039				} elseif (!is_array($icalevent['DTSTART'])) // not fullday event (DTSTART is not array. It is a value like '19700101T000000Z' for 00:00 in greenwitch)
1040				{
1041					$datestart = $icalevent['DTSTART'];
1042					$dateend = $icalevent['DTEND'];
1043
1044					$datestart += +($offsettz * 3600);
1045					$dateend += +($offsettz * 3600);
1046
1047					$addevent = true;
1048					//var_dump($offsettz);
1049					//var_dump(dol_print_date($datestart, 'dayhour', 'gmt'));
1050				} elseif (isset($icalevent['DTSTART']['unixtime']))	// File contains a local timezone + a TZ (for example when using bluemind)
1051				{
1052					$datestart = $icalevent['DTSTART']['unixtime'];
1053					$dateend = $icalevent['DTEND']['unixtime'];
1054
1055					$datestart += +($offsettz * 3600);
1056					$dateend += +($offsettz * 3600);
1057
1058					// $buggedfile is set to uselocalandtznodaylight if conf->global->AGENDA_EXT_BUGGEDFILEx = 'uselocalandtznodaylight'
1059					if ($buggedfile === 'uselocalandtznodaylight')	// unixtime is a local date that does not take daylight into account, TZID is +1 for example for 'Europe/Paris' in summer instead of 2
1060					{
1061						// TODO
1062					}
1063					// $buggedfile is set to uselocalandtzdaylight if conf->global->AGENDA_EXT_BUGGEDFILEx = 'uselocalandtzdaylight' (for example with bluemind)
1064					if ($buggedfile === 'uselocalandtzdaylight')	// unixtime is a local date that does take daylight into account, TZID is +2 for example for 'Europe/Paris' in summer
1065					{
1066						$localtzs = new DateTimeZone(preg_replace('/"/', '', $icalevent['DTSTART']['TZID']));
1067						$localtze = new DateTimeZone(preg_replace('/"/', '', $icalevent['DTEND']['TZID']));
1068						$localdts = new DateTime(dol_print_date($datestart, 'dayrfc', 'gmt'), $localtzs);
1069						$localdte = new DateTime(dol_print_date($dateend, 'dayrfc', 'gmt'), $localtze);
1070						$tmps = -1 * $localtzs->getOffset($localdts);
1071						$tmpe = -1 * $localtze->getOffset($localdte);
1072						$datestart += $tmps;
1073						$dateend += $tmpe;
1074						//var_dump($datestart);
1075					}
1076					$addevent = true;
1077				}
1078
1079				if ($addevent)
1080				{
1081					$event->id = $icalevent['UID'];
1082					$event->ref = $event->id;
1083					$userId = $userstatic->findUserIdByEmail($namecal);
1084					if (!empty($userId) && $userId > 0)
1085					{
1086						$event->userassigned[$userId] = $userId;
1087						$event->percentage = -1;
1088					}
1089					else {
1090						$event->type_code = "ICALEVENT";
1091					}
1092
1093					$event->icalname = $namecal;
1094					$event->icalcolor = $colorcal;
1095					$usertime = 0; // We dont modify date because we want to have date into memory datep and datef stored as GMT date. Compensation will be done during output.
1096					$event->datep = $datestart + $usertime;
1097					$event->datef = $dateend + $usertime;
1098
1099					if ($icalevent['SUMMARY']) $event->label = $icalevent['SUMMARY'];
1100					elseif ($icalevent['DESCRIPTION']) $event->label = dol_nl2br($icalevent['DESCRIPTION'], 1);
1101					else $event->label = $langs->trans("ExtSiteNoLabel");
1102
1103					// Priority (see https://www.kanzaki.com/docs/ical/priority.html)
1104					// LOW      = 0 to 4
1105					// MEDIUM   = 5
1106					// HIGH     = 6 to 9
1107					if ($icalevent['PRIORITY']) $event->priority = $icalevent['PRIORITY'];
1108
1109					// Transparency (see https://www.kanzaki.com/docs/ical/transp.html)
1110					if ($icalevent['TRANSP'])
1111					{
1112						if ($icalevent['TRANSP'] == "TRANSPARENT") $event->transparency = 0; // 0 = available / free
1113						if ($icalevent['TRANSP'] == "OPAQUE") $event->transparency = 1; // 1 = busy
1114
1115						// TODO: MS outlook states
1116						// X-MICROSOFT-CDO-BUSYSTATUS:FREE      + TRANSP:TRANSPARENT => Available / Free
1117						// X-MICROSOFT-CDO-BUSYSTATUS:FREE      + TRANSP:OPAQUE      => Work another place
1118						// X-MICROSOFT-CDO-BUSYSTATUS:TENTATIVE + TRANSP:OPAQUE      => With reservations
1119						// X-MICROSOFT-CDO-BUSYSTATUS:BUSY      + TRANSP:OPAQUE      => Busy
1120						// X-MICROSOFT-CDO-BUSYSTATUS:OOF       + TRANSP:OPAQUE      => Away from the office / off-site
1121					}
1122
1123					if ($icalevent['LOCATION']) $event->location = $icalevent['LOCATION'];
1124
1125					$event->date_start_in_calendar = $event->datep;
1126
1127					if ($event->datef != '' && $event->datef >= $event->datep) $event->date_end_in_calendar = $event->datef;
1128					else $event->date_end_in_calendar = $event->datep;
1129
1130					// Define ponctual property
1131					if ($event->date_start_in_calendar == $event->date_end_in_calendar)
1132					{
1133						$event->ponctuel = 1;
1134						//print 'x'.$datestart.'-'.$dateend;exit;
1135					}
1136
1137					// Add event into $eventarray if date range are ok.
1138					if ($event->date_end_in_calendar < $firstdaytoshow || $event->date_start_in_calendar >= $lastdaytoshow)
1139					{
1140						//print 'x'.$datestart.'-'.$dateend;exit;
1141						//print 'x'.$datestart.'-'.$dateend;exit;
1142						//print 'x'.$datestart.'-'.$dateend;exit;
1143						// This record is out of visible range
1144					} else {
1145						if ($event->date_start_in_calendar < $firstdaytoshow) $event->date_start_in_calendar = $firstdaytoshow;
1146						if ($event->date_end_in_calendar >= $lastdaytoshow) $event->date_end_in_calendar = ($lastdaytoshow - 1);
1147
1148						// Add an entry in actionarray for each day
1149						$daycursor = $event->date_start_in_calendar;
1150						$annee = date('Y', $daycursor);
1151						$mois = date('m', $daycursor);
1152						$jour = date('d', $daycursor);
1153
1154						// Loop on each day covered by action to prepare an index to show on calendar
1155						$loop = true; $j = 0;
1156						// daykey must be date that represent day box in calendar so must be a user time
1157						$daykey = dol_mktime(0, 0, 0, $mois, $jour, $annee);
1158						$daykeygmt = dol_mktime(0, 0, 0, $mois, $jour, $annee, true, 0);
1159						do {
1160							//if ($event->fulldayevent) print dol_print_date($daykeygmt,'dayhour','gmt').'-'.dol_print_date($daykey,'dayhour','gmt').'-'.dol_print_date($event->date_end_in_calendar,'dayhour','gmt').' ';
1161							$eventarray[$daykey][] = $event;
1162							$daykey += 60 * 60 * 24; $daykeygmt += 60 * 60 * 24; // Add one day
1163							if (($event->fulldayevent ? $daykeygmt : $daykey) > $event->date_end_in_calendar) $loop = false;
1164						} while ($loop);
1165					}
1166				}
1167			}
1168		}
1169	}
1170}
1171
1172
1173
1174// Complete $eventarray with events coming from external module
1175$parameters = array(); $object = null;
1176$reshook = $hookmanager->executeHooks('getCalendarEvents', $parameters, $object, $action);
1177if (!empty($hookmanager->resArray['eventarray'])) {
1178	foreach ($hookmanager->resArray['eventarray'] as $keyDate => $events) {
1179		if (!isset($eventarray[$keyDate])) {
1180			$eventarray[$keyDate] = array();
1181		}
1182		$eventarray[$keyDate] = array_merge($eventarray[$keyDate], $events);
1183	}
1184}
1185
1186// Sort events
1187foreach ($eventarray as $keyDate => &$dateeventarray)
1188{
1189	usort($dateeventarray, 'sort_events_by_date');
1190}
1191
1192
1193$maxnbofchar = 0;
1194$cachethirdparties = array();
1195$cachecontacts = array();
1196$cacheusers = array();
1197
1198// Define theme_datacolor array
1199$color_file = DOL_DOCUMENT_ROOT."/theme/".$conf->theme."/theme_vars.inc.php";
1200if (is_readable($color_file))
1201{
1202	include_once $color_file;
1203}
1204if (!is_array($theme_datacolor)) $theme_datacolor = array(array(120, 130, 150), array(200, 160, 180), array(190, 190, 220));
1205
1206
1207print_barre_liste($langs->trans("Agenda"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, -1, 'object_action', 0, $nav.'<span class="marginleftonly"></span>'.$newcardbutton, '', $limit, 1, 0, 1, $viewmode);
1208
1209print $s;
1210
1211
1212if (empty($action) || $action == 'show_month')      // View by month
1213{
1214	$newparam = $param; // newparam is for birthday links
1215	$newparam = preg_replace('/showbirthday=/i', 'showbirthday_=', $newparam); // To avoid replacement when replace day= is done
1216	$newparam = preg_replace('/action=show_month&?/i', '', $newparam);
1217	$newparam = preg_replace('/action=show_week&?/i', '', $newparam);
1218	$newparam = preg_replace('/day=[0-9]+&?/i', '', $newparam);
1219	$newparam = preg_replace('/month=[0-9]+&?/i', '', $newparam);
1220	$newparam = preg_replace('/year=[0-9]+&?/i', '', $newparam);
1221	$newparam = preg_replace('/viewcal=[0-9]+&?/i', '', $newparam);
1222	$newparam = preg_replace('/showbirthday_=/i', 'showbirthday=', $newparam); // Restore correct parameter
1223	$newparam .= '&viewcal=1';
1224
1225	print '<div class="liste_titre liste_titre_bydiv centpercent">';
1226	print_actions_filter($form, $canedit, $status, $year, $month, $day, $showbirthday, 0, $filtert, 0, $pid, $socid, $action, -1, $actioncode, $usergroup, '', $resourceid);
1227	print '</div>';
1228
1229	print '<div class="div-table-responsive-no-min sectioncalendarbymonth maxscreenheightless300">';
1230	print '<table width="100%" class="noborder nocellnopadd cal_pannel cal_month">';
1231	print ' <tr class="liste_titre">';
1232	// Column title of weeks numbers
1233	echo '  <td align="center">#</td>';
1234	$i = 0;
1235	while ($i < 7)
1236	{
1237		print '  <td class="center bold uppercase tdfordaytitle">';
1238		$numdayinweek = (($i + (isset($conf->global->MAIN_START_WEEK) ? $conf->global->MAIN_START_WEEK : 1)) % 7);
1239		if (!empty($conf->dol_optimize_smallscreen))
1240		{
1241			$labelshort = array(0=>'SundayMin', 1=>'MondayMin', 2=>'TuesdayMin', 3=>'WednesdayMin', 4=>'ThursdayMin', 5=>'FridayMin', 6=>'SaturdayMin');
1242			print $langs->trans($labelshort[$numdayinweek]);
1243		} else print $langs->trans("Day".$numdayinweek);
1244		print '  </td>'."\n";
1245		$i++;
1246	}
1247	echo ' </tr>'."\n";
1248
1249	$todayarray = dol_getdate($now, 'fast');
1250	$todaytms = dol_mktime(0, 0, 0, $todayarray['mon'], $todayarray['mday'], $todayarray['year']);
1251
1252	// In loops, tmpday contains day nb in current month (can be zero or negative for days of previous month)
1253	//var_dump($eventarray);
1254	for ($iter_week = 0; $iter_week < 6; $iter_week++) {
1255		echo " <tr>\n";
1256		// Get date of the current day, format 'yyyy-mm-dd'
1257		if ($tmpday <= 0) // If number of the current day is in previous month
1258		{
1259			$currdate0 = sprintf("%04d", $prev_year).sprintf("%02d", $prev_month).sprintf("%02d", $max_day_in_prev_month + $tmpday);
1260		}
1261		elseif ($tmpday <= $max_day_in_month) // If number of the current day is in current month
1262		{
1263			$currdate0 = sprintf("%04d", $year).sprintf("%02d", $month).sprintf("%02d", $tmpday);
1264		}
1265		else // If number of the current day is in next month
1266		{
1267			$currdate0 = sprintf("%04d", $next_year).sprintf("%02d", $next_month).sprintf("%02d", $tmpday - $max_day_in_month);
1268		}
1269		// Get week number for the targeted date '$currdate0'
1270		$numweek0 = date("W", strtotime(date($currdate0)));
1271		// Show the week number, and define column width
1272		echo ' <td class="center weeknumber opacitymedium" width="2%">'.$numweek0.'</td>';
1273
1274		for ($iter_day = 0; $iter_day < 7; $iter_day++) {
1275			if ($tmpday <= 0) {
1276				/* Show days before the beginning of the current month (previous month)  */
1277				$style = 'cal_other_month cal_past';
1278				if ($iter_day == 6) $style .= ' cal_other_month_right';
1279				echo '  <td class="'.$style.' nowrap tdtop" width="14%">';
1280				show_day_events($db, $max_day_in_prev_month + $tmpday, $prev_month, $prev_year, $month, $style, $eventarray, $maxprint, $maxnbofchar, $newparam);
1281				echo "  </td>\n";
1282			} elseif ($tmpday <= $max_day_in_month) {
1283				/* Show days of the current month */
1284				$curtime = dol_mktime(0, 0, 0, $month, $tmpday, $year);
1285				$style = 'cal_current_month';
1286				if ($iter_day == 6) $style .= ' cal_current_month_right';
1287				$today = 0;
1288				if ($todayarray['mday'] == $tmpday && $todayarray['mon'] == $month && $todayarray['year'] == $year) $today = 1;
1289				if ($today) $style = 'cal_today';
1290				if ($curtime < $todaytms) $style .= ' cal_past';
1291				//var_dump($todayarray['mday']."==".$tmpday." && ".$todayarray['mon']."==".$month." && ".$todayarray['year']."==".$year.' -> '.$style);
1292				echo '  <td class="'.$style.' nowrap tdtop" width="14%">';
1293				show_day_events($db, $tmpday, $month, $year, $month, $style, $eventarray, $maxprint, $maxnbofchar, $newparam);
1294				echo "</td>\n";
1295			} else {
1296				/* Show days after the current month (next month) */
1297				$style = 'cal_other_month';
1298				if ($iter_day == 6) $style .= ' cal_other_month_right';
1299				echo '  <td class="'.$style.' nowrap tdtop" width="14%">';
1300				show_day_events($db, $tmpday - $max_day_in_month, $next_month, $next_year, $month, $style, $eventarray, $maxprint, $maxnbofchar, $newparam);
1301				echo "</td>\n";
1302			}
1303			$tmpday++;
1304		}
1305		echo " </tr>\n";
1306	}
1307	print "</table>\n";
1308	print '</div>';
1309
1310	print '<input type="hidden" name="actionmove" value="mupdate">';
1311	print '<input type="hidden" name="backtopage" value="'.dol_escape_htmltag($_SERVER['PHP_SELF']).'?'.dol_escape_htmltag($_SERVER['QUERY_STRING']).'">';
1312	print '<input type="hidden" name="newdate" id="newdate">';
1313} elseif ($action == 'show_week') {
1314	// View by week
1315	$newparam = $param; // newparam is for birthday links
1316	$newparam = preg_replace('/showbirthday=/i', 'showbirthday_=', $newparam); // To avoid replacement when replace day= is done
1317	$newparam = preg_replace('/action=show_month&?/i', '', $newparam);
1318	$newparam = preg_replace('/action=show_week&?/i', '', $newparam);
1319	$newparam = preg_replace('/day=[0-9]+&?/i', '', $newparam);
1320	$newparam = preg_replace('/month=[0-9]+&?/i', '', $newparam);
1321	$newparam = preg_replace('/year=[0-9]+&?/i', '', $newparam);
1322	$newparam = preg_replace('/viewweek=[0-9]+&?/i', '', $newparam);
1323	$newparam = preg_replace('/showbirthday_=/i', 'showbirthday=', $newparam); // Restore correct parameter
1324	$newparam .= '&viewweek=1';
1325
1326	print '<div class="liste_titre liste_titre_bydiv centpercent"><div class="divsearchfield">';
1327	print_actions_filter($form, $canedit, $status, $year, $month, $day, $showbirthday, 0, $filtert, 0, $pid, $socid, $action, -1, $actioncode, $usergroup, '', $resourceid);
1328	print '</div></div>';
1329
1330	print '<div class="div-table-responsive-no-min sectioncalendarbyweek maxscreenheightless300">';
1331	print '<table width="100%" class="noborder nocellnopadd cal_pannel cal_month">';
1332	print ' <tr class="liste_titre">';
1333	$i = 0;
1334	while ($i < 7) {
1335		echo '  <td class="center bold uppercase tdfordaytitle">'.$langs->trans("Day".(($i + (isset($conf->global->MAIN_START_WEEK) ? $conf->global->MAIN_START_WEEK : 1)) % 7))."</td>\n";
1336		$i++;
1337	}
1338	echo " </tr>\n";
1339
1340	echo " <tr>\n";
1341
1342	for ($iter_day = 0; $iter_day < 7; $iter_day++) {
1343		// Show days of the current week
1344		$curtime = dol_time_plus_duree($firstdaytoshow, $iter_day, 'd');		// $firstdaytoshow is in timezone of server
1345		$tmpday = dol_print_date($curtime, '%d', 'tzuserrel');
1346		$tmpmonth = dol_print_date($curtime, '%m', 'tzuserrel');
1347		$tmpyear = dol_print_date($curtime, '%Y', 'tzuserrel');
1348
1349		$style = 'cal_current_month';
1350		if ($iter_day == 6) $style .= ' cal_other_month_right';
1351
1352		$today = 0;
1353		$todayarray = dol_getdate($now, 'fast');
1354		if ($todayarray['mday'] == $tmpday && $todayarray['mon'] == $tmpmonth && $todayarray['year'] == $tmpyear) $today = 1;
1355		if ($today) $style = 'cal_today';
1356
1357		echo '  <td class="'.$style.'" width="14%" valign="top">';
1358		show_day_events($db, $tmpday, $tmpmonth, $tmpyear, $month, $style, $eventarray, 0, $maxnbofchar, $newparam, 1, 300);
1359		echo "  </td>\n";
1360	}
1361	echo " </tr>\n";
1362
1363	print "</table>\n";
1364	print '</div>';
1365
1366	echo '<input type="hidden" name="actionmove" value="mupdate">';
1367	echo '<input type="hidden" name="backtopage" value="'.dol_escape_htmltag($_SERVER['PHP_SELF']).'?'.dol_escape_htmltag($_SERVER['QUERY_STRING']).'">';
1368	echo '<input type="hidden" name="newdate" id="newdate">';
1369} else // View by day
1370{
1371	$newparam = $param; // newparam is for birthday links
1372	$newparam = preg_replace('/action=show_month&?/i', '', $newparam);
1373	$newparam = preg_replace('/action=show_week&?/i', '', $newparam);
1374	$newparam = preg_replace('/viewday=[0-9]+&?/i', '', $newparam);
1375	$newparam .= '&viewday=1';
1376	// Code to show just one day
1377	$style = 'cal_current_month cal_current_month_oneday';
1378	$today = 0;
1379	$todayarray = dol_getdate($now, 'fast');
1380	if ($todayarray['mday'] == $day && $todayarray['mon'] == $month && $todayarray['year'] == $year) $today = 1;
1381	//if ($today) $style='cal_today';
1382
1383	$timestamp = dol_mktime(12, 0, 0, $month, $day, $year);
1384	$arraytimestamp = dol_getdate($timestamp);
1385
1386	print '<div class="liste_titre liste_titre_bydiv centpercent"><div class="divsearchfield">';
1387	print_actions_filter($form, $canedit, $status, $year, $month, $day, $showbirthday, 0, $filtert, 0, $pid, $socid, $action, -1, $actioncode, $usergroup, '', $resourceid);
1388	print '</div></div>';
1389
1390	print '<div class="div-table-responsive-no-min sectioncalendarbyday maxscreenheightless300">';
1391	echo '<table class="tagtable centpercent noborder nocellnopadd cal_pannel cal_month noborderbottom" style="margin-bottom: 5px !important;">';
1392
1393	echo ' <tr class="tagtr liste_titre">';
1394	echo '  <td class="tagtd center bold uppercase">'.$langs->trans("Day".$arraytimestamp['wday'])."</td>\n";
1395	echo " </td>\n";
1396
1397	/*
1398    echo ' <div class="tagtr">';
1399    echo '  <div class="tagtd width100"></div>';
1400    echo '  <div class="tagtd center">';
1401    echo show_day_events($db, $day, $month, $year, $month, $style, $eventarray, 0, $maxnbofchar, $newparam, 1, 300, -1);
1402    echo '  </div>'."\n";
1403    echo " </div>\n";
1404	*/
1405
1406	echo '</table>';
1407	print '</div>';
1408
1409	/* WIP View per hour */
1410	$useviewhour = 0;
1411	if ($useviewhour)
1412	{
1413		print '<div class="div-table-responsive-no-min borderbottom">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
1414
1415		$maxheightwin = (isset($_SESSION["dol_screenheight"]) && $_SESSION["dol_screenheight"] > 500) ? ($_SESSION["dol_screenheight"] - 200) : 660; // Also into index.php file
1416
1417		echo '<div style="max-height: '.$maxheightwin.'px;">';
1418		echo '<div class="tagtable centpercent calendarviewcontainer">';
1419
1420		$maxnbofchar = 80;
1421
1422		$tmp = explode('-', $conf->global->MAIN_DEFAULT_WORKING_HOURS);
1423		$minhour = round($tmp[0], 0);
1424		$maxhour = round($tmp[1], 0);
1425		if ($minhour > 23) $minhour = 23;
1426		if ($maxhour < 1)  $maxhour = 1;
1427		if ($maxhour <= $minhour) { $maxhour = $minhour + 1; }
1428
1429		$i = 0;
1430		$j = 0;
1431		while ($i < 24)
1432		{
1433			echo ' <div class="tagtr calendarviewcontainertr">'."\n";
1434			echo '  <div class="tagtd width100 tdtop">'.dol_print_date($i * 3600, 'hour', 'gmt').'</div>';
1435			echo '  <div class="tagtd '.$style.' tdtop"></div>'."\n";
1436			echo ' </div>'."\n";
1437			$i++;
1438			$j++;
1439		}
1440
1441		echo '</div></div>';
1442
1443		show_day_events($db, $day, $month, $year, $month, $style, $eventarray, 0, $maxnbofchar, $newparam, 1, 300, 1);
1444
1445		print '</div>';
1446	} else {
1447		print '<div class="div-table-responsive-no-min">'; // You can use div-table-responsive-no-min if you dont need reserved height for your table
1448
1449		show_day_events($db, $day, $month, $year, $month, $style, $eventarray, 0, $maxnbofchar, $newparam, 1, 300, 0);
1450
1451		print '</div>';
1452	}
1453}
1454
1455print "\n".'</form>';
1456
1457// End of page
1458llxFooter();
1459$db->close();
1460
1461
1462/**
1463 * Show event of a particular day
1464 *
1465 * @param	DoliDB	$db              Database handler
1466 * @param   int		$day             Day
1467 * @param   int		$month           Month
1468 * @param   int		$year            Year
1469 * @param   int		$monthshown      Current month shown in calendar view
1470 * @param   string	$style           Style to use for this day
1471 * @param   array	$eventarray      Array of events
1472 * @param   int		$maxprint        Nb of actions to show each day on month view (0 means no limit)
1473 * @param   int		$maxnbofchar     Nb of characters to show for event line
1474 * @param   string	$newparam        Parameters on current URL
1475 * @param   int		$showinfo        Add extended information (used by day and week view)
1476 * @param   int		$minheight       Minimum height for each event. 60px by default.
1477 * @param	string	$nonew			 0=Add "new entry button", 1=No "new entry button", -1=Only "new entry button"
1478 * @return	void
1479 */
1480function show_day_events($db, $day, $month, $year, $monthshown, $style, &$eventarray, $maxprint = 0, $maxnbofchar = 16, $newparam = '', $showinfo = 0, $minheight = 60, $nonew = 0)
1481{
1482	global $user, $conf, $langs;
1483	global $action, $filter, $filtert, $status, $actioncode, $usergroup; // Filters used into search form
1484	global $theme_datacolor;
1485	global $cachethirdparties, $cachecontacts, $cacheusers, $colorindexused;
1486
1487	$dateint = sprintf("%04d", $year).sprintf("%02d", $month).sprintf("%02d", $day);
1488
1489	//print 'show_day_events day='.$day.' month='.$month.' year='.$year.' dateint='.$dateint;
1490
1491	print "\n";
1492
1493	$curtime = dol_mktime(0, 0, 0, $month, $day, $year);
1494	$urltoshow = DOL_URL_ROOT.'/comm/action/index.php?action=show_day&day='.str_pad($day, 2, "0", STR_PAD_LEFT).'&month='.str_pad($month, 2, "0", STR_PAD_LEFT).'&year='.$year.$newparam;
1495	$urltocreate = '';
1496	if ($user->rights->agenda->myactions->create || $user->rights->agenda->allactions->create)
1497	{
1498		$newparam .= '&month='.str_pad($month, 2, "0", STR_PAD_LEFT).'&year='.$year;
1499		$hourminsec = '100000';
1500		$urltocreate = DOL_URL_ROOT.'/comm/action/card.php?action=create&datep='.sprintf("%04d%02d%02d", $year, $month, $day).$hourminsec.'&backtopage='.urlencode($_SERVER["PHP_SELF"].($newparam ? '?'.$newparam : ''));
1501	}
1502
1503	// Line with title of day
1504	print '<div id="dayevent_'.$dateint.'" class="dayevent tagtable centpercent nobordernopadding">'."\n";
1505
1506	if ($nonew <= 0)
1507	{
1508		print '<div class="tagtr cursorpointer" onclick="window.location=\''.$urltocreate.'\';"><div class="nowrap tagtd"><div class="left inline-block">';
1509		print '<a class="dayevent-aday" style="color: #666" href="'.$urltoshow.'">';
1510		if ($showinfo) print dol_print_date($curtime, 'daytextshort');
1511		else print dol_print_date($curtime, '%d');
1512		print '</a>';
1513		print '</div><div class="nowrap floatright inline-block marginrightonly">';
1514		if ($user->rights->agenda->myactions->create || $user->rights->agenda->allactions->create)
1515		{
1516			print '<a class="cursoradd" href="'.$urltocreate.'">'; // Explicit link, usefull for nojs interfaces
1517			print img_picto($langs->trans("NewAction"), 'edit_add.png');
1518			print '</a>';
1519		}
1520		print '</div></div></div>'."\n";
1521	}
1522
1523	if ($nonew < 0)
1524	{
1525		print '</div>';
1526		return;
1527	}
1528
1529	// Line with td contains all div of each events
1530	print '<div class="tagtr">';
1531	print '<div class="tagtd centpercent agendacell sortable">';
1532
1533	//$curtime = dol_mktime (0, 0, 0, $month, $day, $year);
1534	$i = 0; $numother = 0; $numbirthday = 0; $numical = 0; $numicals = array();
1535	$ymd = sprintf("%04d", $year).sprintf("%02d", $month).sprintf("%02d", $day);
1536
1537	$colorindexused[$user->id] = 0; // Color index for current user (user->id) is always 0
1538	$nextindextouse = is_array($colorindexused) ?count($colorindexused) : 0; // At first run this is 0, so fist user has 0, next 1, ...
1539	//var_dump($colorindexused);
1540
1541	foreach ($eventarray as $daykey => $notused) {		// daykey is the 'YYYYMMDD' to show according to user
1542		$annee = dol_print_date($daykey, '%Y', 'gmt');	// We use gmt because we want the value represented by string 'YYYYMMDD'
1543		$mois =  dol_print_date($daykey, '%m', 'gmt');	// We use gmt because we want the value represented by string 'YYYYMMDD'
1544		$jour =  dol_print_date($daykey, '%d', 'gmt');	// We use gmt because we want the value represented by string 'YYYYMMDD'
1545
1546		//print 'event daykey='.$daykey.' dol_print_date(daykey)='.dol_print_date($daykey, 'dayhour', 'gmt').' jour='.$jour.' mois='.$mois.' annee='.$annee."<br>\n";
1547
1548		if ($day == $jour && $month == $mois && $year == $annee)
1549		{
1550			foreach ($eventarray[$daykey] as $index => $event)
1551			{
1552				if ($i < $maxprint || $maxprint == 0 || !empty($conf->global->MAIN_JS_SWITCH_AGENDA))
1553				{
1554					$keysofuserassigned = array_keys($event->userassigned);
1555					$ponct = ($event->date_start_in_calendar == $event->date_end_in_calendar);
1556
1557					// Define $color (Hex string like '0088FF') and $cssclass of event
1558					$color = -1; $cssclass = ''; $colorindex = -1;
1559					if (in_array($user->id, $keysofuserassigned))
1560					{
1561						$cssclass = 'family_mytasks';
1562
1563						if (empty($cacheusers[$event->userownerid]))
1564						{
1565							$newuser = new User($db);
1566							$newuser->fetch($event->userownerid);
1567							$cacheusers[$event->userownerid] = $newuser;
1568						}
1569						//var_dump($cacheusers[$event->userownerid]->color);
1570
1571						// We decide to choose color of owner of event (event->userownerid is user id of owner, event->userassigned contains all users assigned to event)
1572						if (!empty($cacheusers[$event->userownerid]->color)) $color = $cacheusers[$event->userownerid]->color;
1573					} elseif ($event->type_code == 'ICALEVENT')      // Event come from external ical file
1574					{
1575						$numical++;
1576						if (!empty($event->icalname)) {
1577							if (!isset($numicals[dol_string_nospecial($event->icalname)])) {
1578								$numicals[dol_string_nospecial($event->icalname)] = 0;
1579							}
1580							$numicals[dol_string_nospecial($event->icalname)]++;
1581						}
1582
1583						$color = ($event->icalcolor ? $event->icalcolor : -1);
1584						$cssclass = (!empty($event->icalname) ? 'family_ext'.md5($event->icalname) : 'family_other');
1585					} elseif ($event->type_code == 'BIRTHDAY')
1586					{
1587						$numbirthday++; $colorindex = 2; $cssclass = 'family_birthday unmovable'; $color = sprintf("%02x%02x%02x", $theme_datacolor[$colorindex][0], $theme_datacolor[$colorindex][1], $theme_datacolor[$colorindex][2]);
1588					} else {
1589						$numother++;
1590						$color = ($event->icalcolor ? $event->icalcolor : -1);
1591						$cssclass = (!empty($event->icalname) ? 'family_ext'.md5($event->icalname) : 'family_other');
1592
1593						if (empty($cacheusers[$event->userownerid]))
1594						{
1595							$newuser = new User($db);
1596							$newuser->fetch($event->userownerid);
1597							$cacheusers[$event->userownerid] = $newuser;
1598						}
1599						//var_dump($cacheusers[$event->userownerid]->color);
1600
1601					   	// We decide to choose color of owner of event (event->userownerid is user id of owner, event->userassigned contains all users assigned to event)
1602					   	if (!empty($cacheusers[$event->userownerid]->color)) $color = $cacheusers[$event->userownerid]->color;
1603					}
1604
1605					if ($color < 0)	// Color was not set on user card. Set color according to color index.
1606					{
1607						// Define color index if not yet defined
1608						$idusertouse = ($event->userownerid ? $event->userownerid : 0);
1609						if (isset($colorindexused[$idusertouse]))
1610						{
1611							$colorindex = $colorindexused[$idusertouse]; // Color already assigned to this user
1612						} else {
1613				   			$colorindex = $nextindextouse;
1614				   			$colorindexused[$idusertouse] = $colorindex;
1615							if (!empty($theme_datacolor[$nextindextouse + 1])) $nextindextouse++; // Prepare to use next color
1616						}
1617						//print '|'.($color).'='.($idusertouse?$idusertouse:0).'='.$colorindex.'<br>';
1618						// Define color
1619						$color = sprintf("%02x%02x%02x", $theme_datacolor[$colorindex][0], $theme_datacolor[$colorindex][1], $theme_datacolor[$colorindex][2]);
1620					}
1621					$cssclass = $cssclass.' '.$cssclass.'_day_'.$ymd;
1622
1623					// Defined style to disable drag and drop feature
1624					if ($event->type_code == 'AC_OTH_AUTO')
1625					{
1626						$cssclass .= " unmovable";
1627					} elseif ($event->type_code == 'ICALEVENT')
1628					{
1629						$cssclass .= " unmovable";
1630					} elseif ($event->date_end_in_calendar && date('Ymd', $event->date_start_in_calendar) != date('Ymd', $event->date_end_in_calendar)) {
1631						$tmpyearend    = date('Y', $event->date_end_in_calendar);
1632						$tmpmonthend   = date('m', $event->date_end_in_calendar);
1633						$tmpdayend     = date('d', $event->date_end_in_calendar);
1634						if ($tmpyearend != $annee || $tmpmonthend != $mois || $tmpdayend != $jour)
1635						{
1636							$cssclass .= " unmovable";
1637						}
1638					} else {
1639						if ($user->rights->agenda->allactions->create ||
1640							(($event->authorid == $user->id || $event->userownerid == $user->id) && $user->rights->agenda->myactions->create))
1641						{
1642							$cssclass .= " movable cursormove";
1643						} else {
1644							$cssclass .= " unmovable";
1645						}
1646					}
1647
1648					$h = ''; $nowrapontd = 1;
1649					if ($action == 'show_day') { $h = 'height: 100%; '; $nowrapontd = 0; }
1650					if ($action == 'show_week') { $h = 'height: 100%; '; $nowrapontd = 0; }
1651
1652					// Show rect of event
1653					print "\n";
1654					print '<!-- start event '.$i.' -->'."\n";
1655					print '<div id="event_'.$ymd.'_'.$i.'" class="event '.$cssclass.'"';
1656					//print ' style="height: 100px;';
1657					//print ' position: absolute; top: 40px; width: 50%;';
1658					//print '"';
1659					print '>';
1660
1661					//var_dump($event->userassigned);
1662					//var_dump($event->transparency);
1663					print '<table class="centpercent cal_event';
1664					print (empty($event->transparency) ? ' cal_event_notbusy' : ' cal_event_busy');
1665					//if (empty($event->transparency) && empty($conf->global->AGENDA_NO_TRANSPARENT_ON_NOT_BUSY)) print ' opacitymedium';	// Not busy
1666					print '" style="'.$h;
1667					$colortouse = $color;
1668					// If colortouse is similar than background, we force to change it.
1669					if (empty($event->transparency) && empty($conf->global->AGENDA_NO_TRANSPARENT_ON_NOT_BUSY))
1670					{
1671						print 'background: #f0f0f0;';
1672						print 'border-left: 5px solid #'.$colortouse.';';
1673					} else {
1674						print 'background: #f0f0f0;';
1675						print 'border-left: 5px solid #'.dol_color_minus($colortouse, -3).';';
1676						//print 'background: -webkit-gradient(linear, left top, left bottom, from(#'.dol_color_minus($colortouse, -3).'), to(#'.dol_color_minus($colortouse, -1).'));';
1677					}
1678				   	//print 'background: #'.$colortouse.';';
1679				   	//print 'background: -webkit-gradient(linear, left top, left bottom, from(#'.dol_color_minus($color, -3).'), to(#'.dol_color_minus($color, -1).'));';
1680					//if (! empty($event->transparency)) print 'background: #'.$color.'; background: -webkit-gradient(linear, left top, left bottom, from(#'.$color.'), to(#'.dol_color_minus($color,1).'));';
1681					//else print 'background-color: transparent !important; background: none; border: 1px solid #bbb;';
1682					//print ' -moz-border-radius:4px;"';
1683					//print 'border: 1px solid #ccc" width="100%"';
1684					print '">';
1685					print '<tr>';
1686					print '<td class="tdoverflow nobottom centpercent '.($nowrapontd ? 'nowrap ' : '').'cal_event'.($event->type_code == 'BIRTHDAY' ? ' cal_event_birthday' : '').'">';
1687
1688					$daterange = '';
1689
1690					if ($event->type_code == 'BIRTHDAY') // It's a birthday
1691					{
1692						print $event->getNomUrl(1, $maxnbofchar, 'cal_event', 'birthday', 'contact');
1693					} elseif ($event->type_code == 'HOLIDAY')
1694					{
1695						print $event->getNomUrl(1, $maxnbofchar, 'cal_event', 'holiday', 'user');
1696					} elseif ($event->type_code != 'BIRTHDAY' && $event->type_code != 'HOLIDAY')
1697					{
1698						// Picto
1699						if (empty($event->fulldayevent))
1700						{
1701							//print $event->getNomUrl(2).' ';
1702						}
1703
1704						// Date
1705						if (empty($event->fulldayevent))
1706						{
1707							// Show hours (start ... end)
1708							$tmpyearstart  = dol_print_date($event->date_start_in_calendar, '%Y', 'tzuserrel');
1709							$tmpmonthstart = dol_print_date($event->date_start_in_calendar, '%m', 'tzuserrel');
1710							$tmpdaystart   = dol_print_date($event->date_start_in_calendar, '%d', 'tzuserrel');
1711							$tmpyearend    = dol_print_date($event->date_end_in_calendar, '%Y', 'tzuserrel');
1712							$tmpmonthend   = dol_print_date($event->date_end_in_calendar, '%m', 'tzuserrel');
1713							$tmpdayend     = dol_print_date($event->date_end_in_calendar, '%d', 'tzuserrel');
1714
1715							// Hour start
1716							if ($tmpyearstart == $annee && $tmpmonthstart == $mois && $tmpdaystart == $jour)
1717							{
1718								$daterange .= dol_print_date($event->date_start_in_calendar, 'hour', 'tzuserrel');
1719								if ($event->date_end_in_calendar && $event->date_start_in_calendar != $event->date_end_in_calendar)
1720								{
1721									if ($tmpyearstart == $tmpyearend && $tmpmonthstart == $tmpmonthend && $tmpdaystart == $tmpdayend)
1722									$daterange .= '-';
1723									//else
1724									//print '...';
1725								}
1726							}
1727							if ($event->date_end_in_calendar && $event->date_start_in_calendar != $event->date_end_in_calendar)
1728							{
1729								if ($tmpyearstart != $tmpyearend || $tmpmonthstart != $tmpmonthend || $tmpdaystart != $tmpdayend)
1730								{
1731									$daterange .= '...';
1732								}
1733							}
1734							// Hour end
1735							if ($event->date_end_in_calendar && $event->date_start_in_calendar != $event->date_end_in_calendar)
1736							{
1737								if ($tmpyearend == $annee && $tmpmonthend == $mois && $tmpdayend == $jour)
1738								$daterange .= dol_print_date($event->date_end_in_calendar, 'hour', 'tzuserrel');
1739							}
1740						} else {
1741							if ($showinfo)
1742							{
1743								print $langs->trans("EventOnFullDay")."<br>\n";
1744							}
1745						}
1746
1747						// Show title
1748						$titletoshow = $daterange;
1749						$titletoshow .= ($titletoshow ? ' ' : '').($event->label ? $event->label : $event->libelle);
1750
1751						if ($event->type_code != 'ICALEVENT') {
1752							$savlabel = $event->label ? $event->label : $event->libelle;
1753							$event->label = $titletoshow;
1754							$event->libelle = $titletoshow;
1755							// Note: List of users are inside $event->userassigned. Link may be clickable depending on permissions of user.
1756							$titletoshow = $event->getNomUrl(0, $maxnbofchar, 'cal_event cal_event_title', '', 0, 0);
1757							$event->label = $savlabel;
1758							$event->libelle = $savlabel;
1759						}
1760
1761						// Loop on each assigned user
1762						$listofusertoshow = '';
1763						$posuserassigned = 0;
1764						foreach ($event->userassigned as $tmpid => $tmpdata)
1765						{
1766							if (!$posuserassigned && $titletoshow) $listofusertoshow .= '<br>';
1767							$posuserassigned++;
1768							if (empty($cacheusers[$tmpid]))
1769							{
1770								$newuser = new User($db);
1771								$newuser->fetch($tmpid);
1772								$cacheusers[$tmpid] = $newuser;
1773							}
1774
1775							$listofusertoshow .= $cacheusers[$tmpid]->getNomUrl(-3, '', 0, 0, 0, 0, '', 'paddingright valigntextbottom');
1776						}
1777
1778						print $titletoshow;
1779						print $listofusertoshow;
1780
1781						if ($event->type_code == 'ICALEVENT') print '<br>('.dol_trunc($event->icalname, $maxnbofchar).')';
1782
1783						$thirdparty_id = ($event->thirdparty_id > 0 ? $event->thirdparty_id : ((is_object($event->societe) && $event->societe->id > 0) ? $event->societe->id : 0));
1784						$contact_id = ($event->contact_id > 0 ? $event->contact_id : ((is_object($event->contact) && $event->contact->id > 0) ? $event->contact->id : 0));
1785
1786						// If action related to company / contact
1787						$linerelatedto = '';
1788						if ($thirdparty_id > 0)
1789						{
1790							if (!isset($cachethirdparties[$thirdparty_id]) || !is_object($cachethirdparties[$thirdparty_id]))
1791							{
1792								$thirdparty = new Societe($db);
1793								$thirdparty->fetch($thirdparty_id);
1794								$cachethirdparties[$thirdparty_id] = $thirdparty;
1795							} else $thirdparty = $cachethirdparties[$thirdparty_id];
1796							if (!empty($thirdparty->id)) $linerelatedto .= $thirdparty->getNomUrl(1, '', 0);
1797						}
1798						if (!empty($contact_id) && $contact_id > 0)
1799						{
1800							if (!is_object($cachecontacts[$contact_id]))
1801							{
1802								$contact = new Contact($db);
1803								$contact->fetch($contact_id);
1804								$cachecontacts[$contact_id] = $contact;
1805							} else $contact = $cachecontacts[$contact_id];
1806							if ($linerelatedto) $linerelatedto .= '&nbsp;';
1807							if (!empty($contact->id)) $linerelatedto .= $contact->getNomUrl(1, '', 0);
1808						}
1809						if (!empty($event->fk_element) && $event->fk_element > 0 && !empty($event->elementtype) && !empty($conf->global->AGENDA_SHOW_LINKED_OBJECT))
1810						{
1811							include_once DOL_DOCUMENT_ROOT.'/core/lib/functions2.lib.php';
1812							if ($linerelatedto) $linerelatedto .= '<br>';
1813							$linerelatedto .= dolGetElementUrl($event->fk_element, $event->elementtype, 1);
1814						}
1815						if ($linerelatedto) print '<br>'.$linerelatedto;
1816					}
1817
1818					// Show location
1819					if ($showinfo)
1820					{
1821						if ($event->location)
1822						{
1823							print '<br>';
1824							print $langs->trans("Location").': '.$event->location;
1825						}
1826					}
1827
1828					print '</td>';
1829					// Status - Percent
1830					$withstatus = 0;
1831					if ($event->type_code != 'BIRTHDAY' && $event->type_code != 'ICALEVENT')
1832					{
1833						$withstatus = 1;
1834						if ($event->percentage >= 0) $withstatus = 2;
1835					}
1836					print '<td class="nobottom right nowrap cal_event_right'.($withstatus >= 2 ? ' cal_event_right_status' : '').'">';
1837					if ($withstatus) print $event->getLibStatut(3, 1);
1838					else print '&nbsp;';
1839					print '</td></tr></table>';
1840					print '</div><!-- end event '.$i.' -->'."\n";
1841					$i++;
1842				} else {
1843					print '<a href="'.DOL_URL_ROOT.'/comm/action/index.php?action='.$action.'&maxprint=0&month='.$monthshown.'&year='.$year;
1844					print ($status ? '&status='.$status : '').($filter ? '&filter='.$filter : '');
1845					print ($filtert ? '&search_filtert='.$filtert : '');
1846					print ($usergroup ? '&search_usergroup='.$usergroup : '');
1847					print ($actioncode != '' ? '&search_actioncode='.$actioncode : '');
1848					print '">'.img_picto("all", "1downarrow_selected.png").' ...';
1849					print ' +'.(count($eventarray[$daykey]) - $maxprint);
1850					print '</a>';
1851					break;
1852					//$ok=false;        // To avoid to show twice the link
1853				}
1854			}
1855
1856			break;
1857		}
1858	}
1859	if (!$i) {	// No events
1860		print '&nbsp;';
1861	}
1862
1863	if (!empty($conf->global->MAIN_JS_SWITCH_AGENDA) && $i > $maxprint && $maxprint)
1864	{
1865		print '<div id="more_'.$ymd.'">'.img_picto("all", "1downarrow_selected.png").' +'.$langs->trans("More").'...</div>';
1866		//print ' +'.(count($eventarray[$daykey])-$maxprint);
1867		print '<script type="text/javascript">'."\n";
1868		print 'jQuery(document).ready(function () {'."\n";
1869		print 'jQuery("#more_'.$ymd.'").click(function() { reinit_day_'.$ymd.'(); });'."\n";
1870
1871		print 'function reinit_day_'.$ymd.'() {'."\n";
1872		print 'var nb=0;'."\n";
1873		// TODO Loop on each element of day $ymd and start to toggle once $maxprint has been reached
1874		print 'jQuery(".family_mytasks_day_'.$ymd.'").toggle();';
1875		print '}'."\n";
1876
1877		print '});'."\n";
1878
1879		print '</script>'."\n";
1880	}
1881
1882	print '</div></div>'; // td tr
1883
1884	print '</div>'; // table
1885	print "\n";
1886}
1887
1888
1889/**
1890 * Change color with a delta
1891 *
1892 * @param	string	$color		Color
1893 * @param 	int		$minus		Delta (1 = 16 unit). Positive value = darker color, Negative value = brighter color.
1894 * @param   int     $minusunit  Minus unit
1895 * @return	string				New color
1896 */
1897function dol_color_minus($color, $minus, $minusunit = 16)
1898{
1899	$newcolor = $color;
1900	if ($minusunit == 16)
1901	{
1902		$newcolor[0] = dechex(max(min(hexdec($newcolor[0]) - $minus, 15), 0));
1903		$newcolor[2] = dechex(max(min(hexdec($newcolor[2]) - $minus, 15), 0));
1904		$newcolor[4] = dechex(max(min(hexdec($newcolor[4]) - $minus, 15), 0));
1905	} else {
1906		// Not yet implemented
1907	}
1908	return $newcolor;
1909}
1910
1911/**
1912 * Sort events by date
1913 *
1914 * @param   object  $a      Event A
1915 * @param   object  $b      Event B
1916 * @return  int             < 0 if event A should be before event B, > 0 otherwise, 0 if they have the exact same time slot
1917 */
1918function sort_events_by_date($a, $b)
1919{
1920	// Sort holidays at first
1921	if ($a->type_code === 'HOLIDAY')
1922	{
1923		return -1;
1924	}
1925
1926	if ($b->type_code === 'HOLIDAY')
1927	{
1928		return 1;
1929	}
1930
1931	// datep => Event start time
1932	// datef => Event end time
1933
1934	// Events have different start time
1935	if ($a->datep !== $b->datep)
1936	{
1937		return $a->datep - $b->datep;
1938	}
1939
1940	// Events have same start time and no end time
1941	if ((!is_numeric($b->datef)) || (!is_numeric($a->datef)))
1942	{
1943		return sort_events_by_percentage($a, $b);
1944	}
1945
1946	// Events have the same start time and same end time
1947	if ($b->datef === $a->datef)
1948	{
1949		return sort_events_by_percentage($a, $b);
1950	}
1951
1952	// Events have the same start time, but have different end time -> longest event first
1953	return $b->datef - $a->datef;
1954}
1955
1956/**
1957 * Sort events by percentage
1958 *
1959 * @param   object  $a      Event A
1960 * @param   object  $b      Event B
1961 * @return  int             < 0 if event A should be before event B, > 0 otherwise, 0 if they have the exact same percentage
1962 */
1963function sort_events_by_percentage($a, $b)
1964{
1965	// Sort events with no percentage before each other
1966	// (usefull to sort holidays, sick days or similar on the top)
1967
1968	if ($a->percentage < 0)
1969	{
1970		return -1;
1971	}
1972
1973	if ($b->percentage < 0)
1974	{
1975		return 1;
1976	}
1977
1978	return $b->percentage - $a->percentage;
1979}
1980