Add user timetables

This commit is contained in:
Frederic Guillot 2015-03-09 21:37:10 -04:00
parent 7328995645
commit c870508923
45 changed files with 2014 additions and 5 deletions

View File

@ -57,6 +57,11 @@ use Symfony\Component\EventDispatcher\Event;
* @property \Model\TaskPosition $taskPosition
* @property \Model\TaskPermission $taskPermission
* @property \Model\TaskStatus $taskStatus
* @property \Model\Timetable $timetable
* @property \Model\TimetableDay $timetableDay
* @property \Model\TimetableWeek $timetableWeek
* @property \Model\TimetableExtra $timetableExtra
* @property \Model\TimetableOff $timetableOff
* @property \Model\TaskValidator $taskValidator
* @property \Model\TaskLink $taskLink
* @property \Model\CommentHistory $commentHistory

View File

@ -8,7 +8,7 @@ namespace Controller;
* @package controller
* @author Frederic Guillot
*/
class HourlyRate extends User
class Hourlyrate extends User
{
/**
* Display rate and form

View File

@ -0,0 +1,39 @@
<?php
namespace Controller;
use DateTime;
/**
* Timetable controller
*
* @package controller
* @author Frederic Guillot
*/
class Timetable extends User
{
/**
* Display timetable for the user
*
* @access public
*/
public function index()
{
$user = $this->getUser();
$from = $this->request->getStringParam('from', date('Y-m-d'));
$to = $this->request->getStringParam('to', date('Y-m-d', strtotime('next week')));
$timetable = $this->timetable->calculate($user['id'], new DateTime($from), new DateTime($to));
$this->response->html($this->layout('timetable/index', array(
'user' => $user,
'timetable' => $timetable,
'values' => array(
'from' => $from,
'to' => $to,
'controller' => 'timetable',
'action' => 'index',
'user_id' => $user['id'],
),
)));
}
}

View File

@ -0,0 +1,88 @@
<?php
namespace Controller;
/**
* Day Timetable controller
*
* @package controller
* @author Frederic Guillot
*/
class Timetableday extends User
{
/**
* Display timetable for the user
*
* @access public
*/
public function index(array $values = array(), array $errors = array())
{
$user = $this->getUser();
$this->response->html($this->layout('timetable_day/index', array(
'timetable' => $this->timetableDay->getByUser($user['id']),
'values' => $values + array('user_id' => $user['id']),
'errors' => $errors,
'user' => $user,
)));
}
/**
* Validate and save
*
* @access public
*/
public function save()
{
$values = $this->request->getValues();
list($valid, $errors) = $this->timetableDay->validateCreation($values);
if ($valid) {
if ($this->timetableDay->create($values['user_id'], $values['start'], $values['end'])) {
$this->session->flash(t('Time slot created successfully.'));
$this->response->redirect($this->helper->url('timetableday', 'index', array('user_id' => $values['user_id'])));
}
else {
$this->session->flashError(t('Unable to save this time slot.'));
}
}
$this->index($values, $errors);
}
/**
* Confirmation dialag box to remove a row
*
* @access public
*/
public function confirm()
{
$user = $this->getUser();
$this->response->html($this->layout('timetable_day/remove', array(
'slot_id' => $this->request->getIntegerParam('slot_id'),
'user' => $user,
)));
}
/**
* Remove a row
*
* @access public
*/
public function remove()
{
$this->checkCSRFParam();
$user = $this->getUser();
if ($this->timetableDay->remove($this->request->getIntegerParam('slot_id'))) {
$this->session->flash(t('Time slot removed successfully.'));
}
else {
$this->session->flash(t('Unable to remove this time slot.'));
}
$this->response->redirect($this->helper->url('timetableday', 'index', array('user_id' => $user['id'])));
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace Controller;
/**
* Over-time Timetable controller
*
* @package controller
* @author Frederic Guillot
*/
class Timetableextra extends TimetableOff
{
protected $model = 'timetableExtra';
protected $controller_url = 'timetableextra';
protected $template_dir = 'timetable_extra';
}

View File

@ -0,0 +1,107 @@
<?php
namespace Controller;
/**
* Time-off Timetable controller
*
* @package controller
* @author Frederic Guillot
*/
class Timetableoff extends User
{
protected $model = 'timetableOff';
protected $controller_url = 'timetableoff';
protected $template_dir = 'timetable_off';
/**
* Display timetable for the user
*
* @access public
*/
public function index(array $values = array(), array $errors = array())
{
$user = $this->getUser();
$paginator = $this->paginator
->setUrl($this->controller_url, 'index', array('user_id' => $user['id']))
->setMax(10)
->setOrder('date')
->setDirection('desc')
->setQuery($this->{$this->model}->getUserQuery($user['id']))
->calculate();
$this->response->html($this->layout($this->template_dir.'/index', array(
'values' => $values + array('user_id' => $user['id']),
'errors' => $errors,
'paginator' => $paginator,
'user' => $user,
)));
}
/**
* Validate and save
*
* @access public
*/
public function save()
{
$values = $this->request->getValues();
list($valid, $errors) = $this->{$this->model}->validateCreation($values);
if ($valid) {
if ($this->{$this->model}->create(
$values['user_id'],
$values['date'],
isset($values['all_day']) && $values['all_day'] == 1,
$values['start'],
$values['end'],
$values['comment'])) {
$this->session->flash(t('Time slot created successfully.'));
$this->response->redirect($this->helper->url($this->controller_url, 'index', array('user_id' => $values['user_id'])));
}
else {
$this->session->flashError(t('Unable to save this time slot.'));
}
}
$this->index($values, $errors);
}
/**
* Confirmation dialag box to remove a row
*
* @access public
*/
public function confirm()
{
$user = $this->getUser();
$this->response->html($this->layout($this->template_dir.'/remove', array(
'slot_id' => $this->request->getIntegerParam('slot_id'),
'user' => $user,
)));
}
/**
* Remove a row
*
* @access public
*/
public function remove()
{
$this->checkCSRFParam();
$user = $this->getUser();
if ($this->{$this->model}->remove($this->request->getIntegerParam('slot_id'))) {
$this->session->flash(t('Time slot removed successfully.'));
}
else {
$this->session->flash(t('Unable to remove this time slot.'));
}
$this->response->redirect($this->helper->url($this->controller_url, 'index', array('user_id' => $user['id'])));
}
}

View File

@ -0,0 +1,99 @@
<?php
namespace Controller;
/**
* Week Timetable controller
*
* @package controller
* @author Frederic Guillot
*/
class Timetableweek extends User
{
/**
* Display timetable for the user
*
* @access public
*/
public function index(array $values = array(), array $errors = array())
{
$user = $this->getUser();
if (empty($values)) {
$day = $this->timetableDay->getByUser($user['id']);
$values = array(
'user_id' => $user['id'],
'start' => isset($day[0]['start']) ? $day[0]['start'] : null,
'end' => isset($day[0]['end']) ? $day[0]['end'] : null,
);
}
$this->response->html($this->layout('timetable_week/index', array(
'timetable' => $this->timetableWeek->getByUser($user['id']),
'values' => $values,
'errors' => $errors,
'user' => $user,
)));
}
/**
* Validate and save
*
* @access public
*/
public function save()
{
$values = $this->request->getValues();
list($valid, $errors) = $this->timetableWeek->validateCreation($values);
if ($valid) {
if ($this->timetableWeek->create($values['user_id'], $values['day'], $values['start'], $values['end'])) {
$this->session->flash(t('Time slot created successfully.'));
$this->response->redirect($this->helper->url('timetableweek', 'index', array('user_id' => $values['user_id'])));
}
else {
$this->session->flashError(t('Unable to save this time slot.'));
}
}
$this->index($values, $errors);
}
/**
* Confirmation dialag box to remove a row
*
* @access public
*/
public function confirm()
{
$user = $this->getUser();
$this->response->html($this->layout('timetable_week/remove', array(
'slot_id' => $this->request->getIntegerParam('slot_id'),
'user' => $user,
)));
}
/**
* Remove a row
*
* @access public
*/
public function remove()
{
$this->checkCSRFParam();
$user = $this->getUser();
if ($this->timetableWeek->remove($this->request->getIntegerParam('slot_id'))) {
$this->session->flash(t('Time slot removed successfully.'));
}
else {
$this->session->flash(t('Unable to remove this time slot.'));
}
$this->response->redirect($this->helper->url('timetableweek', 'index', array('user_id' => $user['id'])));
}
}

View File

@ -677,4 +677,53 @@ class Helper
array('task_id' => $subtask['task_id'], 'subtask_id' => $subtask['id'], 'redirect' => $redirect)
);
}
/**
* Get all hours for day
*
* @access public
* @return array
*/
public function getDayHours()
{
$values = array();
foreach (range(0, 23) as $hour) {
foreach (array(0, 30) as $minute) {
$time = sprintf('%02d:%02d', $hour, $minute);
$values[$time] = $time;
}
}
return $values;
}
/**
* Get all days of a week
*
* @access public
* @return array
*/
public function getWeekDays()
{
$values = array();
foreach (range(1, 7) as $day) {
$values[$day] = $this->getWeekDay($day);
}
return $values;
}
/**
* Get the localized day name from the day number
*
* @access public
* @param integer $day Day number
* @return string
*/
public function getWeekDay($day)
{
return dt('%A', strtotime('next Monday +'.($day - 1).' days'));
}
}

