PluginProbe
ShiftController Employee Shift Scheduling / 4.9.70
ShiftController Employee Shift Scheduling v4.9.70
4.9.97 4.9.96 4.9.95 4.9.74 4.9.75 4.9.76 4.9.77 4.9.78 4.9.84 4.9.85 4.9.87 4.9.91 4.9.92 trunk 2.1.0 2.1.1 2.1.2 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 3.2.4 All 38 releases
shiftcontroller / sh4 / schedule / html / view / week.php

week.php in ShiftController Employee Shift Scheduling 4.9.70, at sh4/schedule/html/view/week.php

1,089 lines 29.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php if (! defined('ABSPATH')) exit; // Exit if accessed directly
2 #[AllowDynamicProperties]
3 class SH4_Schedule_Html_View_Week
4 {
5 protected $borderColor = 'gray';
6 protected $allCombosShift = array();
7 protected $allCombosTimeoff = array();
8
9 public function __construct(
10 HC3_Hooks $hooks,
11 HC3_Ui $ui,
12 HC3_Request $request,
13 HC3_Time $t,
14 HC3_Settings $settings,
15
16 HC3_Uri $uri,
17
18 SH4_New_Acl $newAcl,
19
20 SH4_Shifts_Duration $shiftsDuration,
21 SH4_Shifts_View_Widget $widget,
22 SH4_Calendars_Presenter $calendarsPresenter,
23 SH4_Employees_Presenter $employeesPresenter,
24 SH4_Schedule_Html_View_Common $common,
25 SH4_Shifts_View_Common $shiftsCommon
26 )
27 {
28 $this->self = $hooks->wrap($this);
29
30 $this->ui = $ui;
31
32 $this->uri = $uri;
33 $this->t = $t;
34 $this->request = $request;
35
36 $this->settings = $hooks->wrap( $settings );
37 $this->newAcl = $hooks->wrap( $newAcl );
38
39 $this->shiftsDuration = $hooks->wrap( $shiftsDuration );
40 $this->calendarsPresenter = $hooks->wrap( $calendarsPresenter );
41 $this->employeesPresenter = $hooks->wrap( $employeesPresenter );
42
43 $this->widget = $hooks->wrap( $widget );
44 $this->common = $hooks->wrap( $common );
45 $this->shiftsCommon = $hooks->wrap( $shiftsCommon );
46
47 $this->allCombosShift = $this->newAcl->findAllCombosShift();
48 $this->allCombosTimeoff = $this->newAcl->findAllCombosTimeoff();
49 }
50
51 public function renderDateLabel( $date )
52 {
53 $slug = $this->request->getSlug();
54 $today = $this->t->setNow()->formatDateDb();
55
56 $this->t->setDateDb( $date );
57
58 $weekdayView = $this->t->getWeekdayName();
59 $weekdayView = $this->ui->makeBlock( $weekdayView )->tag('muted')->tag('font-size', 1);
60
61 $ret = $this->t->formatDate();
62
63 $ret = $this->ui->makeList( array($weekdayView, $ret) )
64 ->gutter(0)
65 ;
66
67 $toDateParams = array();
68 $toDateParams['type'] = 'day';
69 $toDateParams['start'] = $date;
70 $toDate = array( $slug, $toDateParams );
71
72 $ret = $this->ui->makeAhref( $toDate, $ret )
73 ->tag('print')
74 ;
75
76 if( $date == $today ){
77 $ret = $this->ui->makeBlock( $ret )
78 ->tag('border')
79 ->tag('border-color', 'gray')
80 ;
81 }
82
83 return $ret;
84 }
85
86 public function render()
87 {
88 $slug = $this->request->getSlug();
89 $today = $this->t->setNow()->formatDateDb();
90
91 $shifts = $this->common->getShifts();
92
93 $params = $this->request->getParams();
94 $startDate = $params['start'];
95
96 $disabledWeekdays = $this->settings->get( 'skip_weekdays', TRUE );
97
98 $startDate = $this->t->setDateDb( $startDate )->setStartWeek()->formatDateDb();
99 $endDate = $this->t->modify('+1 week')->modify('-1 day')->formatDateDb();
100
101 $this->t->setDateDb( $startDate );
102 $dates = array();
103 $rexDate = $startDate;
104
105 while( $rexDate <= $endDate ){
106 if( $disabledWeekdays ){
107 $wkd = $this->t->getWeekday();
108 if( in_array($wkd, $disabledWeekdays) ){
109 $rexDate = $this->t->modify('+1 day')->formatDateDb();
110 continue;
111 }
112 }
113
114 $dates[] = $rexDate;
115 $rexDate = $this->t->modify('+1 day')->formatDateDb();
116 }
117
118 $viewShifts = array();
119 $iknow = array('date');
120
121 $allCalendars = $this->common->findAllCalendars();
122 if( count($allCalendars) <= 1 ) $iknow[] = 'calendar';
123
124 $this->shiftsDuration->reset();
125 foreach( $shifts as $shift ){
126 $this->shiftsDuration->add( $shift );
127 $start = $shift->getStart();
128 $end = $shift->getEnd();
129
130 $startDayTime = substr($start, 8, 4);
131 $endDayTime = substr($end, 8, 4);
132 $shiftAllDay = ( (0 == $startDayTime) && (0 == $endDayTime) ) ? TRUE : FALSE;
133
134 $this->t->setDateTimeDb( $end )->modify('-1 second');
135 $shiftEndDate = $this->t->formatDateDb();
136
137 $this->t->setDateTimeDb( $start );
138 $shiftStartDate = $this->t->formatDateDb();
139
140 $rexDate = $shiftStartDate;
141 while( $rexDate <= $shiftEndDate ){
142 if( in_array($rexDate, $dates) ){
143 if( ! array_key_exists($rexDate, $viewShifts) ){
144 $viewShifts[$rexDate] = array();
145 }
146 $viewShifts[$rexDate][] = $shift;
147 }
148
149 if( ! $shiftAllDay ){
150 break;
151 }
152 $this->t->modify( '+1 day' );
153 $rexDate = $this->t->formatDateDb();
154 }
155 }
156
157 $rows = array();
158
159 $row = array();
160 foreach( $dates as $date ){
161 if( ! $date ){
162 $row[] = NULL;
163 continue;
164 }
165
166 $cell = array();
167
168 $dateView = $this->self->renderDateLabel( $date );
169
170 // SHIFTS DURATION
171 $counted = 0;
172 $this->shiftsDuration->reset();
173
174 if( isset($viewShifts[$date]) ){
175 $dateStart = $this->t->setDateDb( $date )
176 ->formatDateTimeDb()
177 ;
178 $dateEnd = $this->t->modify('+1 day')
179 ->formatDateTimeDb()
180 ;
181 foreach( $viewShifts[$date] as $shift ){
182 if( $shift->isMultiDay() ){
183 $durationShift = clone $shift;
184 if( $dateStart > $durationShift->getStart() ){
185 $durationShift->setStart( $dateStart );
186 }
187 if( $dateEnd < $durationShift->getEnd() ){
188 $durationShift->setEnd( $dateEnd );
189 }
190 $this->shiftsDuration->add( $durationShift );
191 }
192 else {
193 $this->shiftsDuration->add( $shift );
194 }
195 $counted++;
196 }
197 }
198
199 if( $counted ){
200 $outReport = $this->common->renderReport( $this->shiftsDuration, FALSE );
201 $outReport = $this->ui->makeSpan( $outReport )
202 ->tag('font-size', 2)
203 ;
204 $dateView = $this->ui->makeList( array($dateView, $outReport) )
205 ->gutter(1)
206 ;
207 }
208
209 $dateView = $this->ui->makeBlock( $dateView )
210 ->tag('align', 'center')
211 ;
212
213 $cell[] = $dateView;
214
215 if( isset($viewShifts[$date]) ){
216 $shiftsView = $this->self->renderDay( $viewShifts[$date], $iknow );
217 $cell[] = $shiftsView;
218 }
219
220 $to = 'new';
221 $toParams = array(
222 'date' => $date
223 );
224 if( array_key_exists('employee', $params) && (count($params['employee']) == 1) ){
225 if( ! in_array(-1, $params['employee']) ){
226 $toParams['employee'] = $params['employee'][0];
227 }
228 }
229
230 $links = array();
231
232 if( $this->allCombosShift ){
233 $label = '+' . ' ' . '__Shift__';
234 $thisTo = 'new/shift';
235 $thisTo = array( $thisTo, $toParams );
236 $link = $this->ui->makeAhref( $thisTo, $label )
237 ->tag('tab-link')
238 ->tag('align', 'center')
239 // ->addAttr('title', '__Add New__')
240 ;
241 if( $today > $date ){
242 $link->tag('muted', 3);
243 }
244 $links[] = $link;
245 }
246
247 if( $this->allCombosTimeoff ){
248 $label = '+' . ' ' . '__Time Off__';
249 $thisTo = 'new/timeoff';
250 $thisTo = array( $thisTo, $toParams );
251 $link = $this->ui->makeAhref( $thisTo, $label )
252 ->tag('tab-link')
253 ->tag('align', 'center')
254 // ->addAttr('title', '__Add New__')
255 ;
256 if( $today > $date ){
257 $link->tag('muted', 3);
258 }
259 $links[] = $link;
260 }
261
262 $links = $this->ui->makeList( $links )->gutter(0);
263
264 $cell[] = $links;
265
266 $cell = $this->ui->makeList( $cell )
267 ->gutter(1)
268 ->tag('margin', 1)
269 ;
270
271 $row[] = $cell;
272 }
273
274 $rows[] = $row;
275
276 $out = $this->ui->makeTable( NULL, $rows, FALSE )
277 ->gutter(0)
278 ->setBordered( $this->borderColor )
279 // ->setSegments( $weekSegments )
280 ;
281
282 return $out;
283 }
284
285 public function renderByCalendar()
286 {
287 $slug = $this->request->getSlug();
288 $today = $this->t->setNow()->formatDateDb();
289
290 $calendars = $this->common->getCalendars();
291 $employees = $this->common->getEmployees();
292 $shifts = $this->common->getShifts();
293
294 // finalize calendars to include those that employee was removed from but still have shifts in
295 $listCalendarId = array_keys( $calendars );
296 $dictCalendarId = array_combine( $listCalendarId, $listCalendarId );
297 foreach( $shifts as $shift ){
298 $calendar = $shift->getCalendar();
299 if( ! $calendar ) continue;
300 $calendarId = $calendar->getId();
301 $dictCalendarId[ $calendarId ] = $calendarId;
302 }
303 if( count($dictCalendarId) > count($calendars) ){
304 $allCalendars = $this->common->findAllCalendars();
305 $calendars = array_intersect_key( $allCalendars, $dictCalendarId );
306 }
307
308 // we can probably have archived calendars so if such calendars have no shifts then skip them
309 $removeArchivedCalendars = array();
310 foreach( $calendars as $calendar ){
311 if( $calendar->isArchived() ){
312 $removeArchivedCalendars[ $calendar->getId() ] = $calendar->getId();
313 }
314 }
315 if( $removeArchivedCalendars ){
316 foreach( $shifts as $shift ){
317 $calendar = $shift->getCalendar();
318 $id = $calendar ? $calendar->getId() : 0;
319 if( isset($removeArchivedCalendars[$id]) ){
320 unset( $removeArchivedCalendars[$id] );
321 }
322 if( ! $removeArchivedCalendars ){
323 break;
324 }
325 }
326 foreach( $removeArchivedCalendars as $id ){
327 unset( $calendars[$id] );
328 }
329 reset( $shifts );
330 }
331
332 $disabledWeekdays = $this->settings->get( 'skip_weekdays', TRUE );
333
334 $params = $this->request->getParams();
335 $startDate = $params['start'];
336
337 $this->t->setDateDb( $startDate )->setStartWeek();
338 $dates = array();
339
340 for( $ii = 0; $ii <= 6; $ii++ ){
341 if( $disabledWeekdays ){
342 $wkd = $this->t->getWeekday();
343 if( in_array($wkd, $disabledWeekdays) ){
344 $this->t->modify('+1 day');
345 continue;
346 }
347 }
348 $dates[] = $this->t->formatDateDb();
349 $this->t->modify('+1 day');
350 }
351
352 $view_calendars = array();
353 foreach( $calendars as $calendar ){
354 $calendarId = $calendar->getId();
355
356 $label = $this->calendarsPresenter->presentTitle( $calendar );
357 $title = htmlspecialchars( $calendar->getTitle() );
358 $description = $calendar->getDescription();
359 if( strlen($description) ){
360 $description = htmlspecialchars( $description );
361 $title .= "\n" . $description;
362 }
363
364 $label = $this->ui->makeSpan( $label )
365 ->addAttr( 'title', $title )
366 ;
367
368 $view_calendars[ $calendarId ] = $label;
369 }
370
371 $view_shifts = array();
372
373 $iknow = array('calendar', 'date');
374 $hori = FALSE;
375
376 $allEmployees = $this->common->findAllEmployees();
377 if( count($allEmployees) < 2 ){
378 $iknow[] = 'employee';
379 }
380
381 foreach( $shifts as $shift ){
382 $calendar = $shift->getCalendar();
383 $id = $calendar->getId();
384
385 if( ! array_key_exists($id, $view_shifts) ){
386 $view_shifts[$id] = array();
387 }
388
389 $start = $shift->getStart();
390 $end = $shift->getEnd();
391
392 $startDayTime = substr($start, 8, 4);
393 $endDayTime = substr($end, 8, 4);
394 $shiftAllDay = ( (0 == $startDayTime) && (0 == $endDayTime) ) ? TRUE : FALSE;
395
396 $this->t->setDateTimeDb( $end )->modify('-1 second');
397 $shiftEndDate = $this->t->formatDateDb();
398
399 $this->t->setDateTimeDb( $start );
400 $shiftStartDate = $this->t->formatDateDb();
401
402 $rexDate = $shiftStartDate;
403 while( $rexDate <= $shiftEndDate ){
404 if( in_array($rexDate, $dates) ){
405 if( ! array_key_exists($rexDate, $view_shifts[$id]) ){
406 $view_shifts[$id][$rexDate] = array();
407 }
408 $view_shifts[$id][$rexDate][] = $shift;
409 }
410
411 if( ! $shiftAllDay ){
412 break;
413 }
414 $this->t->modify( '+1 day' );
415 $rexDate = $this->t->formatDateDb();
416 }
417 }
418
419 $header = array();
420 $header[] = null;
421
422 foreach( $dates as $date ){
423 $this->t->setDateDb( $date );
424 $dateView = $this->self->renderDateLabel( $date );
425
426 // SHIFTS DURATION
427 $counted = 0;
428 $this->shiftsDuration->reset();
429
430 reset( $view_shifts );
431 foreach( $view_shifts as $id => $shifts2 ){
432 if( isset($shifts2[$date]) ){
433 $dateStart = $this->t->setDateDb( $date )
434 ->formatDateTimeDb()
435 ;
436 $dateEnd = $this->t->modify('+1 day')
437 ->formatDateTimeDb()
438 ;
439 foreach( $shifts2[$date] as $shift ){
440 if( $shift->isMultiDay() ){
441 $durationShift = clone $shift;
442 if( $dateStart > $durationShift->getStart() ){
443 $durationShift->setStart( $dateStart );
444 }
445 if( $dateEnd < $durationShift->getEnd() ){
446 $durationShift->setEnd( $dateEnd );
447 }
448 $this->shiftsDuration->add( $durationShift );
449 }
450 else {
451 $this->shiftsDuration->add( $shift );
452 }
453 $counted++;
454 }
455 }
456 }
457 if( $counted ){
458 $outReport = $this->common->renderReport( $this->shiftsDuration, FALSE );
459 $outReport = $this->ui->makeSpan( $outReport )
460 ->tag('font-size', 2)
461 ;
462 $dateView = $this->ui->makeList( array($dateView, $outReport) )
463 ->gutter(1)
464 ;
465 }
466
467 $dateView = $this->ui->makeBlock( $dateView )
468 ->tag('align', 'center')
469 ;
470
471 $header[] = $dateView;
472 }
473
474 $rows = array();
475
476 // link templates to speed things up
477 $toParams = array(
478 'calendar' => '{CID}',
479 'date' => '{DATE}'
480 );
481 $thisTo = 'new/shift';
482 $thisTo = array( $thisTo, $toParams );
483 $thisHref = $this->uri->makeUrl( $thisTo );
484
485 $linkTemplateShift = '<a title="+ __Shift__" class="hc-block hc-theme-tab-link hc-align-center" href="' . $thisHref . '">+ __Shift__</a>';
486 $linkTemplateShiftMuted = '<a title="+ __Shift__" class="hc-block hc-theme-tab-link hc-align-center hc-muted3" href="' . $thisHref . '">+ __Shift__</a>';
487
488 $toParams = array(
489 'calendar' => '{CID}',
490 'date' => '{DATE}'
491 );
492 $thisTo = 'new/timeoff';
493 $thisTo = array( $thisTo, $toParams );
494 $thisHref = $this->uri->makeUrl( $thisTo );
495
496 $linkTemplateTimeoff = '<a title="+ __Time Off__" class="hc-block hc-theme-tab-link hc-align-center" href="' . $thisHref . '">+ __Time Off__</a>';
497 $linkTemplateTimeoffMuted = '<a title="+ __Time Off__" class="hc-block hc-theme-tab-link hc-align-center hc-muted3" href="' . $thisHref . '">+ __Time Off__</a>';
498
499 foreach( $view_calendars as $id => $calendarView ){
500 $row = array();
501
502 $thisCalendar = $calendars[$id];
503 $addOk = FALSE;
504 if( $thisCalendar->isTimeoff() ){
505 $label = '+ ' . '__Time Off__';
506 if( isset($toParams['employee']) ){
507 $testComboId = $id . '-' . $toParams['employee'];
508 if( isset($this->allCombosTimeoff[$testComboId]) ){
509 $addOk = TRUE;
510 }
511 }
512 else {
513 $testComboId = $id . '-';
514 reset( $this->allCombosTimeoff );
515 foreach( $this->allCombosTimeoff as $comboId ){
516 if( $testComboId == substr($comboId, 0, strlen($testComboId)) ){
517 $addOk = TRUE;
518 break;
519 }
520 }
521 }
522 }
523 else {
524 $label = '+ ' . '__Shift__';
525 if( isset($toParams['employee']) ){
526 $testComboId = $id . '-' . $toParams['employee'];
527 if( isset($this->allCombosShift[$testComboId]) ){
528 $addOk = TRUE;
529 }
530 }
531 else {
532 $testComboId = $id . '-';
533 reset( $this->allCombosShift );
534 foreach( $this->allCombosShift as $comboId ){
535 if( $testComboId == substr($comboId, 0, strlen($testComboId)) ){
536 $addOk = TRUE;
537 break;
538 }
539 }
540 }
541 }
542
543 if( $addOk ){
544 $to = 'new';
545 $toParams = array(
546 'calendar' => $id,
547 // 'date' => $date
548 );
549 if( array_key_exists('employee', $params) && (count($params['employee']) == 1) ){
550 if( ! in_array(-1, $params['employee']) ){
551 $toParams['employee'] = $params['employee'][0];
552 }
553 }
554
555 $to = array( $to, $toParams );
556
557 $link = $this->ui->makeAhref( $to, $label )
558 ->tag('tab-link')
559 ->tag('align', 'center')
560 ;
561 // if( $today > $date ){
562 // $link->tag('muted', 3);
563 // }
564
565 $calendarView = $this->ui->makeList( array($calendarView, $link) )
566 ->gutter(1)
567 ;
568 }
569
570 $this->shiftsDuration->reset();
571 if( isset($view_shifts[$id]) ){
572 foreach( $view_shifts[$id] as $date => $dateShifts ){
573 foreach( $dateShifts as $shift ){
574 $this->shiftsDuration->add( $shift );
575 }
576 }
577
578 $outReport = $this->common->renderReport( $this->shiftsDuration, FALSE );
579 $outReport = $this->ui->makeSpan( $outReport )
580 ->tag('font-size', 2)
581 ;
582 $calendarView = $this->ui->makeList( array($calendarView, $outReport) )
583 ->gutter(1)
584 ;
585 }
586
587 $calendarView = $this->ui->makeBlock( $calendarView )
588 ->tag('padding', 2)
589 ->tag('nowrap')
590 ;
591 $row[] = $calendarView;
592
593 foreach( $dates as $date ){
594 $cell = array();
595
596 if( isset($view_shifts[$id][$date]) ){
597 $shiftsView = $this->self->renderDay( $view_shifts[$id][$date], $iknow );
598 $cell[] = $shiftsView;
599 }
600
601 $thisCalendar = $calendars[$id];
602
603 $to = 'new';
604 $toParams = array(
605 'calendar' => $id,
606 'date' => $date
607 );
608 if( array_key_exists('employee', $params) && (count($params['employee']) == 1) ){
609 if( ! in_array(-1, $params['employee']) ){
610 $toParams['employee'] = $params['employee'][0];
611 }
612 }
613
614 if( $addOk ){
615 /*
616 $to = array( $to, $toParams );
617
618 $link = $this->ui->makeAhref( $to, $label )
619 ->tag('tab-link')
620 ->tag('align', 'center')
621 ;
622 if( $today > $date ){
623 $link->tag('muted', 3);
624 }
625 */
626 if( $today > $date ){
627 if( $thisCalendar->isTimeoff() ){
628 $link = str_replace( array('{CID}', '{DATE}'), array($id, $date), $linkTemplateTimeoffMuted );
629 }
630 else {
631 $link = str_replace( array('{CID}', '{DATE}'), array($id, $date), $linkTemplateShiftMuted );
632 }
633 }
634 else {
635 if( $thisCalendar->isTimeoff() ){
636 $link = str_replace( array('{CID}', '{DATE}'), array($id, $date), $linkTemplateTimeoff );
637 }
638 else {
639 $link = str_replace( array('{CID}', '{DATE}'), array($id, $date), $linkTemplateShift );
640 }
641 }
642
643 $cell[] = $link;
644 }
645
646 $cell = $this->ui->makeList( $cell )
647 ->gutter(1)
648 ->tag('margin', 1)
649 ;
650
651 $row[] = $cell;
652 }
653
654 $rows[] = $row;
655 }
656
657 $out = $this->ui->makeTable( $header, $rows, FALSE )
658 ->gutter(0)
659 ->setBordered( $this->borderColor )
660 // ->setSegments( $weekSegments )
661 ;
662
663 return $out;
664 }
665
666 public function renderByEmployee()
667 {
668 $slug = $this->request->getSlug();
669 $today = $this->t->setNow()->formatDateDb();
670
671 $calendars = $this->common->getCalendars();
672 $employees = $this->common->getEmployees();
673
674 $shifts = $this->common->getShifts();
675
676 // finalize employees to include those that employee was removed from but still have shifts in
677 $listEmployeeId = array_keys( $employees );
678 $dictEmployeeId = array_combine( $listEmployeeId, $listEmployeeId );
679 foreach( $shifts as $shift ){
680 $employee = $shift->getEmployee();
681 if( ! $employee ) continue;
682 $employeeId = $employee->getId();
683 $dictEmployeeId[ $employeeId ] = $employeeId;
684 }
685 if( count($dictEmployeeId) > count($employees) ){
686 $allEmployees = $this->common->findAllEmployees();
687 $employees = array_intersect_key( $allEmployees, $dictEmployeeId );
688 }
689
690 // we can probably have archived employees so if such employees have no shifts then skip them
691 $removeArchivedEmployees = array();
692 foreach( $employees as $employee ){
693 if( $employee->isArchived() ){
694 $removeArchivedEmployees[ $employee->getId() ] = $employee->getId();
695 }
696 }
697 if( $removeArchivedEmployees ){
698 foreach( $shifts as $shift ){
699 $employee = $shift->getEmployee();
700 $id = $employee ? $employee->getId() : 0;
701 if( isset($removeArchivedEmployees[$id]) ){
702 unset( $removeArchivedEmployees[$id] );
703 }
704 if( ! $removeArchivedEmployees ){
705 break;
706 }
707 }
708 foreach( $removeArchivedEmployees as $id ){
709 unset( $employees[$id] );
710 }
711 reset( $shifts );
712 }
713
714 $disabledWeekdays = $this->settings->get( 'skip_weekdays', TRUE );
715
716 $params = $this->request->getParams();
717 $startDate = $params['start'];
718
719 $this->t->setDateDb( $startDate )->setStartWeek();
720 $dates = array();
721
722 for( $ii = 0; $ii <= 6; $ii++ ){
723 if( $disabledWeekdays ){
724 $wkd = $this->t->getWeekday();
725 if( in_array($wkd, $disabledWeekdays) ){
726 $this->t->modify('+1 day');
727 continue;
728 }
729 }
730
731 $dates[] = $this->t->formatDateDb();
732 $this->t->modify('+1 day');
733 }
734
735 $view_employees = array();
736 foreach( $employees as $employee ){
737 $label = $this->employeesPresenter->presentTitle( $employee );
738 $title = htmlspecialchars( $label );
739
740 $description = $employee->getDescription();
741 if( strlen($description) ){
742 $imgpos = strpos( $description, '<img' );
743 if( false !== $imgpos ){
744 $label = $this->ui->makeList( array($label, $description) );
745 }
746 else {
747 $title .= "\n" . htmlspecialchars( $description );
748 }
749 }
750
751 $label = $this->ui->makeSpan( $label )
752 ->tag( 'font-size', 4 )
753 ->addAttr( 'title', $title )
754 ;
755
756 $view_employees[ $employee->getId() ] = $label;
757 }
758
759 $view_shifts = array();
760
761 $iknow = array('employee', 'date');
762
763 $allCalendars = $this->common->findAllCalendars();
764 if( count($allCalendars) <= 1 ) $iknow[] = 'calendar';
765
766 $hori = FALSE;
767
768 foreach( $shifts as $shift ){
769 $employee = $shift->getEmployee();
770 $id = $employee ? $employee->getId() : 0;
771
772 if( ! array_key_exists($id, $view_shifts) ){
773 $view_shifts[$id] = array();
774 }
775
776 $start = $shift->getStart();
777 $end = $shift->getEnd();
778
779 $startDayTime = substr($start, 8, 4);
780 $endDayTime = substr($end, 8, 4);
781 $shiftAllDay = ( (0 == $startDayTime) && (0 == $endDayTime) ) ? TRUE : FALSE;
782
783 $this->t->setDateTimeDb( $end )->modify('-1 second');
784 $shiftEndDate = $this->t->formatDateDb();
785
786 $this->t->setDateTimeDb( $start );
787 $shiftStartDate = $this->t->formatDateDb();
788
789 $rexDate = $shiftStartDate;
790 while( $rexDate <= $shiftEndDate ){
791 if( in_array($rexDate, $dates) ){
792 if( ! array_key_exists($rexDate, $view_shifts[$id]) ){
793 $view_shifts[$id][$rexDate] = array();
794 }
795 $view_shifts[$id][$rexDate][] = $shift;
796 }
797
798 if( ! $shiftAllDay ){
799 break;
800 }
801 $this->t->modify( '+1 day' );
802 $rexDate = $this->t->formatDateDb();
803 }
804 }
805
806 $header = array();
807 $header[] = NULL;
808 foreach( $dates as $date ){
809 $this->t->setDateDb( $date );
810 $dateView = $this->self->renderDateLabel( $date );
811
812 // SHIFTS DURATION
813 $counted = 0;
814 $this->shiftsDuration->reset();
815
816 reset( $view_shifts );
817 foreach( $view_shifts as $id => $shifts2 ){
818 if( isset($shifts2[$date]) ){
819 $dateStart = $this->t->setDateDb( $date )
820 ->formatDateTimeDb()
821 ;
822 $dateEnd = $this->t->modify('+1 day')
823 ->formatDateTimeDb()
824 ;
825 foreach( $shifts2[$date] as $shift ){
826 if( $shift->isMultiDay() ){
827 $durationShift = clone $shift;
828 if( $dateStart > $durationShift->getStart() ){
829 $durationShift->setStart( $dateStart );
830 }
831 if( $dateEnd < $durationShift->getEnd() ){
832 $durationShift->setEnd( $dateEnd );
833 }
834 $this->shiftsDuration->add( $durationShift );
835 }
836 else {
837 $this->shiftsDuration->add( $shift );
838 }
839 $counted++;
840 }
841 }
842 }
843 if( $counted ){
844 $outReport = $this->common->renderReport( $this->shiftsDuration, FALSE );
845 $outReport = $this->ui->makeSpan( $outReport )
846 ->tag('font-size', 2)
847 ;
848 $dateView = $this->ui->makeList( array($dateView, $outReport) )
849 ->gutter(1)
850 ;
851 }
852
853 $dateView = $this->ui->makeBlock( $dateView )
854 ->tag('align', 'center')
855 ;
856
857 $header[] = $dateView;
858 }
859
860 $rows = array();
861
862 // link templates to speed things up
863 $toParams = array(
864 'employee' => '{EID}',
865 'date' => '{DATE}'
866 );
867 $thisTo = 'new/shift';
868 $thisTo = array( $thisTo, $toParams );
869 $thisHref = $this->uri->makeUrl( $thisTo );
870
871 $linkTemplateShift = '<a title="+ __Shift__" class="hc-block hc-theme-tab-link hc-align-center" href="' . $thisHref . '">+ __Shift__</a>';
872 $linkTemplateShiftMuted = '<a title="+ __Shift__" class="hc-block hc-theme-tab-link hc-align-center hc-muted3" href="' . $thisHref . '">+ __Shift__</a>';
873
874 $toParams = array(
875 'employee' => '{EID}',
876 'date' => '{DATE}'
877 );
878 $thisTo = 'new/timeoff';
879 $thisTo = array( $thisTo, $toParams );
880 $thisHref = $this->uri->makeUrl( $thisTo );
881
882 $linkTemplateTimeoff = '<a title="+ __Time Off__" class="hc-block hc-theme-tab-link hc-align-center" href="' . $thisHref . '">+ __Time Off__</a>';
883 $linkTemplateTimeoffMuted = '<a title="+ __Time Off__" class="hc-block hc-theme-tab-link hc-align-center hc-muted3" href="' . $thisHref . '">+ __Time Off__</a>';
884
885 foreach( $view_employees as $id => $employeeView ){
886 $row = array();
887
888 if( isset($view_shifts[$id]) ){
889 $this->shiftsDuration->reset();
890 $counted = 0;
891 foreach( $view_shifts[$id] as $date => $dateShifts ){
892 foreach( $dateShifts as $shift ){
893 $shiftCalendar = $shift->getCalendar();
894 // if( ! $shiftCalendar->isShift() ){
895 // continue;
896 // }
897 $this->shiftsDuration->add( $shift );
898 $counted++;
899 }
900 }
901
902 if( $counted ){
903 $outReport = $this->common->renderReport( $this->shiftsDuration, FALSE );
904 $outReport = $this->ui->makeSpan( $outReport )
905 ->tag('font-size', 2)
906 ;
907 $employeeView = $this->ui->makeList( array($employeeView, $outReport) )
908 ->gutter(1)
909 ;
910 }
911 }
912
913 $thisShifts = isset( $view_shifts[$id] ) ? $view_shifts[$id] : array();
914 $employeeView = $this->common->employeeRowLabel( $employeeView, $id, 'week', $dates, $thisShifts );
915
916 $employeeView = $this->ui->makeBlock( $employeeView )
917 ->tag('padding', 2)
918 ->tag('nowrap')
919 ;
920 $row[] = $employeeView;
921
922 foreach( $dates as $date ){
923 $cell = array();
924
925 if( isset($view_shifts[$id][$date]) ){
926 $shiftsView = $this->self->renderDay( $view_shifts[$id][$date], $iknow );
927 $cell[] = $shiftsView;
928 }
929
930 $toParams = array(
931 'employee' => $id,
932 'date' => $date
933 );
934
935 $links = array();
936
937 $comboId = 0 . '-' . $id;
938 if( isset($this->allCombosShift[$comboId]) ){
939 /*
940 $label = '+' . ' ' . '__Shift__';
941 $thisTo = 'new/shift';
942 $thisTo = array( $thisTo, $toParams );
943 $link = $this->ui->makeAhref( $thisTo, $label )
944 ->tag('tab-link')
945 ->tag('align', 'center')
946 ;
947 if( $today > $date ){
948 $link->tag('muted', 3);
949 }
950 */
951 if( $today > $date ){
952 $link = str_replace( array('{EID}', '{DATE}'), array($id, $date), $linkTemplateShiftMuted );
953 }
954 else {
955 $link = str_replace( array('{EID}', '{DATE}'), array($id, $date), $linkTemplateShift );
956 }
957
958 $links[] = $link;
959 }
960
961 if( isset($this->allCombosTimeoff[$comboId]) ){
962 /*
963 $label = '+' . ' ' . '__Time Off__';
964 $thisTo = 'new/timeoff';
965 $thisTo = array( $thisTo, $toParams );
966 $link = $this->ui->makeAhref( $thisTo, $label )
967 ->tag('tab-link')
968 ->tag('align', 'center')
969 ;
970 if( $today > $date ){
971 $link->tag('muted', 3);
972 }
973 */
974
975 if( $today > $date ){
976 $link = str_replace( array('{EID}', '{DATE}'), array($id, $date), $linkTemplateTimeoffMuted );
977 }
978 else {
979 $link = str_replace( array('{EID}', '{DATE}'), array($id, $date), $linkTemplateTimeoff );
980 }
981
982 $links[] = $link;
983 }
984
985 if( $links ){
986 $links = $this->ui->makeList( $links )->gutter(0);
987 $cell[] = $links;
988 }
989
990 $cell = $this->ui->makeList( $cell )
991 ->gutter(1)
992 ->tag('margin', 1)
993 ;
994
995 $row[] = $cell;
996 }
997
998 $rows[] = $row;
999 }
1000
1001 $out = $this->ui->makeTable( $header, $rows, FALSE )
1002 ->gutter(0)
1003 ->setBordered( $this->borderColor )
1004 // ->setSegments( $weekSegments )
1005 ;
1006
1007 return $out;
1008 }
1009
1010 public function renderDay( $shifts, $iknow )
1011 {
1012 $return = NULL;
1013 if( ! $shifts ){
1014 return $return;
1015 }
1016
1017 $params = $this->request->getParams();
1018
1019 $hideui = $params['hideui'];
1020 $noZoom = in_array('shiftdetails', $hideui);
1021
1022 if( array_key_exists('employee', $params) && (count($params['employee']) == 1) ){
1023 if( ! in_array(-1, $params['employee']) ){
1024 $iknow[] = 'employee';
1025 }
1026 }
1027 if( array_key_exists('calendar', $params) && (count($params['calendar']) == 1) ){
1028 $iknow[] = 'calendar';
1029 }
1030
1031 // groups?
1032 $groups = array();
1033 $groupedShifts = array();
1034 reset( $shifts );
1035 foreach( $shifts as $shift ){
1036 if( ! $shift->isOpen() ){
1037 continue;
1038 }
1039
1040 $groupId = $shift->getGroupingId();
1041
1042 if( ! isset($groups[$groupId]) ){
1043 $groups[ $groupId ] = $shift->getId();
1044 $groupedShifts[ $shift->getId() ] = array( $shift->getId() => $shift );
1045 }
1046 else {
1047 $mainShiftId = $groups[ $groupId ];
1048 $groupedShifts[ $mainShiftId ][ $shift->getId() ] = $shift;
1049 $groupedShifts[ $shift->getId() ] = 0;
1050 }
1051 }
1052
1053 $hori = FALSE;
1054 $return = array();
1055 reset( $shifts );
1056 foreach( $shifts as $shift ){
1057 $id = $shift->getId();
1058
1059 if( isset($groupedShifts[$id]) && (! $groupedShifts[$id]) ){
1060 continue;
1061 }
1062
1063 $groupedQty = NULL;
1064 if( isset($groupedShifts[$id]) && (count($groupedShifts[$id]) > 1) ){
1065 $groupedQty = count($groupedShifts[$id]);
1066 }
1067
1068 $thisView = $this->widget->render( $shift, $iknow, $hori, $noZoom, $groupedQty );
1069 $shiftId = $shift->getId();
1070
1071 $buildMenuFromShifts = isset($groupedShifts[$id]) ? $groupedShifts[$id] : array( $shift );
1072 $menu = $this->shiftsCommon->bulkMenu( $buildMenuFromShifts );
1073 if( $menu ){
1074 $thisView = $this->ui->makeCollection( array($thisView, $menu) );
1075 }
1076
1077 $thisView = $this->ui->makeBlock( $thisView )
1078 ->tag('block')
1079 ->addAttr('class', 'sh4-shift-widget')
1080 ;
1081
1082 $return[] = $thisView;
1083 }
1084
1085 $return = $this->ui->makeList( $return )->gutter(1);
1086
1087 return $return;
1088 }
1089 }