PluginProbe
ShiftController Employee Shift Scheduling / 4.9.72
ShiftController Employee Shift Scheduling v4.9.72
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.72, at sh4/schedule/html/view/week.php

1,099 lines 29.2 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 $isPrintView = $this->request->isPrintView();
499
500 foreach( $view_calendars as $id => $calendarView ){
501 $row = array();
502
503 $thisCalendar = $calendars[$id];
504 $addOk = FALSE;
505 if( $thisCalendar->isTimeoff() ){
506 $label = '+ ' . '__Time Off__';
507 if( isset($toParams['employee']) ){
508 $testComboId = $id . '-' . $toParams['employee'];
509 if( isset($this->allCombosTimeoff[$testComboId]) ){
510 $addOk = TRUE;
511 }
512 }
513 else {
514 $testComboId = $id . '-';
515 reset( $this->allCombosTimeoff );
516 foreach( $this->allCombosTimeoff as $comboId ){
517 if( $testComboId == substr($comboId, 0, strlen($testComboId)) ){
518 $addOk = TRUE;
519 break;
520 }
521 }
522 }
523 }
524 else {
525 $label = '+ ' . '__Shift__';
526 if( isset($toParams['employee']) ){
527 $testComboId = $id . '-' . $toParams['employee'];
528 if( isset($this->allCombosShift[$testComboId]) ){
529 $addOk = TRUE;
530 }
531 }
532 else {
533 $testComboId = $id . '-';
534 reset( $this->allCombosShift );
535 foreach( $this->allCombosShift as $comboId ){
536 if( $testComboId == substr($comboId, 0, strlen($testComboId)) ){
537 $addOk = TRUE;
538 break;
539 }
540 }
541 }
542 }
543
544 if( $addOk ){
545 $to = 'new';
546 $toParams = array(
547 'calendar' => $id,
548 // 'date' => $date
549 );
550 if( array_key_exists('employee', $params) && (count($params['employee']) == 1) ){
551 if( ! in_array(-1, $params['employee']) ){
552 $toParams['employee'] = $params['employee'][0];
553 }
554 }
555
556 $to = array( $to, $toParams );
557
558 $link = $this->ui->makeAhref( $to, $label )
559 ->tag('tab-link')
560 ->tag('align', 'center')
561 ;
562 // if( $today > $date ){
563 // $link->tag('muted', 3);
564 // }
565
566 $calendarView = $this->ui->makeList( array($calendarView, $link) )
567 ->gutter(1)
568 ;
569 }
570
571 $this->shiftsDuration->reset();
572 if( isset($view_shifts[$id]) ){
573 foreach( $view_shifts[$id] as $date => $dateShifts ){
574 foreach( $dateShifts as $shift ){
575 $this->shiftsDuration->add( $shift );
576 }
577 }
578
579 $outReport = $this->common->renderReport( $this->shiftsDuration, FALSE );
580 $outReport = $this->ui->makeSpan( $outReport )
581 ->tag('font-size', 2)
582 ;
583 $calendarView = $this->ui->makeList( array($calendarView, $outReport) )
584 ->gutter(1)
585 ;
586 }
587
588 $calendarView = $this->ui->makeBlock( $calendarView )
589 ->tag('padding', 2)
590 ->tag('nowrap')
591 ;
592 $row[] = $calendarView;
593
594 foreach( $dates as $date ){
595 $cell = array();
596
597 if( isset($view_shifts[$id][$date]) ){
598 $shiftsView = $this->self->renderDay( $view_shifts[$id][$date], $iknow );
599 $cell[] = $shiftsView;
600 }
601
602 $thisCalendar = $calendars[$id];
603
604 $to = 'new';
605 $toParams = array(
606 'calendar' => $id,
607 'date' => $date
608 );
609 if( array_key_exists('employee', $params) && (count($params['employee']) == 1) ){
610 if( ! in_array(-1, $params['employee']) ){
611 $toParams['employee'] = $params['employee'][0];
612 }
613 }
614
615 if( $isPrintView ) $addOk = false;
616
617 if( $addOk ){
618 /*
619 $to = array( $to, $toParams );
620
621 $link = $this->ui->makeAhref( $to, $label )
622 ->tag('tab-link')
623 ->tag('align', 'center')
624 ;
625 if( $today > $date ){
626 $link->tag('muted', 3);
627 }
628 */
629 if( $today > $date ){
630 if( $thisCalendar->isTimeoff() ){
631 $link = str_replace( array('{CID}', '{DATE}'), array($id, $date), $linkTemplateTimeoffMuted );
632 }
633 else {
634 $link = str_replace( array('{CID}', '{DATE}'), array($id, $date), $linkTemplateShiftMuted );
635 }
636 }
637 else {
638 if( $thisCalendar->isTimeoff() ){
639 $link = str_replace( array('{CID}', '{DATE}'), array($id, $date), $linkTemplateTimeoff );
640 }
641 else {
642 $link = str_replace( array('{CID}', '{DATE}'), array($id, $date), $linkTemplateShift );
643 }
644 }
645
646 $cell[] = $link;
647 }
648
649 $cell = $this->ui->makeList( $cell )
650 ->gutter(1)
651 ->tag('margin', 1)
652 ;
653
654 $row[] = $cell;
655 }
656
657 $rows[] = $row;
658 }
659
660 $out = $this->ui->makeTable( $header, $rows, FALSE )
661 ->gutter(0)
662 ->setBordered( $this->borderColor )
663 // ->setSegments( $weekSegments )
664 ;
665
666 return $out;
667 }
668
669 public function renderByEmployee()
670 {
671 $slug = $this->request->getSlug();
672 $today = $this->t->setNow()->formatDateDb();
673
674 $calendars = $this->common->getCalendars();
675 $employees = $this->common->getEmployees();
676
677 $shifts = $this->common->getShifts();
678
679 // finalize employees to include those that employee was removed from but still have shifts in
680 $listEmployeeId = array_keys( $employees );
681 $dictEmployeeId = array_combine( $listEmployeeId, $listEmployeeId );
682 foreach( $shifts as $shift ){
683 $employee = $shift->getEmployee();
684 if( ! $employee ) continue;
685 $employeeId = $employee->getId();
686 $dictEmployeeId[ $employeeId ] = $employeeId;
687 }
688 if( count($dictEmployeeId) > count($employees) ){
689 $allEmployees = $this->common->findAllEmployees();
690 $employees = array_intersect_key( $allEmployees, $dictEmployeeId );
691 }
692
693 // we can probably have archived employees so if such employees have no shifts then skip them
694 $removeArchivedEmployees = array();
695 foreach( $employees as $employee ){
696 if( $employee->isArchived() ){
697 $removeArchivedEmployees[ $employee->getId() ] = $employee->getId();
698 }
699 }
700 if( $removeArchivedEmployees ){
701 foreach( $shifts as $shift ){
702 $employee = $shift->getEmployee();
703 $id = $employee ? $employee->getId() : 0;
704 if( isset($removeArchivedEmployees[$id]) ){
705 unset( $removeArchivedEmployees[$id] );
706 }
707 if( ! $removeArchivedEmployees ){
708 break;
709 }
710 }
711 foreach( $removeArchivedEmployees as $id ){
712 unset( $employees[$id] );
713 }
714 reset( $shifts );
715 }
716
717 $disabledWeekdays = $this->settings->get( 'skip_weekdays', TRUE );
718
719 $params = $this->request->getParams();
720 $startDate = $params['start'];
721
722 $this->t->setDateDb( $startDate )->setStartWeek();
723 $dates = array();
724
725 for( $ii = 0; $ii <= 6; $ii++ ){
726 if( $disabledWeekdays ){
727 $wkd = $this->t->getWeekday();
728 if( in_array($wkd, $disabledWeekdays) ){
729 $this->t->modify('+1 day');
730 continue;
731 }
732 }
733
734 $dates[] = $this->t->formatDateDb();
735 $this->t->modify('+1 day');
736 }
737
738 $view_employees = array();
739 foreach( $employees as $employee ){
740 $label = $this->employeesPresenter->presentTitle( $employee );
741 $title = htmlspecialchars( $label );
742
743 $description = $employee->getDescription();
744 if( strlen($description) ){
745 $imgpos = strpos( $description, '<img' );
746 if( false !== $imgpos ){
747 $label = $this->ui->makeList( array($label, $description) );
748 }
749 else {
750 $title .= "\n" . htmlspecialchars( $description );
751 }
752 }
753
754 $label = $this->ui->makeSpan( $label )
755 ->tag( 'font-size', 4 )
756 ->addAttr( 'title', $title )
757 ;
758
759 $view_employees[ $employee->getId() ] = $label;
760 }
761
762 $view_shifts = array();
763
764 $iknow = array('employee', 'date');
765
766 $allCalendars = $this->common->findAllCalendars();
767 if( count($allCalendars) <= 1 ) $iknow[] = 'calendar';
768
769 $hori = FALSE;
770
771 foreach( $shifts as $shift ){
772 $employee = $shift->getEmployee();
773 $id = $employee ? $employee->getId() : 0;
774
775 if( ! array_key_exists($id, $view_shifts) ){
776 $view_shifts[$id] = array();
777 }
778
779 $start = $shift->getStart();
780 $end = $shift->getEnd();
781
782 $startDayTime = substr($start, 8, 4);
783 $endDayTime = substr($end, 8, 4);
784 $shiftAllDay = ( (0 == $startDayTime) && (0 == $endDayTime) ) ? TRUE : FALSE;
785
786 $this->t->setDateTimeDb( $end )->modify('-1 second');
787 $shiftEndDate = $this->t->formatDateDb();
788
789 $this->t->setDateTimeDb( $start );
790 $shiftStartDate = $this->t->formatDateDb();
791
792 $rexDate = $shiftStartDate;
793 while( $rexDate <= $shiftEndDate ){
794 if( in_array($rexDate, $dates) ){
795 if( ! array_key_exists($rexDate, $view_shifts[$id]) ){
796 $view_shifts[$id][$rexDate] = array();
797 }
798 $view_shifts[$id][$rexDate][] = $shift;
799 }
800
801 if( ! $shiftAllDay ){
802 break;
803 }
804 $this->t->modify( '+1 day' );
805 $rexDate = $this->t->formatDateDb();
806 }
807 }
808
809 $header = array();
810 $header[] = NULL;
811 foreach( $dates as $date ){
812 $this->t->setDateDb( $date );
813 $dateView = $this->self->renderDateLabel( $date );
814
815 // SHIFTS DURATION
816 $counted = 0;
817 $this->shiftsDuration->reset();
818
819 reset( $view_shifts );
820 foreach( $view_shifts as $id => $shifts2 ){
821 if( isset($shifts2[$date]) ){
822 $dateStart = $this->t->setDateDb( $date )
823 ->formatDateTimeDb()
824 ;
825 $dateEnd = $this->t->modify('+1 day')
826 ->formatDateTimeDb()
827 ;
828 foreach( $shifts2[$date] as $shift ){
829 if( $shift->isMultiDay() ){
830 $durationShift = clone $shift;
831 if( $dateStart > $durationShift->getStart() ){
832 $durationShift->setStart( $dateStart );
833 }
834 if( $dateEnd < $durationShift->getEnd() ){
835 $durationShift->setEnd( $dateEnd );
836 }
837 $this->shiftsDuration->add( $durationShift );
838 }
839 else {
840 $this->shiftsDuration->add( $shift );
841 }
842 $counted++;
843 }
844 }
845 }
846 if( $counted ){
847 $outReport = $this->common->renderReport( $this->shiftsDuration, FALSE );
848 $outReport = $this->ui->makeSpan( $outReport )
849 ->tag('font-size', 2)
850 ;
851 $dateView = $this->ui->makeList( array($dateView, $outReport) )
852 ->gutter(1)
853 ;
854 }
855
856 $dateView = $this->ui->makeBlock( $dateView )
857 ->tag('align', 'center')
858 ;
859
860 $header[] = $dateView;
861 }
862
863 $rows = array();
864
865 // link templates to speed things up
866 $toParams = array(
867 'employee' => '{EID}',
868 'date' => '{DATE}'
869 );
870 $thisTo = 'new/shift';
871 $thisTo = array( $thisTo, $toParams );
872 $thisHref = $this->uri->makeUrl( $thisTo );
873
874 $linkTemplateShift = '<a title="+ __Shift__" class="hc-block hc-theme-tab-link hc-align-center" href="' . $thisHref . '">+ __Shift__</a>';
875 $linkTemplateShiftMuted = '<a title="+ __Shift__" class="hc-block hc-theme-tab-link hc-align-center hc-muted3" href="' . $thisHref . '">+ __Shift__</a>';
876
877 $toParams = array(
878 'employee' => '{EID}',
879 'date' => '{DATE}'
880 );
881 $thisTo = 'new/timeoff';
882 $thisTo = array( $thisTo, $toParams );
883 $thisHref = $this->uri->makeUrl( $thisTo );
884
885 $linkTemplateTimeoff = '<a title="+ __Time Off__" class="hc-block hc-theme-tab-link hc-align-center" href="' . $thisHref . '">+ __Time Off__</a>';
886 $linkTemplateTimeoffMuted = '<a title="+ __Time Off__" class="hc-block hc-theme-tab-link hc-align-center hc-muted3" href="' . $thisHref . '">+ __Time Off__</a>';
887 $isPrintView = $this->request->isPrintView();
888
889 foreach( $view_employees as $id => $employeeView ){
890 $row = array();
891
892 if( isset($view_shifts[$id]) ){
893 $this->shiftsDuration->reset();
894 $counted = 0;
895 foreach( $view_shifts[$id] as $date => $dateShifts ){
896 foreach( $dateShifts as $shift ){
897 $shiftCalendar = $shift->getCalendar();
898 // if( ! $shiftCalendar->isShift() ){
899 // continue;
900 // }
901 $this->shiftsDuration->add( $shift );
902 $counted++;
903 }
904 }
905
906 if( $counted ){
907 $outReport = $this->common->renderReport( $this->shiftsDuration, FALSE );
908 $outReport = $this->ui->makeSpan( $outReport )
909 ->tag('font-size', 2)
910 ;
911 $employeeView = $this->ui->makeList( array($employeeView, $outReport) )
912 ->gutter(1)
913 ;
914 }
915 }
916
917 $thisShifts = isset( $view_shifts[$id] ) ? $view_shifts[$id] : array();
918 $employeeView = $this->common->employeeRowLabel( $employeeView, $id, 'week', $dates, $thisShifts );
919
920 $employeeView = $this->ui->makeBlock( $employeeView )
921 ->tag('padding', 2)
922 ->tag('nowrap')
923 ;
924 $row[] = $employeeView;
925
926 foreach( $dates as $date ){
927 $cell = array();
928
929 if( isset($view_shifts[$id][$date]) ){
930 $shiftsView = $this->self->renderDay( $view_shifts[$id][$date], $iknow );
931 $cell[] = $shiftsView;
932 }
933
934 $toParams = array(
935 'employee' => $id,
936 'date' => $date
937 );
938
939 $links = array();
940
941 $comboId = 0 . '-' . $id;
942 if( isset($this->allCombosShift[$comboId]) ){
943 /*
944 $label = '+' . ' ' . '__Shift__';
945 $thisTo = 'new/shift';
946 $thisTo = array( $thisTo, $toParams );
947 $link = $this->ui->makeAhref( $thisTo, $label )
948 ->tag('tab-link')
949 ->tag('align', 'center')
950 ;
951 if( $today > $date ){
952 $link->tag('muted', 3);
953 }
954 */
955 if( $today > $date ){
956 $link = str_replace( array('{EID}', '{DATE}'), array($id, $date), $linkTemplateShiftMuted );
957 }
958 else {
959 $link = str_replace( array('{EID}', '{DATE}'), array($id, $date), $linkTemplateShift );
960 }
961
962 if( ! $isPrintView ){
963 $cell[] = $link;
964 }
965 }
966
967 if( isset($this->allCombosTimeoff[$comboId]) ){
968 /*
969 $label = '+' . ' ' . '__Time Off__';
970 $thisTo = 'new/timeoff';
971 $thisTo = array( $thisTo, $toParams );
972 $link = $this->ui->makeAhref( $thisTo, $label )
973 ->tag('tab-link')
974 ->tag('align', 'center')
975 ;
976 if( $today > $date ){
977 $link->tag('muted', 3);
978 }
979 */
980
981 if( $today > $date ){
982 $link = str_replace( array('{EID}', '{DATE}'), array($id, $date), $linkTemplateTimeoffMuted );
983 }
984 else {
985 $link = str_replace( array('{EID}', '{DATE}'), array($id, $date), $linkTemplateTimeoff );
986 }
987
988 if( ! $isPrintView ){
989 $cell[] = $link;
990 }
991 }
992
993 if( ! $isPrintView ){
994 if( $links ){
995 $links = $this->ui->makeList( $links )->gutter(0);
996 $cell[] = $links;
997 }
998 }
999
1000 $cell = $this->ui->makeList( $cell )
1001 ->gutter(1)
1002 ->tag('margin', 1)
1003 ;
1004
1005 $row[] = $cell;
1006 }
1007
1008 $rows[] = $row;
1009 }
1010
1011 $out = $this->ui->makeTable( $header, $rows, FALSE )
1012 ->gutter(0)
1013 ->setBordered( $this->borderColor )
1014 // ->setSegments( $weekSegments )
1015 ;
1016
1017 return $out;
1018 }
1019
1020 public function renderDay( $shifts, $iknow )
1021 {
1022 $return = NULL;
1023 if( ! $shifts ){
1024 return $return;
1025 }
1026
1027 $params = $this->request->getParams();
1028
1029 $hideui = $params['hideui'];
1030 $noZoom = in_array('shiftdetails', $hideui);
1031
1032 if( array_key_exists('employee', $params) && (count($params['employee']) == 1) ){
1033 if( ! in_array(-1, $params['employee']) ){
1034 $iknow[] = 'employee';
1035 }
1036 }
1037 if( array_key_exists('calendar', $params) && (count($params['calendar']) == 1) ){
1038 $iknow[] = 'calendar';
1039 }
1040
1041 // groups?
1042 $groups = array();
1043 $groupedShifts = array();
1044 reset( $shifts );
1045 foreach( $shifts as $shift ){
1046 if( ! $shift->isOpen() ){
1047 continue;
1048 }
1049
1050 $groupId = $shift->getGroupingId();
1051
1052 if( ! isset($groups[$groupId]) ){
1053 $groups[ $groupId ] = $shift->getId();
1054 $groupedShifts[ $shift->getId() ] = array( $shift->getId() => $shift );
1055 }
1056 else {
1057 $mainShiftId = $groups[ $groupId ];
1058 $groupedShifts[ $mainShiftId ][ $shift->getId() ] = $shift;
1059 $groupedShifts[ $shift->getId() ] = 0;
1060 }
1061 }
1062
1063 $hori = FALSE;
1064 $return = array();
1065 reset( $shifts );
1066 foreach( $shifts as $shift ){
1067 $id = $shift->getId();
1068
1069 if( isset($groupedShifts[$id]) && (! $groupedShifts[$id]) ){
1070 continue;
1071 }
1072
1073 $groupedQty = NULL;
1074 if( isset($groupedShifts[$id]) && (count($groupedShifts[$id]) > 1) ){
1075 $groupedQty = count($groupedShifts[$id]);
1076 }
1077
1078 $thisView = $this->widget->render( $shift, $iknow, $hori, $noZoom, $groupedQty );
1079 $shiftId = $shift->getId();
1080
1081 $buildMenuFromShifts = isset($groupedShifts[$id]) ? $groupedShifts[$id] : array( $shift );
1082 $menu = $this->shiftsCommon->bulkMenu( $buildMenuFromShifts );
1083 if( $menu ){
1084 $thisView = $this->ui->makeCollection( array($thisView, $menu) );
1085 }
1086
1087 $thisView = $this->ui->makeBlock( $thisView )
1088 ->tag('block')
1089 ->addAttr('class', 'sh4-shift-widget')
1090 ;
1091
1092 $return[] = $thisView;
1093 }
1094
1095 $return = $this->ui->makeList( $return )->gutter(1);
1096
1097 return $return;
1098 }
1099 }