View File

@ -1,6 +1,8 @@
<?php
return array(
// 'number.decimals_separator' => '',
// 'number.thousands_separator' => '',
'None' => 'Ingen',
'edit' => 'rediger',
'Edit' => 'Rediger',
@ -738,4 +740,37 @@ return array(
// 'Horizontal scrolling' => '',
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Remove hourly rate' => '',
// 'Do you really want to remove this hourly rate?' => '',
// 'Hourly rates' => '',
// 'Hourly rate' => '',
// 'Currency' => '',
// 'Effective date' => '',
// 'Add new rate' => '',
// 'Rate removed successfully.' => '',
// 'Unable to remove this rate.' => '',
// 'Unable to save the hourly rate.' => '',
// 'Hourly rate created successfully.' => '',
// 'Start time' => '',
// 'End time' => '',
// 'Comment' => '',
// 'All day' => '',
// 'Day' => '',
// 'Manage timetable' => '',
// 'Overtime timetable' => '',
// 'Time off timetable' => '',
// 'Timetable' => '',
// 'Work timetable' => '',
// 'Week timetable' => '',
// 'Day timetable' => '',
// 'From' => '',
// 'To' => '',
// 'Time slot created successfully.' => '',
// 'Unable to save this time slot.' => '',
// 'Time slot removed successfully.' => '',
// 'Unable to remove this time slot.' => '',
// 'Do you really want to remove this time slot?' => '',
// 'Remove time slot' => '',
// 'Add new time slot' => '',
// 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
);

View File

@ -1,6 +1,8 @@
<?php
return array(
// 'number.decimals_separator' => '',
// 'number.thousands_separator' => '',
'None' => 'Keines',
'edit' => 'Bearbeiten',
'Edit' => 'Bearbeiten',
@ -738,4 +740,37 @@ return array(
// 'Horizontal scrolling' => '',
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Remove hourly rate' => '',
// 'Do you really want to remove this hourly rate?' => '',
// 'Hourly rates' => '',
// 'Hourly rate' => '',
// 'Currency' => '',
// 'Effective date' => '',
// 'Add new rate' => '',
// 'Rate removed successfully.' => '',
// 'Unable to remove this rate.' => '',
// 'Unable to save the hourly rate.' => '',
// 'Hourly rate created successfully.' => '',
// 'Start time' => '',
// 'End time' => '',
// 'Comment' => '',
// 'All day' => '',
// 'Day' => '',
// 'Manage timetable' => '',
// 'Overtime timetable' => '',
// 'Time off timetable' => '',
// 'Timetable' => '',
// 'Work timetable' => '',
// 'Week timetable' => '',
// 'Day timetable' => '',
// 'From' => '',
// 'To' => '',
// 'Time slot created successfully.' => '',
// 'Unable to save this time slot.' => '',
// 'Time slot removed successfully.' => '',
// 'Unable to remove this time slot.' => '',
// 'Do you really want to remove this time slot?' => '',
// 'Remove time slot' => '',
// 'Add new time slot' => '',
// 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
);

View File

@ -1,6 +1,8 @@
<?php
return array(
// 'number.decimals_separator' => '',
// 'number.thousands_separator' => '',
'None' => 'Ninguno',
'edit' => 'modificar',
'Edit' => 'Modificar',
@ -738,4 +740,37 @@ return array(
// 'Horizontal scrolling' => '',
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Remove hourly rate' => '',
// 'Do you really want to remove this hourly rate?' => '',
// 'Hourly rates' => '',
// 'Hourly rate' => '',
// 'Currency' => '',
// 'Effective date' => '',
// 'Add new rate' => '',
// 'Rate removed successfully.' => '',
// 'Unable to remove this rate.' => '',
// 'Unable to save the hourly rate.' => '',
// 'Hourly rate created successfully.' => '',
// 'Start time' => '',
// 'End time' => '',
// 'Comment' => '',
// 'All day' => '',
// 'Day' => '',
// 'Manage timetable' => '',
// 'Overtime timetable' => '',
// 'Time off timetable' => '',
// 'Timetable' => '',
// 'Work timetable' => '',
// 'Week timetable' => '',
// 'Day timetable' => '',
// 'From' => '',
// 'To' => '',
// 'Time slot created successfully.' => '',
// 'Unable to save this time slot.' => '',
// 'Time slot removed successfully.' => '',
// 'Unable to remove this time slot.' => '',
// 'Do you really want to remove this time slot?' => '',
// 'Remove time slot' => '',
// 'Add new time slot' => '',
// 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
);

View File

@ -1,6 +1,8 @@
<?php
return array(
// 'number.decimals_separator' => '',
// 'number.thousands_separator' => '',
'None' => 'Ei mikään',
'edit' => 'muokkaa',
'Edit' => 'Muokkaa',
@ -738,4 +740,37 @@ return array(
// 'Horizontal scrolling' => '',
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Remove hourly rate' => '',
// 'Do you really want to remove this hourly rate?' => '',
// 'Hourly rates' => '',
// 'Hourly rate' => '',
// 'Currency' => '',
// 'Effective date' => '',
// 'Add new rate' => '',
// 'Rate removed successfully.' => '',
// 'Unable to remove this rate.' => '',
// 'Unable to save the hourly rate.' => '',
// 'Hourly rate created successfully.' => '',
// 'Start time' => '',
// 'End time' => '',
// 'Comment' => '',
// 'All day' => '',
// 'Day' => '',
// 'Manage timetable' => '',
// 'Overtime timetable' => '',
// 'Time off timetable' => '',
// 'Timetable' => '',
// 'Work timetable' => '',
// 'Week timetable' => '',
// 'Day timetable' => '',
// 'From' => '',
// 'To' => '',
// 'Time slot created successfully.' => '',
// 'Unable to save this time slot.' => '',
// 'Time slot removed successfully.' => '',
// 'Unable to remove this time slot.' => '',
// 'Do you really want to remove this time slot?' => '',
// 'Remove time slot' => '',
// 'Add new time slot' => '',
// 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
);

View File

@ -753,4 +753,26 @@ return array(
'Unable to remove this rate.' => 'Impossible de supprimer ce taux horaire.',
'Unable to save the hourly rate.' => 'Impossible de sauvegarder ce taux horaire.',
'Hourly rate created successfully.' => 'Taux horaire créé avec succès.',
'Start time' => 'Date de début',
'End time' => 'Date de fin',
'Comment' => 'Commentaire',
'All day' => 'Toute la journée',
'Day' => 'Jour',
'Manage timetable' => 'Gérer les horaires',
'Overtime timetable' => 'Heures supplémentaires',
'Time off timetable' => 'Heures d\'absences',
'Timetable' => 'Horaires',
'Work timetable' => 'Horaires travaillés',
'Week timetable' => 'Horaires de la semaine',
'Day timetable' => 'Horaire d\'une journée',
'From' => 'Depuis',
'To' => 'À',
'Time slot created successfully.' => 'Créneau horaire créé avec succès.',
'Unable to save this time slot.' => 'Impossible de sauvegarder ce créneau horaire.',
'Time slot removed successfully.' => 'Créneau horaire supprimé avec succès.',
'Unable to remove this time slot.' => 'Impossible de supprimer ce créneau horaire.',
'Do you really want to remove this time slot?' => 'Voulez-vous vraiment supprimer ce créneau horaire ?',
'Remove time slot' => 'Supprimer un créneau horaire',
'Add new time slot' => 'Ajouter un créneau horaire',
'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => 'Ces horaires sont utilisés lorsque la case « Toute la journée » est cochée pour les heures d\'absences ou supplémentaires programmées.',
);

View File

@ -1,6 +1,8 @@
<?php
return array(
// 'number.decimals_separator' => '',
// 'number.thousands_separator' => '',
'None' => 'Nincs',
'edit' => 'szerkesztés',
'Edit' => 'Szerkesztés',
@ -738,4 +740,37 @@ return array(
// 'Horizontal scrolling' => '',
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Remove hourly rate' => '',
// 'Do you really want to remove this hourly rate?' => '',
// 'Hourly rates' => '',
// 'Hourly rate' => '',
// 'Currency' => '',
// 'Effective date' => '',
// 'Add new rate' => '',
// 'Rate removed successfully.' => '',
// 'Unable to remove this rate.' => '',
// 'Unable to save the hourly rate.' => '',
// 'Hourly rate created successfully.' => '',
// 'Start time' => '',
// 'End time' => '',
// 'Comment' => '',
// 'All day' => '',
// 'Day' => '',
// 'Manage timetable' => '',
// 'Overtime timetable' => '',
// 'Time off timetable' => '',
// 'Timetable' => '',
// 'Work timetable' => '',
// 'Week timetable' => '',
// 'Day timetable' => '',
// 'From' => '',
// 'To' => '',
// 'Time slot created successfully.' => '',
// 'Unable to save this time slot.' => '',
// 'Time slot removed successfully.' => '',
// 'Unable to remove this time slot.' => '',
// 'Do you really want to remove this time slot?' => '',
// 'Remove time slot' => '',
// 'Add new time slot' => '',
// 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
);

View File

@ -1,6 +1,8 @@
<?php
return array(
// 'number.decimals_separator' => '',
// 'number.thousands_separator' => '',
'None' => 'Nessuno',
'edit' => 'modificare',
'Edit' => 'Modificare',
@ -738,4 +740,37 @@ return array(
// 'Horizontal scrolling' => '',
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Remove hourly rate' => '',
// 'Do you really want to remove this hourly rate?' => '',
// 'Hourly rates' => '',
// 'Hourly rate' => '',
// 'Currency' => '',
// 'Effective date' => '',
// 'Add new rate' => '',
// 'Rate removed successfully.' => '',
// 'Unable to remove this rate.' => '',
// 'Unable to save the hourly rate.' => '',
// 'Hourly rate created successfully.' => '',
// 'Start time' => '',
// 'End time' => '',
// 'Comment' => '',
// 'All day' => '',
// 'Day' => '',
// 'Manage timetable' => '',
// 'Overtime timetable' => '',
// 'Time off timetable' => '',
// 'Timetable' => '',
// 'Work timetable' => '',
// 'Week timetable' => '',
// 'Day timetable' => '',
// 'From' => '',
// 'To' => '',
// 'Time slot created successfully.' => '',
// 'Unable to save this time slot.' => '',
// 'Time slot removed successfully.' => '',
// 'Unable to remove this time slot.' => '',
// 'Do you really want to remove this time slot?' => '',
// 'Remove time slot' => '',
// 'Add new time slot' => '',
// 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
);

View File

@ -1,6 +1,8 @@
<?php
return array(
// 'number.decimals_separator' => '',
// 'number.thousands_separator' => '',
'None' => 'なし',
'edit' => '変更',
'Edit' => '変更',
@ -738,4 +740,37 @@ return array(
// 'Horizontal scrolling' => '',
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Remove hourly rate' => '',
// 'Do you really want to remove this hourly rate?' => '',
// 'Hourly rates' => '',
// 'Hourly rate' => '',
// 'Currency' => '',
// 'Effective date' => '',
// 'Add new rate' => '',
// 'Rate removed successfully.' => '',
// 'Unable to remove this rate.' => '',
// 'Unable to save the hourly rate.' => '',
// 'Hourly rate created successfully.' => '',
// 'Start time' => '',
// 'End time' => '',
// 'Comment' => '',
// 'All day' => '',
// 'Day' => '',
// 'Manage timetable' => '',
// 'Overtime timetable' => '',
// 'Time off timetable' => '',
// 'Timetable' => '',
// 'Work timetable' => '',
// 'Week timetable' => '',
// 'Day timetable' => '',
// 'From' => '',
// 'To' => '',
// 'Time slot created successfully.' => '',
// 'Unable to save this time slot.' => '',
// 'Time slot removed successfully.' => '',
// 'Unable to remove this time slot.' => '',
// 'Do you really want to remove this time slot?' => '',
// 'Remove time slot' => '',
// 'Add new time slot' => '',
// 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
);

View File

@ -1,6 +1,8 @@
<?php
return array(
// 'number.decimals_separator' => '',
// 'number.thousands_separator' => '',
'None' => 'Brak',
'edit' => 'edytuj',
'Edit' => 'Edytuj',
@ -738,4 +740,37 @@ return array(
// 'Horizontal scrolling' => '',
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Remove hourly rate' => '',
// 'Do you really want to remove this hourly rate?' => '',
// 'Hourly rates' => '',
// 'Hourly rate' => '',
// 'Currency' => '',
// 'Effective date' => '',
// 'Add new rate' => '',
// 'Rate removed successfully.' => '',
// 'Unable to remove this rate.' => '',
// 'Unable to save the hourly rate.' => '',
// 'Hourly rate created successfully.' => '',
// 'Start time' => '',
// 'End time' => '',
// 'Comment' => '',
// 'All day' => '',
// 'Day' => '',
// 'Manage timetable' => '',
// 'Overtime timetable' => '',
// 'Time off timetable' => '',
// 'Timetable' => '',
// 'Work timetable' => '',
// 'Week timetable' => '',
// 'Day timetable' => '',
// 'From' => '',
// 'To' => '',
// 'Time slot created successfully.' => '',
// 'Unable to save this time slot.' => '',
// 'Time slot removed successfully.' => '',
// 'Unable to remove this time slot.' => '',
// 'Do you really want to remove this time slot?' => '',
// 'Remove time slot' => '',
// 'Add new time slot' => '',
// 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
);

View File

@ -1,6 +1,8 @@
<?php
return array(
// 'number.decimals_separator' => '',
// 'number.thousands_separator' => '',
'None' => 'Nenhum',
'edit' => 'editar',
'Edit' => 'Editar',
@ -738,4 +740,37 @@ return array(
// 'Horizontal scrolling' => '',
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Remove hourly rate' => '',
// 'Do you really want to remove this hourly rate?' => '',
// 'Hourly rates' => '',
// 'Hourly rate' => '',
// 'Currency' => '',
// 'Effective date' => '',
// 'Add new rate' => '',
// 'Rate removed successfully.' => '',
// 'Unable to remove this rate.' => '',
// 'Unable to save the hourly rate.' => '',
// 'Hourly rate created successfully.' => '',
// 'Start time' => '',
// 'End time' => '',
// 'Comment' => '',
// 'All day' => '',
// 'Day' => '',
// 'Manage timetable' => '',
// 'Overtime timetable' => '',
// 'Time off timetable' => '',
// 'Timetable' => '',
// 'Work timetable' => '',
// 'Week timetable' => '',
// 'Day timetable' => '',
// 'From' => '',
// 'To' => '',
// 'Time slot created successfully.' => '',
// 'Unable to save this time slot.' => '',
// 'Time slot removed successfully.' => '',
// 'Unable to remove this time slot.' => '',
// 'Do you really want to remove this time slot?' => '',
// 'Remove time slot' => '',
// 'Add new time slot' => '',
// 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
);

View File

@ -1,6 +1,8 @@
<?php
return array(
// 'number.decimals_separator' => '',
// 'number.thousands_separator' => '',
'None' => 'Отсутствует',
'edit' => 'изменить',
'Edit' => 'Изменить',
@ -738,4 +740,37 @@ return array(
// 'Horizontal scrolling' => '',
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Remove hourly rate' => '',
// 'Do you really want to remove this hourly rate?' => '',
// 'Hourly rates' => '',
// 'Hourly rate' => '',
// 'Currency' => '',
// 'Effective date' => '',
// 'Add new rate' => '',
// 'Rate removed successfully.' => '',
// 'Unable to remove this rate.' => '',
// 'Unable to save the hourly rate.' => '',
// 'Hourly rate created successfully.' => '',
// 'Start time' => '',
// 'End time' => '',
// 'Comment' => '',
// 'All day' => '',
// 'Day' => '',
// 'Manage timetable' => '',
// 'Overtime timetable' => '',
// 'Time off timetable' => '',
// 'Timetable' => '',
// 'Work timetable' => '',
// 'Week timetable' => '',
// 'Day timetable' => '',
// 'From' => '',
// 'To' => '',
// 'Time slot created successfully.' => '',
// 'Unable to save this time slot.' => '',
// 'Time slot removed successfully.' => '',
// 'Unable to remove this time slot.' => '',
// 'Do you really want to remove this time slot?' => '',
// 'Remove time slot' => '',
// 'Add new time slot' => '',
// 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
);

View File

@ -1,6 +1,8 @@
<?php
return array(
// 'number.decimals_separator' => '',
// 'number.thousands_separator' => '',
'None' => 'Ingen',
'edit' => 'redigera',
'Edit' => 'Redigera',
@ -738,4 +740,37 @@ return array(
// 'Horizontal scrolling' => '',
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Remove hourly rate' => '',
// 'Do you really want to remove this hourly rate?' => '',
// 'Hourly rates' => '',
// 'Hourly rate' => '',
// 'Currency' => '',
// 'Effective date' => '',
// 'Add new rate' => '',
// 'Rate removed successfully.' => '',
// 'Unable to remove this rate.' => '',
// 'Unable to save the hourly rate.' => '',
// 'Hourly rate created successfully.' => '',
// 'Start time' => '',
// 'End time' => '',
// 'Comment' => '',
// 'All day' => '',
// 'Day' => '',
// 'Manage timetable' => '',
// 'Overtime timetable' => '',
// 'Time off timetable' => '',
// 'Timetable' => '',
// 'Work timetable' => '',
// 'Week timetable' => '',
// 'Day timetable' => '',
// 'From' => '',
// 'To' => '',
// 'Time slot created successfully.' => '',
// 'Unable to save this time slot.' => '',
// 'Time slot removed successfully.' => '',
// 'Unable to remove this time slot.' => '',
// 'Do you really want to remove this time slot?' => '',
// 'Remove time slot' => '',
// 'Add new time slot' => '',
// 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
);

View File

@ -1,6 +1,8 @@
<?php
return array(
// 'number.decimals_separator' => '',
// 'number.thousands_separator' => '',
'None' => 'ไม่มี',
'edit' => 'แก้ไข',
'Edit' => 'แก้ไข',
@ -738,4 +740,37 @@ return array(
// 'Horizontal scrolling' => '',
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Remove hourly rate' => '',
// 'Do you really want to remove this hourly rate?' => '',
// 'Hourly rates' => '',
// 'Hourly rate' => '',
// 'Currency' => '',
// 'Effective date' => '',
// 'Add new rate' => '',
// 'Rate removed successfully.' => '',
// 'Unable to remove this rate.' => '',
// 'Unable to save the hourly rate.' => '',
// 'Hourly rate created successfully.' => '',
// 'Start time' => '',
// 'End time' => '',
// 'Comment' => '',
// 'All day' => '',
// 'Day' => '',
// 'Manage timetable' => '',
// 'Overtime timetable' => '',
// 'Time off timetable' => '',
// 'Timetable' => '',
// 'Work timetable' => '',
// 'Week timetable' => '',
// 'Day timetable' => '',
// 'From' => '',
// 'To' => '',
// 'Time slot created successfully.' => '',
// 'Unable to save this time slot.' => '',
// 'Time slot removed successfully.' => '',
// 'Unable to remove this time slot.' => '',
// 'Do you really want to remove this time slot?' => '',
// 'Remove time slot' => '',
// 'Add new time slot' => '',
// 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
);

View File

@ -1,6 +1,8 @@
<?php
return array(
// 'number.decimals_separator' => '',
// 'number.thousands_separator' => '',
'None' => 'Hiçbiri',
'edit' => 'düzenle',
'Edit' => 'Düzenle',
@ -738,4 +740,37 @@ return array(
'Horizontal scrolling' => 'Geniş görünüm',
'Compact/wide view' => 'Ekrana sığdır / Geniş görünüm',
// 'No results match:' => '',
// 'Remove hourly rate' => '',
// 'Do you really want to remove this hourly rate?' => '',
// 'Hourly rates' => '',
// 'Hourly rate' => '',
// 'Currency' => '',
// 'Effective date' => '',
// 'Add new rate' => '',
// 'Rate removed successfully.' => '',
// 'Unable to remove this rate.' => '',
// 'Unable to save the hourly rate.' => '',
// 'Hourly rate created successfully.' => '',
// 'Start time' => '',
// 'End time' => '',
// 'Comment' => '',
// 'All day' => '',
// 'Day' => '',
// 'Manage timetable' => '',
// 'Overtime timetable' => '',
// 'Time off timetable' => '',
// 'Timetable' => '',
// 'Work timetable' => '',
// 'Week timetable' => '',
// 'Day timetable' => '',
// 'From' => '',
// 'To' => '',
// 'Time slot created successfully.' => '',
// 'Unable to save this time slot.' => '',
// 'Time slot removed successfully.' => '',
// 'Unable to remove this time slot.' => '',
// 'Do you really want to remove this time slot?' => '',
// 'Remove time slot' => '',
// 'Add new time slot' => '',
// 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
);

View File

@ -1,6 +1,8 @@
<?php
return array(
// 'number.decimals_separator' => '',
// 'number.thousands_separator' => '',
'None' => '无',
'edit' => '编辑',
'Edit' => '编辑',
@ -738,4 +740,37 @@ return array(
// 'Horizontal scrolling' => '',
// 'Compact/wide view' => '',
// 'No results match:' => '',
// 'Remove hourly rate' => '',
// 'Do you really want to remove this hourly rate?' => '',
// 'Hourly rates' => '',
// 'Hourly rate' => '',
// 'Currency' => '',
// 'Effective date' => '',
// 'Add new rate' => '',
// 'Rate removed successfully.' => '',
// 'Unable to remove this rate.' => '',
// 'Unable to save the hourly rate.' => '',
// 'Hourly rate created successfully.' => '',
// 'Start time' => '',
// 'End time' => '',
// 'Comment' => '',
// 'All day' => '',
// 'Day' => '',
// 'Manage timetable' => '',
// 'Overtime timetable' => '',
// 'Time off timetable' => '',
// 'Timetable' => '',
// 'Work timetable' => '',
// 'Week timetable' => '',
// 'Day timetable' => '',
// 'From' => '',
// 'To' => '',
// 'Time slot created successfully.' => '',
// 'Unable to save this time slot.' => '',
// 'Time slot removed successfully.' => '',
// 'Unable to remove this time slot.' => '',
// 'Do you really want to remove this time slot?' => '',
// 'Remove time slot' => '',
// 'Add new time slot' => '',
// 'This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.' => '',
);

194
app/Model/Timetable.php Normal file
View File

@ -0,0 +1,194 @@
<?php
namespace Model;
use DateTime;
use DateInterval;
/**
* Timetable
*
* @package model
* @author Frederic Guillot
*/
class Timetable extends Base
{
/**
* User time slots
*
* @access private
* @var array
*/
private $day;
private $week;
private $overtime;
private $timeoff;
/**
* Get the timetable for a user for a given date range
*
* @access public
* @param integer $user_id
* @param \DateTime $start
* @param \DateTime $end
* @return array
*/
public function calculate($user_id, DateTime $start, DateTime $end)
{
$timetable = array();
$this->day = $this->timetableDay->getByUser($user_id);
$this->week = $this->timetableWeek->getByUser($user_id);
$this->overtime = $this->timetableExtra->getByUserAndDate($user_id, $start->format('Y-m-d'), $end->format('Y-m-d'));
$this->timeoff = $this->timetableOff->getByUserAndDate($user_id, $start->format('Y-m-d'), $end->format('Y-m-d'));
for ($today = clone($start); $today <= $end; $today->add(new DateInterval('P1D'))) {
$week_day = $today->format('N');
$timetable = array_merge($timetable, $this->getWeekSlots($today, $week_day));
$timetable = array_merge($timetable, $this->getOvertimeSlots($today, $week_day));
}
return $timetable;
}
/**
* Return worked time slots for the given day
*
* @access public
* @param \DateTime $today
* @param string $week_day
* @return array
*/
public function getWeekSlots(DateTime $today, $week_day)
{
$slots = array();
$dayoff = $this->getDayOff($today);
if (! empty($dayoff) && $dayoff['all_day'] == 1) {
return array();
}
foreach ($this->week as $slot) {
if ($week_day == $slot['day']) {
$slots = array_merge($slots, $this->getDayWorkSlots($slot, $dayoff, $today));
}
}
return $slots;
}
/**
* Get the overtime time slots for the given day
*
* @access public
* @param \DateTime $today
* @param string $week_day
* @return array
*/
public function getOvertimeSlots(DateTime $today, $week_day)
{
$slots = array();
foreach ($this->overtime as $slot) {
$day = new DateTime($slot['date']);
if ($week_day == $day->format('N')) {
if ($slot['all_day'] == 1) {
$slots = array_merge($slots, $this->getDaySlots($today));
}
else {
$slots[] = $this->getTimeSlot($slot, $day);
}
}
}
return $slots;
}
/**
* Get worked time slots and remove time off
*
* @access public
* @param array $slot
* @param array $dayoff
* @param \DateTime $today
* @return array
*/
public function getDayWorkSlots(array $slot, array $dayoff, DateTime $today)
{
$slots = array();
if (! empty($dayoff) && $dayoff['start'] < $slot['end']) {
if ($dayoff['start'] > $slot['start']) {
$slots[] = $this->getTimeSlot(array('end' => $dayoff['start']) + $slot, $today);
}
if ($dayoff['end'] < $slot['end']) {
$slots[] = $this->getTimeSlot(array('start' => $dayoff['end']) + $slot, $today);
}
}
else {
$slots[] = $this->getTimeSlot($slot, $today);
}
return $slots;
}
/**
* Get regular day work time slots
*
* @access public
* @param \DateTime $today
* @return array
*/
public function getDaySlots(DateTime $today)
{
$slots = array();
foreach ($this->day as $day) {
$slots[] = $this->getTimeSlot($day, $today);
}
return $slots;
}
/**
* Get the start and end time slot for a given day
*
* @access public
* @param array $slot
* @param \DateTime $today
* @return array
*/
public function getTimeSlot(array $slot, DateTime $today)
{
$date = $today->format('Y-m-d');
return array(
new DateTime($date.' '.$slot['start']),
new DateTime($date.' '.$slot['end']),
);
}
/**
* Return day off time slot
*
* @access public
* @param \DateTime $today
* @return array
*/
public function getDayOff(DateTime $today)
{
foreach ($this->timeoff as $day) {
if ($day['date'] === $today->format('Y-m-d')) {
return $day;
}
}
return array();
}
}

View File

@ -0,0 +1,87 @@
<?php
namespace Model;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
/**
* Timetable Workweek
*
* @package model
* @author Frederic Guillot
*/
class TimetableDay extends Base
{
/**
* SQL table name
*
* @var string
*/
const TABLE = 'timetable_day';
/**
* Get the timetable for a given user
*
* @access public
* @param integer $user_id User id
* @return array
*/
public function getByUser($user_id)
{
return $this->db->table(self::TABLE)->eq('user_id', $user_id)->asc('start')->findAll();
}
/**
* Add a new time slot in the database
*
* @access public
* @param integer $user_id User id
* @param string $start Start hour (24h format)
* @param string $end End hour (24h format)
* @return boolean|integer
*/
public function create($user_id, $start, $end)
{
$values = array(
'user_id' => $user_id,
'start' => $start,
'end' => $end,
);
return $this->persist(self::TABLE, $values);
}
/**
* Remove a specific time slot
*
* @access public
* @param integer $slot_id
* @return boolean
*/
public function remove($slot_id)
{
return $this->db->table(self::TABLE)->eq('id', $slot_id)->remove();
}
/**
* Validate creation
*
* @access public
* @param array $values Form values
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
*/
public function validateCreation(array $values)
{
$v = new Validator($values, array(
new Validators\Required('user_id', t('Field required')),
new Validators\Required('start', t('Field required')),
new Validators\Required('end', t('Field required')),
));
return array(
$v->execute(),
$v->getErrors()
);
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace Model;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
/**
* Timetable over-time
*
* @package model
* @author Frederic Guillot
*/
class TimetableExtra extends TimetableOff
{
/**
* SQL table name
*
* @var string
*/
const TABLE = 'timetable_extra';
}

125
app/Model/TimetableOff.php Normal file
View File

@ -0,0 +1,125 @@
<?php
namespace Model;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
/**
* Timetable time off
*
* @package model
* @author Frederic Guillot
*/
class TimetableOff extends Base
{
/**
* SQL table name
*
* @var string
*/
const TABLE = 'timetable_off';
/**
* Get query to fetch everything (pagination)
*
* @access public
* @param integer $user_id User id
* @return \PicoDb\Table
*/
public function getUserQuery($user_id)
{
return $this->db->table(static::TABLE)->eq('user_id', $user_id);
}
/**
* Get the timetable for a given user
*
* @access public
* @param integer $user_id User id
* @return array
*/
public function getByUser($user_id)
{
return $this->db->table(static::TABLE)->eq('user_id', $user_id)->desc('date')->asc('start')->findAll();
}
/**
* Get the timetable for a given user
*
* @access public
* @param integer $user_id User id
* @param string $start_date
* @param string $end_date
* @return array
*/
public function getByUserAndDate($user_id, $start_date, $end_date)
{
return $this->db->table(static::TABLE)
->eq('user_id', $user_id)
->gte('date', $start_date)
->lte('date', $end_date)
->desc('date')
->asc('start')
->findAll();
}
/**
* Add a new time slot in the database
*
* @access public
* @param integer $user_id User id
* @param string $date Day (ISO8601 format)
* @param boolean $all_day All day flag
* @param float $start Start hour (24h format)
* @param float $end End hour (24h format)
* @param string $comment
* @return boolean|integer
*/
public function create($user_id, $date, $all_day, $start = '', $end = '', $comment = '')
{
$values = array(
'user_id' => $user_id,
'date' => $date,
'all_day' => $all_day,
'start' => $all_day ? '' : $start,
'end' => $all_day ? '' : $end,
'comment' => $comment,
);
return $this->persist(static::TABLE, $values);
}
/**
* Remove a specific time slot
*
* @access public
* @param integer $slot_id
* @return boolean
*/
public function remove($slot_id)
{
return $this->db->table(static::TABLE)->eq('id', $slot_id)->remove();
}
/**
* Validate creation
*
* @access public
* @param array $values Form values
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
*/
public function validateCreation(array $values)
{
$v = new Validator($values, array(
new Validators\Required('user_id', t('Field required')),
new Validators\Required('date', t('Field required')),
new Validators\Numeric('all_day', t('This value must be numeric')),
));
return array(
$v->execute(),
$v->getErrors()
);
}
}

View File

@ -0,0 +1,91 @@
<?php
namespace Model;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
/**
* Timetable Workweek
*
* @package model
* @author Frederic Guillot
*/
class TimetableWeek extends Base
{
/**
* SQL table name
*
* @var string
*/
const TABLE = 'timetable_week';
/**
* Get the timetable for a given user
*
* @access public
* @param integer $user_id User id
* @return array
*/
public function getByUser($user_id)
{
return $this->db->table(self::TABLE)->eq('user_id', $user_id)->asc('day')->asc('start')->findAll();
}
/**
* Add a new time slot in the database
*
* @access public
* @param integer $user_id User id
* @param string $day Day of the week (ISO-8601)
* @param string $start Start hour (24h format)
* @param string $end End hour (24h format)
* @return boolean|integer
*/
public function create($user_id, $day, $start, $end)
{
$values = array(
'user_id' => $user_id,
'day' => $day,
'start' => $start,
'end' => $end,
);
return $this->persist(self::TABLE, $values);
}
/**
* Remove a specific time slot
*
* @access public
* @param integer $slot_id
* @return boolean
*/
public function remove($slot_id)
{
return $this->db->table(self::TABLE)->eq('id', $slot_id)->remove();
}
/**
* Validate creation
*
* @access public
* @param array $values Form values
* @return array $valid, $errors [0] = Success or not, [1] = List of errors
*/
public function validateCreation(array $values)
{
$v = new Validator($values, array(
new Validators\Required('user_id', t('Field required')),
new Validators\Required('day', t('Field required')),
new Validators\Numeric('day', t('This value must be numeric')),
new Validators\Required('start', t('Field required')),
new Validators\Required('end', t('Field required')),
));
return array(
$v->execute(),
$v->getErrors()
);
}
}

View File

@ -6,7 +6,53 @@ use PDO;
use Core\Security;
use Model\Link;
const VERSION = 50;
const VERSION = 51;
function version_51($pdo)
{
$pdo->exec('CREATE TABLE timetable_day (
id INT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL,
start VARCHAR(5) NOT NULL,
end VARCHAR(5) NOT NULL,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
PRIMARY KEY(id)
) ENGINE=InnoDB CHARSET=utf8');
$pdo->exec('CREATE TABLE timetable_week (
id INT NOT NULL AUTO_INCREMENT,
user_id INTEGER NOT NULL,
day INT NOT NULL,
start VARCHAR(5) NOT NULL,
end VARCHAR(5) NOT NULL,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
PRIMARY KEY(id)
) ENGINE=InnoDB CHARSET=utf8');
$pdo->exec('CREATE TABLE timetable_off (
id INT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL,
date VARCHAR(10) NOT NULL,
all_day TINYINT(1) DEFAULT 0,
start VARCHAR(5) DEFAULT 0,
end VARCHAR(5) DEFAULT 0,
comment TEXT,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
PRIMARY KEY(id)
) ENGINE=InnoDB CHARSET=utf8');
$pdo->exec('CREATE TABLE timetable_extra (
id INT NOT NULL AUTO_INCREMENT,
user_id INT NOT NULL,
date VARCHAR(10) NOT NULL,
all_day TINYINT(1) DEFAULT 0,
start VARCHAR(5) DEFAULT 0,
end VARCHAR(5) DEFAULT 0,
comment TEXT,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE,
PRIMARY KEY(id)
) ENGINE=InnoDB CHARSET=utf8');
}
function version_50($pdo)
{

View File

@ -6,12 +6,54 @@ use PDO;
use Core\Security;
use Model\Link;
const VERSION = 31;
const VERSION = 32;
function version_32($pdo)
{
$pdo->exec('CREATE TABLE timetable_day (
"id" SERIAL PRIMARY KEY,
"user_id" INTEGER NOT NULL,
"start" VARCHAR(5) NOT NULL,
"end" VARCHAR(5) NOT NULL,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
)');
$pdo->exec('CREATE TABLE timetable_week (
"id" SERIAL PRIMARY KEY,
"user_id" INTEGER NOT NULL,
"day" INTEGER NOT NULL,
"start" VARCHAR(5) NOT NULL,
"end" VARCHAR(5) NOT NULL,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
)');
$pdo->exec('CREATE TABLE timetable_off (
"id" SERIAL PRIMARY KEY,
"user_id" INTEGER NOT NULL,
"date" VARCHAR(10) NOT NULL,
"all_day" BOOLEAN DEFAULT \'0\',
"start" VARCHAR(5) DEFAULT 0,
"end" VARCHAR(5) DEFAULT 0,
"comment" TEXT,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
)');
$pdo->exec('CREATE TABLE timetable_extra (
"id" SERIAL PRIMARY KEY,
"user_id" INTEGER NOT NULL,
"date" VARCHAR(10) NOT NULL,
"all_day" BOOLEAN DEFAULT \'0\',
"start" VARCHAR(5) DEFAULT 0,
"end" VARCHAR(5) DEFAULT 0,
"comment" TEXT,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
)');
}
function version_31($pdo)
{
$pdo->exec("CREATE TABLE hourly_rates (
id SERIAL,
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL,
rate REAL DEFAULT 0,
date_effective INTEGER NOT NULL,

View File

@ -6,7 +6,49 @@ use Core\Security;
use PDO;
use Model\Link;
const VERSION = 49;
const VERSION = 50;
function version_50($pdo)
{
$pdo->exec('CREATE TABLE timetable_day (
"id" INTEGER PRIMARY KEY,
"user_id" INTEGER NOT NULL,
"start" TEXT NOT NULL,
"end" TEXT NOT NULL,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
)');
$pdo->exec('CREATE TABLE timetable_week (
"id" INTEGER PRIMARY KEY,
"user_id" INTEGER NOT NULL,
"day" INTEGER NOT NULL,
"start" TEXT NOT NULL,
"end" TEXT NOT NULL,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
)');
$pdo->exec('CREATE TABLE timetable_off (
"id" INTEGER PRIMARY KEY,
"user_id" INTEGER NOT NULL,
"date" TEXT NOT NULL,
"all_day" INTEGER DEFAULT 0,
"start" TEXT DEFAULT 0,
"end" TEXT DEFAULT 0,
"comment" TEXT,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
)');
$pdo->exec('CREATE TABLE timetable_extra (
"id" INTEGER PRIMARY KEY,
"user_id" INTEGER NOT NULL,
"date" TEXT NOT NULL,
"all_day" INTEGER DEFAULT 0,
"start" TEXT DEFAULT 0,
"end" TEXT DEFAULT 0,
"comment" TEXT,
FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE
)');
}
function version_49($pdo)
{

View File

@ -49,6 +49,11 @@ class ClassProvider implements ServiceProviderInterface
'TaskPosition',
'TaskStatus',
'TaskValidator',
'Timetable',
'TimetableDay',
'TimetableWeek',
'TimetableOff',
'TimetableExtra',
'TimeTracking',
'User',
'UserSession',

View File

@ -0,0 +1,44 @@
<div class="page-header">
<h2><?= t('Timetable') ?></h2>
<ul>
<li><?= $this->a(t('Day timetable'), 'timetableday', 'index', array('user_id' => $user['id'])) ?></li>
<li><?= $this->a(t('Week timetable'), 'timetableweek', 'index', array('user_id' => $user['id'])) ?></li>
<li><?= $this->a(t('Time off timetable'), 'timetableoff', 'index', array('user_id' => $user['id'])) ?></li>
<li><?= $this->a(t('Overtime timetable'), 'timetableextra', 'index', array('user_id' => $user['id'])) ?></li>
</ul>
</div>
<form method="get" action="?" autocomplete="off" class="form-inline">
<?= $this->formHidden('controller', $values) ?>
<?= $this->formHidden('action', $values) ?>
<?= $this->formHidden('user_id', $values) ?>
<?= $this->formLabel(t('From'), 'from') ?>
<?= $this->formText('from', $values, array(), array(), 'form-date') ?>
<?= $this->formLabel(t('To'), 'to') ?>
<?= $this->formText('to', $values, array(), array(), 'form-date') ?>
<input type="submit" value="<?= t('Execute') ?>" class="btn btn-blue"/>
</form>
<?php if (! empty($timetable)): ?>
<hr/>
<h3><?= t('Work timetable') ?></h3>
<table class="table-fixed table-stripped">
<tr>
<th><?= t('Day') ?></th>
<th><?= t('Start') ?></th>
<th><?= t('End') ?></th>
</tr>
<?php foreach ($timetable as $slot): ?>
<tr>
<td><?= dt('%B %e, %Y', $slot[0]->getTimestamp()) ?></td>
<td><?= dt('%k:%M %p', $slot[0]->getTimestamp()) ?></td>
<td><?= dt('%k:%M %p', $slot[1]->getTimestamp()) ?></td>
</tr>
<?php endforeach ?>
</table>
<?php endif ?>

View File

@ -0,0 +1,45 @@
<div class="page-header">
<h2><?= t('Day timetable') ?></h2>
</div>
<?php if (! empty($timetable)): ?>
<table class="table-fixed table-stripped">
<tr>
<th><?= t('Start time') ?></th>
<th><?= t('End time') ?></th>
<th><?= t('Action') ?></th>
</tr>
<?php foreach ($timetable as $slot): ?>
<tr>
<td><?= $slot['start'] ?></td>
<td><?= $slot['end'] ?></td>
<td>
<?= $this->a(t('Remove'), 'timetableday', 'confirm', array('user_id' => $user['id'], 'slot_id' => $slot['id'])) ?>
</td>
</tr>
<?php endforeach ?>
</table>
<h3><?= t('Add new time slot') ?></h3>
<?php endif ?>
<form method="post" action="<?= $this->u('timetableday', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off">
<?= $this->formHidden('user_id', $values) ?>
<?= $this->formCsrf() ?>
<?= $this->formLabel(t('Start time'), 'start') ?>
<?= $this->formSelect('start', $this->getDayHours(), $values, $errors) ?>
<?= $this->formLabel(t('End time'), 'end') ?>
<?= $this->formSelect('end', $this->getDayHours(), $values, $errors) ?>
<div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
</div>
</form>
<p class="alert alert-info">
<?= t('This timetable is used when the checkbox "all day" is checked for scheduled time off and overtime.') ?>
</p>

View File

@ -0,0 +1,13 @@
<div class="page-header">
<h2><?= t('Remove time slot') ?></h2>
</div>
<div class="confirm">
<p class="alert alert-info"><?= t('Do you really want to remove this time slot?') ?></p>
<div class="form-actions">
<?= $this->a(t('Yes'), 'timetableday', 'remove', array('user_id' => $user['id'], 'slot_id' => $slot_id), true, 'btn btn-red') ?>
<?= t('or') ?>
<?= $this->a(t('cancel'), 'timetableday', 'index', array('user_id' => $user['id'])) ?>
</div>
</div>

View File

@ -0,0 +1,56 @@
<div class="page-header">
<h2><?= t('Overtime timetable') ?></h2>
</div>
<?php if (! $paginator->isEmpty()): ?>
<table class="table-fixed table-stripped">
<tr>
<th><?= $paginator->order(t('Day'), 'Day') ?></th>
<th><?= $paginator->order(t('All day'), 'all_day') ?></th>
<th><?= $paginator->order(t('Start time'), 'start') ?></th>
<th><?= $paginator->order(t('End time'), 'end') ?></th>
<th class="column-40"><?= t('Comment') ?></th>
<th><?= t('Action') ?></th>
</tr>
<?php foreach ($paginator->getCollection() as $slot): ?>
<tr>
<td><?= $slot['date'] ?></td>
<td><?= $slot['all_day'] == 1 ? t('Yes') : t('No') ?></td>
<td><?= $slot['start'] ?></td>
<td><?= $slot['end'] ?></td>
<td><?= $this->e($slot['comment']) ?></td>
<td>
<?= $this->a(t('Remove'), 'timetableextra', 'confirm', array('user_id' => $user['id'], 'slot_id' => $slot['id'])) ?>
</td>
</tr>
<?php endforeach ?>
</table>
<?= $paginator ?>
<?php endif ?>
<form method="post" action="<?= $this->u('timetableextra', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off">
<?= $this->formHidden('user_id', $values) ?>
<?= $this->formCsrf() ?>
<?= $this->formLabel(t('Day'), 'date') ?>
<?= $this->formText('date', $values, $errors, array('required'), 'form-date') ?>
<?= $this->formCheckbox('all_day', t('All day'), 1) ?>
<?= $this->formLabel(t('Start time'), 'start') ?>
<?= $this->formSelect('start', $this->getDayHours(), $values, $errors) ?>
<?= $this->formLabel(t('End time'), 'end') ?>
<?= $this->formSelect('end', $this->getDayHours(), $values, $errors) ?>
<?= $this->formLabel(t('Comment'), 'comment') ?>
<?= $this->formText('comment', $values, $errors) ?>
<div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
</div>
</form>

View File

@ -0,0 +1,13 @@
<div class="page-header">
<h2><?= t('Remove time slot') ?></h2>
</div>
<div class="confirm">
<p class="alert alert-info"><?= t('Do you really want to remove this time slot?') ?></p>
<div class="form-actions">
<?= $this->a(t('Yes'), 'timetableextra', 'remove', array('user_id' => $user['id'], 'slot_id' => $slot_id), true, 'btn btn-red') ?>
<?= t('or') ?>
<?= $this->a(t('cancel'), 'timetableextra', 'index', array('user_id' => $user['id'])) ?>
</div>
</div>

View File

@ -0,0 +1,56 @@
<div class="page-header">
<h2><?= t('Time off timetable') ?></h2>
</div>
<?php if (! $paginator->isEmpty()): ?>
<table class="table-fixed table-stripped">
<tr>
<th><?= $paginator->order(t('Day'), 'Day') ?></th>
<th><?= $paginator->order(t('All day'), 'all_day') ?></th>
<th><?= $paginator->order(t('Start time'), 'start') ?></th>
<th><?= $paginator->order(t('End time'), 'end') ?></th>
<th class="column-40"><?= t('Comment') ?></th>
<th><?= t('Action') ?></th>
</tr>
<?php foreach ($paginator->getCollection() as $slot): ?>
<tr>
<td><?= $slot['date'] ?></td>
<td><?= $slot['all_day'] == 1 ? t('Yes') : t('No') ?></td>
<td><?= $slot['start'] ?></td>
<td><?= $slot['end'] ?></td>
<td><?= $this->e($slot['comment']) ?></td>
<td>
<?= $this->a(t('Remove'), 'timetableoff', 'confirm', array('user_id' => $user['id'], 'slot_id' => $slot['id'])) ?>
</td>
</tr>
<?php endforeach ?>
</table>
<?= $paginator ?>
<?php endif ?>
<form method="post" action="<?= $this->u('timetableoff', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off">
<?= $this->formHidden('user_id', $values) ?>
<?= $this->formCsrf() ?>
<?= $this->formLabel(t('Day'), 'date') ?>
<?= $this->formText('date', $values, $errors, array('required'), 'form-date') ?>
<?= $this->formCheckbox('all_day', t('All day'), 1) ?>
<?= $this->formLabel(t('Start time'), 'start') ?>
<?= $this->formSelect('start', $this->getDayHours(), $values, $errors) ?>
<?= $this->formLabel(t('End time'), 'end') ?>
<?= $this->formSelect('end', $this->getDayHours(), $values, $errors) ?>
<?= $this->formLabel(t('Comment'), 'comment') ?>
<?= $this->formText('comment', $values, $errors) ?>
<div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
</div>
</form>

View File

@ -0,0 +1,13 @@
<div class="page-header">
<h2><?= t('Remove time slot') ?></h2>
</div>
<div class="confirm">
<p class="alert alert-info"><?= t('Do you really want to remove this time slot?') ?></p>
<div class="form-actions">
<?= $this->a(t('Yes'), 'timetableoff', 'remove', array('user_id' => $user['id'], 'slot_id' => $slot_id), true, 'btn btn-red') ?>
<?= t('or') ?>
<?= $this->a(t('cancel'), 'timetableoff', 'index', array('user_id' => $user['id'])) ?>
</div>
</div>

View File

@ -0,0 +1,46 @@
<div class="page-header">
<h2><?= t('Week timetable') ?></h2>
</div>
<?php if (! empty($timetable)): ?>
<table class="table-fixed table-stripped">
<tr>
<th><?= t('Day') ?></th>
<th><?= t('Start time') ?></th>
<th><?= t('End time') ?></th>
<th><?= t('Action') ?></th>
</tr>
<?php foreach ($timetable as $slot): ?>
<tr>
<td><?= $this->getWeekDay($slot['day']) ?></td>
<td><?= $slot['start'] ?></td>
<td><?= $slot['end'] ?></td>
<td>
<?= $this->a(t('Remove'), 'timetableweek', 'confirm', array('user_id' => $user['id'], 'slot_id' => $slot['id'])) ?>
</td>
</tr>
<?php endforeach ?>
</table>
<h3><?= t('Add new time slot') ?></h3>
<?php endif ?>
<form method="post" action="<?= $this->u('timetableweek', 'save', array('user_id' => $user['id'])) ?>" autocomplete="off">
<?= $this->formHidden('user_id', $values) ?>
<?= $this->formCsrf() ?>
<?= $this->formLabel(t('Day'), 'day') ?>
<?= $this->formSelect('day', $this->getWeekDays(), $values, $errors) ?>
<?= $this->formLabel(t('Start time'), 'start') ?>
<?= $this->formSelect('start', $this->getDayHours(), $values, $errors) ?>
<?= $this->formLabel(t('End time'), 'end') ?>
<?= $this->formSelect('end', $this->getDayHours(), $values, $errors) ?>
<div class="form-actions">
<input type="submit" value="<?= t('Save') ?>" class="btn btn-blue"/>
</div>
</form>

View File

@ -0,0 +1,13 @@
<div class="page-header">
<h2><?= t('Remove time slot') ?></h2>
</div>
<div class="confirm">
<p class="alert alert-info"><?= t('Do you really want to remove this time slot?') ?></p>
<div class="form-actions">
<?= $this->a(t('Yes'), 'timetableweek', 'remove', array('user_id' => $user['id'], 'slot_id' => $slot_id), true, 'btn btn-red') ?>
<?= t('or') ?>
<?= $this->a(t('cancel'), 'timetableweek', 'index', array('user_id' => $user['id'])) ?>
</div>
</div>

View File

@ -43,6 +43,9 @@
<li>
<?= $this->a(t('Hourly rates'), 'hourlyrate', 'index', array('user_id' => $user['id'])) ?>
</li>
<li>
<?= $this->a(t('Manage timetable'), 'timetable', 'index', array('user_id' => $user['id'])) ?>
</li>
<?php endif ?>
<?php if ($this->userSession->isAdmin() && ! $this->userSession->isCurrentUser($user['id'])): ?>

View File

@ -152,6 +152,10 @@ th a:hover {
text-overflow: ellipsis;
}
.table-stripped tr:nth-child(odd) td {
background: #fefefe;
}
.column-5 {
width: 5%;
}

View File

@ -58,6 +58,10 @@ th a:hover {
text-overflow: ellipsis;
}
.table-stripped tr:nth-child(odd) td {
background: #fefefe;
}
.column-5 {
width: 5%;
}

View File

@ -0,0 +1,130 @@
<?php
require_once __DIR__.'/Base.php';
use Model\User;
use Model\Timetable;
use Model\TimetableDay;
use Model\TimetableWeek;
use Model\TimetableOff;
use Model\TimetableExtra;
class TimetableTest extends Base
{
public function testCalculateWorkDays()
{
$w = new TimetableWeek($this->container);
$t = new Timetable($this->container);
$this->assertNotFalse($w->create(1, 1, '09:30', '12:00'));
$this->assertNotFalse($w->create(1, 1, '13:00', '17:00'));
$this->assertNotFalse($w->create(1, 2, '09:30', '12:00'));
$this->assertNotFalse($w->create(1, 2, '13:00', '17:00'));
$monday = new DateTime('next Monday');
$timetable = $t->calculate(1, $monday, new DateTime('next Monday + 6 days'));
$this->assertNotEmpty($timetable);
$this->assertCount(4, $timetable);
$this->assertEquals($monday->format('Y-m-d').' 09:30', $timetable[0][0]->format('Y-m-d H:i'));
$this->assertEquals($monday->format('Y-m-d').' 12:00', $timetable[0][1]->format('Y-m-d H:i'));
$this->assertEquals($monday->format('Y-m-d').' 13:00', $timetable[1][0]->format('Y-m-d H:i'));
$this->assertEquals($monday->format('Y-m-d').' 17:00', $timetable[1][1]->format('Y-m-d H:i'));
$this->assertEquals($monday->add(new DateInterval('P1D'))->format('Y-m-d').' 09:30', $timetable[2][0]->format('Y-m-d H:i'));
$this->assertEquals($monday->format('Y-m-d').' 12:00', $timetable[2][1]->format('Y-m-d H:i'));
$this->assertEquals($monday->format('Y-m-d').' 13:00', $timetable[3][0]->format('Y-m-d H:i'));
$this->assertEquals($monday->format('Y-m-d').' 17:00', $timetable[3][1]->format('Y-m-d H:i'));
}
public function testCalculateOverTime()
{
$d = new TimetableDay($this->container);
$w = new TimetableWeek($this->container);
$e = new TimetableExtra($this->container);
$t = new Timetable($this->container);
$monday = new DateTime('next Monday');
$tuesday = new DateTime('next Monday + 1 day');
$friday = new DateTime('next Monday + 4 days');
$this->assertNotFalse($d->create(1, '08:00', '12:00'));
$this->assertNotFalse($d->create(1, '14:00', '18:00'));
$this->assertNotFalse($w->create(1, 1, '09:30', '12:00'));
$this->assertNotFalse($w->create(1, 1, '13:00', '17:00'));
$this->assertNotFalse($w->create(1, 2, '09:30', '12:00'));
$this->assertNotFalse($w->create(1, 2, '13:00', '17:00'));
$this->assertNotFalse($e->create(1, $tuesday->format('Y-m-d'), 0, '17:00', '22:00'));
$this->assertNotFalse($e->create(1, $friday->format('Y-m-d'), 1));
$timetable = $t->calculate(1, $monday, new DateTime('next Monday + 6 days'));
$this->assertNotEmpty($timetable);
$this->assertCount(7, $timetable);
$this->assertEquals($monday->format('Y-m-d').' 09:30', $timetable[0][0]->format('Y-m-d H:i'));
$this->assertEquals($monday->format('Y-m-d').' 12:00', $timetable[0][1]->format('Y-m-d H:i'));
$this->assertEquals($monday->format('Y-m-d').' 13:00', $timetable[1][0]->format('Y-m-d H:i'));
$this->assertEquals($monday->format('Y-m-d').' 17:00', $timetable[1][1]->format('Y-m-d H:i'));
$this->assertEquals($tuesday->format('Y-m-d').' 09:30', $timetable[2][0]->format('Y-m-d H:i'));
$this->assertEquals($tuesday->format('Y-m-d').' 12:00', $timetable[2][1]->format('Y-m-d H:i'));
$this->assertEquals($tuesday->format('Y-m-d').' 13:00', $timetable[3][0]->format('Y-m-d H:i'));
$this->assertEquals($tuesday->format('Y-m-d').' 17:00', $timetable[3][1]->format('Y-m-d H:i'));
$this->assertEquals($tuesday->format('Y-m-d').' 17:00', $timetable[4][0]->format('Y-m-d H:i'));
$this->assertEquals($tuesday->format('Y-m-d').' 22:00', $timetable[4][1]->format('Y-m-d H:i'));
$this->assertEquals($friday->format('Y-m-d').' 08:00', $timetable[5][0]->format('Y-m-d H:i'));
$this->assertEquals($friday->format('Y-m-d').' 12:00', $timetable[5][1]->format('Y-m-d H:i'));
$this->assertEquals($friday->format('Y-m-d').' 14:00', $timetable[6][0]->format('Y-m-d H:i'));
$this->assertEquals($friday->format('Y-m-d').' 18:00', $timetable[6][1]->format('Y-m-d H:i'));
}
public function testCalculateTimeOff()
{
$d = new TimetableDay($this->container);
$w = new TimetableWeek($this->container);
$o = new TimetableOff($this->container);
$t = new Timetable($this->container);
$monday = new DateTime('next Monday');
$tuesday = new DateTime('next Monday + 1 day');
$friday = new DateTime('next Monday + 4 days');
$this->assertNotFalse($d->create(1, '08:00', '12:00'));
$this->assertNotFalse($d->create(1, '14:00', '18:00'));
$this->assertNotFalse($w->create(1, 1, '09:30', '12:00'));
$this->assertNotFalse($w->create(1, 1, '13:00', '17:00'));
$this->assertNotFalse($w->create(1, 2, '09:30', '12:00'));
$this->assertNotFalse($w->create(1, 2, '13:00', '17:00'));
$this->assertNotFalse($w->create(1, 5, '09:30', '12:00'));
$this->assertNotFalse($w->create(1, 5, '13:00', '17:00'));
$this->assertNotFalse($o->create(1, $tuesday->format('Y-m-d'), 0, '14:00', '15:00'));
$this->assertNotFalse($o->create(1, $monday->format('Y-m-d'), 1));
$timetable = $t->calculate(1, $monday, new DateTime('next Monday + 6 days'));
$this->assertNotEmpty($timetable);
$this->assertCount(5, $timetable);
$this->assertEquals($tuesday->format('Y-m-d').' 09:30', $timetable[0][0]->format('Y-m-d H:i'));
$this->assertEquals($tuesday->format('Y-m-d').' 12:00', $timetable[0][1]->format('Y-m-d H:i'));
$this->assertEquals($tuesday->format('Y-m-d').' 13:00', $timetable[1][0]->format('Y-m-d H:i'));
$this->assertEquals($tuesday->format('Y-m-d').' 14:00', $timetable[1][1]->format('Y-m-d H:i'));
$this->assertEquals($tuesday->format('Y-m-d').' 15:00', $timetable[2][0]->format('Y-m-d H:i'));
$this->assertEquals($tuesday->format('Y-m-d').' 17:00', $timetable[2][1]->format('Y-m-d H:i'));
$this->assertEquals($friday->format('Y-m-d').' 09:30', $timetable[3][0]->format('Y-m-d H:i'));
$this->assertEquals($friday->format('Y-m-d').' 12:00', $timetable[3][1]->format('Y-m-d H:i'));
$this->assertEquals($friday->format('Y-m-d').' 13:00', $timetable[4][0]->format('Y-m-d H:i'));
$this->assertEquals($friday->format('Y-m-d').' 17:00', $timetable[4][1]->format('Y-m-d H:i'));
}
}