- Added `users_permissions` table for managing user permissions. - Created `PermissionRepository` for handling permission logic. - Refactored `controls\Users::permissions()` to utilize the new database structure. - Introduced AJAX endpoint for saving user permissions. - Enhanced user management UI with permission checkboxes. - Added vacation management template for handling employee absences. - Implemented tests for `PermissionRepository`.
380 lines
15 KiB
PHP
380 lines
15 KiB
PHP
<div class="form_container full vacations-page">
|
|
<div class="block-header">
|
|
<h2>Urlopy i <strong>nieobecności</strong></h2>
|
|
</div>
|
|
|
|
<div class="action_menu">
|
|
<? if ( $this -> can_switch_back ):?>
|
|
<a href="/users/back_to_admin/" class="btn btn-warning" title="Powrót do konta administratora">
|
|
<i class="fa fa-undo"></i> Powrot do admina
|
|
</a>
|
|
<? endif;?>
|
|
</div>
|
|
|
|
<div class="content">
|
|
|
|
<!-- Filtry -->
|
|
<form method="GET" action="/users/vacations/" class="filters-bar">
|
|
<select name="user_id">
|
|
<option value="0">Wszyscy pracownicy</option>
|
|
<? if ( is_array( $this -> users ) ): foreach ( $this -> users as $u ):?>
|
|
<option value="<?= (int) $u['id'];?>" <?= (int) $this -> filter_user_id === (int) $u['id'] ? 'selected' : '';?>>
|
|
<?= htmlspecialchars( $u['name'] . ' ' . $u['surname'] );?>
|
|
</option>
|
|
<? endforeach; endif;?>
|
|
</select>
|
|
|
|
<select name="year">
|
|
<? for ( $y = (int) date( 'Y' ) + 1; $y >= (int) date( 'Y' ) - 3; $y-- ):?>
|
|
<option value="<?= $y;?>" <?= (int) $this -> year === $y ? 'selected' : '';?>><?= $y;?></option>
|
|
<? endfor;?>
|
|
</select>
|
|
|
|
<button type="submit" class="btn btn-primary"><i class="fa fa-filter"></i> Filtruj</button>
|
|
<button type="button" class="btn btn-success" id="vacation-add-btn"><i class="fa fa-plus"></i> Dodaj urlop</button>
|
|
</form>
|
|
|
|
<!-- Zaległy urlop z poprzednich lat -->
|
|
<? if ( is_array( $this -> carryover ) and count( $this -> carryover ) ):?>
|
|
<div style="background: #fef3e0; border-left: 4px solid #e67e22; border-radius: 4px; padding: 14px 18px; margin-bottom: 20px;">
|
|
<div style="font-weight: 600; color: #e67e22; margin-bottom: 8px;">
|
|
<i class="fa fa-exclamation-triangle"></i> Zaległy urlop z poprzednich lat
|
|
</div>
|
|
<? foreach ( $this -> carryover as $c ):?>
|
|
<div style="margin-bottom: 4px; color: #5a4e3a;">
|
|
<strong><?= htmlspecialchars( $c['name'] );?></strong>
|
|
— <strong><?= (int) $c['total'];?> dni</strong>
|
|
<span style="color: #999; margin-left: 4px;">(<?
|
|
$parts = [];
|
|
foreach ( $c['years'] as $yd )
|
|
$parts[] = (int) $yd['year'] . ': ' . (int) $yd['remaining'] . ' dni';
|
|
echo implode( ', ', $parts );
|
|
?>)</span>
|
|
</div>
|
|
<? endforeach;?>
|
|
</div>
|
|
<? endif;?>
|
|
|
|
<!-- Podsumowanie roczne -->
|
|
<div class="section-title">Podsumowanie roku <?= (int) $this -> year;?></div>
|
|
<table class="table">
|
|
<thead>
|
|
<tr>
|
|
<th>Pracownik</th>
|
|
<th style="width: 100px;" class="center">Limit dni</th>
|
|
<th style="width: 120px;" class="center">Wykorzystano</th>
|
|
<th style="width: 100px;" class="center">Pozostało</th>
|
|
<th style="width: 120px;" class="center">Akcje</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<? if ( is_array( $this -> summary ) ): foreach ( $this -> summary as $s ):?>
|
|
<tr>
|
|
<td class="left"><?= htmlspecialchars( $s['name'] );?></td>
|
|
<td class="center"><?= (int) $s['limit'];?></td>
|
|
<td class="center"><?= (int) $s['used'];?></td>
|
|
<td class="center">
|
|
<strong style="color: <?= $s['remaining'] < 0 ? '#cc563d' : '#099885';?>;"><?= (int) $s['remaining'];?></strong>
|
|
</td>
|
|
<td class="center">
|
|
<button class="btn btn-success btn_small vacation-change-limit" data-user-id="<?= (int) $s['user_id'];?>" data-current-limit="<?= (int) $s['limit'];?>">
|
|
<i class="fa fa-pencil"></i> Zmień limit
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
<? endforeach; endif;?>
|
|
</tbody>
|
|
</table>
|
|
|
|
<!-- Lista nieobecności -->
|
|
<div class="section-title">Nieobecności</div>
|
|
<table class="table">
|
|
<thead>
|
|
<tr>
|
|
<th>Pracownik</th>
|
|
<th style="width: 110px;">Od</th>
|
|
<th style="width: 110px;">Do</th>
|
|
<th style="width: 160px;">Typ</th>
|
|
<th style="width: 80px;" class="center">Dni rob.</th>
|
|
<th>Komentarz</th>
|
|
<th style="width: 80px;" class="center">Akcje</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<? if ( is_array( $this -> vacations ) and count( $this -> vacations ) ): foreach ( $this -> vacations as $v ):?>
|
|
<? $business_days = \Domain\Users\VacationRepository::countBusinessDays( $v['date_from'], $v['date_to'] );?>
|
|
<tr>
|
|
<td class="left"><?= htmlspecialchars( $v['name'] . ' ' . $v['surname'] );?></td>
|
|
<td><?= htmlspecialchars( $v['date_from'] );?></td>
|
|
<td><?= htmlspecialchars( $v['date_to'] );?></td>
|
|
<td>
|
|
<span class="vacation-type-badge type-<?= htmlspecialchars( $v['type'] );?>">
|
|
<?= isset( $this -> vacation_types[ $v['type'] ] ) ? $this -> vacation_types[ $v['type'] ] : $v['type'];?>
|
|
</span>
|
|
</td>
|
|
<td class="center"><?= $business_days;?></td>
|
|
<td class="left"><?= htmlspecialchars( $v['comment'] );?></td>
|
|
<td class="center">
|
|
<button class="btn btn-success btn_small vacation-edit"
|
|
data-id="<?= (int) $v['id'];?>"
|
|
data-user-id="<?= (int) $v['user_id'];?>"
|
|
data-date-from="<?= htmlspecialchars( $v['date_from'] );?>"
|
|
data-date-to="<?= htmlspecialchars( $v['date_to'] );?>"
|
|
data-type="<?= htmlspecialchars( $v['type'] );?>"
|
|
data-comment="<?= htmlspecialchars( $v['comment'] );?>">
|
|
<i class="fa fa-pencil"></i>
|
|
</button>
|
|
<button class="btn btn-danger btn_small vacation-delete" data-id="<?= (int) $v['id'];?>">
|
|
<i class="fa fa-trash"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
<? endforeach; else:?>
|
|
<tr>
|
|
<td colspan="7" class="center">Brak nieobecności w wybranym okresie.</td>
|
|
</tr>
|
|
<? endif;?>
|
|
</tbody>
|
|
</table>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
(function(){
|
|
var currentYear = <?= (int) $this -> year;?>;
|
|
var currentFilterUser = <?= (int) $this -> filter_user_id;?>;
|
|
var csrfToken = '<?= \S::csrf_token();?>';
|
|
|
|
function reloadPage() {
|
|
var url = '/users/vacations/?year=' + currentYear;
|
|
if ( currentFilterUser ) url += '&user_id=' + currentFilterUser;
|
|
window.location.href = url;
|
|
}
|
|
|
|
// Dodaj urlop — popup
|
|
$( '#vacation-add-btn' ).on( 'click', function(e) {
|
|
e.preventDefault();
|
|
|
|
var html = '<form id="vacation-add-form" style="padding: 15px;">';
|
|
html += '<input type="hidden" name="csrf_token" value="' + csrfToken + '">';
|
|
html += '<div class="form-group" style="margin-bottom: 12px;">';
|
|
html += '<label>Pracownik</label>';
|
|
html += '<select name="user_id" class="form-control" required>';
|
|
<? if ( is_array( $this -> users ) ): foreach ( $this -> users as $u ):?>
|
|
html += '<option value="<?= (int) $u['id'];?>"><?= htmlspecialchars( $u['name'] . ' ' . $u['surname'] );?></option>';
|
|
<? endforeach; endif;?>
|
|
html += '</select></div>';
|
|
|
|
html += '<div class="form-group" style="margin-bottom: 12px;">';
|
|
html += '<label>Typ</label>';
|
|
html += '<select name="type" class="form-control" required>';
|
|
<? foreach ( $this -> vacation_types as $key => $label ):?>
|
|
html += '<option value="<?= $key;?>"><?= $label;?></option>';
|
|
<? endforeach;?>
|
|
html += '</select></div>';
|
|
|
|
html += '<div class="form-group" style="margin-bottom: 12px;">';
|
|
html += '<label>Data od</label>';
|
|
html += '<input type="date" name="date_from" class="form-control" required>';
|
|
html += '</div>';
|
|
|
|
html += '<div class="form-group" style="margin-bottom: 12px;">';
|
|
html += '<label>Data do</label>';
|
|
html += '<input type="date" name="date_to" class="form-control" required>';
|
|
html += '</div>';
|
|
|
|
html += '<div class="form-group" style="margin-bottom: 12px;">';
|
|
html += '<label>Komentarz</label>';
|
|
html += '<textarea name="comment" class="form-control" rows="2"></textarea>';
|
|
html += '</div>';
|
|
|
|
html += '<button type="submit" class="btn btn-success" style="width: 100%;"><i class="fa fa-check"></i> Zapisz</button>';
|
|
html += '</form>';
|
|
|
|
$( '.default_popup .title' ).text( 'Dodaj urlop / nieobecność' );
|
|
show_default_popup( html );
|
|
});
|
|
|
|
// Submit formularza dodawania
|
|
$( 'body' ).on( 'submit', '#vacation-add-form', function(e) {
|
|
e.preventDefault();
|
|
var $form = $( this );
|
|
|
|
$.ajax({
|
|
url: '/users/vacation_add/',
|
|
type: 'POST',
|
|
data: $form.serialize(),
|
|
success: function( response ) {
|
|
var data = typeof response === 'string' ? jQuery.parseJSON( response ) : response;
|
|
if ( data.status === 'success' ) {
|
|
$( '.default_popup .close' ).click();
|
|
$.alert({ title: 'Sukces', content: data.msg, type: 'green', buttons: { ok: { action: function(){ reloadPage(); } } } });
|
|
} else {
|
|
$.alert({ title: 'Błąd', content: data.msg, type: 'red' });
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Edycja urlopu — popup
|
|
$( 'body' ).on( 'click', '.vacation-edit', function(e) {
|
|
e.preventDefault();
|
|
var $btn = $( this );
|
|
var id = $btn.data( 'id' );
|
|
var userId = $btn.data( 'user-id' );
|
|
var dateFrom = $btn.data( 'date-from' );
|
|
var dateTo = $btn.data( 'date-to' );
|
|
var type = $btn.data( 'type' );
|
|
var comment = $btn.data( 'comment' ) || '';
|
|
|
|
var html = '<form id="vacation-edit-form" style="padding: 15px;">';
|
|
html += '<input type="hidden" name="csrf_token" value="' + csrfToken + '">';
|
|
html += '<input type="hidden" name="id" value="' + id + '">';
|
|
html += '<div class="form-group" style="margin-bottom: 12px;">';
|
|
html += '<label>Pracownik</label>';
|
|
html += '<select name="user_id" class="form-control" required>';
|
|
<? if ( is_array( $this -> users ) ): foreach ( $this -> users as $u ):?>
|
|
html += '<option value="<?= (int) $u['id'];?>"' + ( userId == <?= (int) $u['id'];?> ? ' selected' : '' ) + '><?= htmlspecialchars( $u['name'] . ' ' . $u['surname'] );?></option>';
|
|
<? endforeach; endif;?>
|
|
html += '</select></div>';
|
|
|
|
html += '<div class="form-group" style="margin-bottom: 12px;">';
|
|
html += '<label>Typ</label>';
|
|
html += '<select name="type" class="form-control" required>';
|
|
<? foreach ( $this -> vacation_types as $key => $label ):?>
|
|
html += '<option value="<?= $key;?>"' + ( type === '<?= $key;?>' ? ' selected' : '' ) + '><?= $label;?></option>';
|
|
<? endforeach;?>
|
|
html += '</select></div>';
|
|
|
|
html += '<div class="form-group" style="margin-bottom: 12px;">';
|
|
html += '<label>Data od</label>';
|
|
html += '<input type="date" name="date_from" class="form-control" value="' + dateFrom + '" required>';
|
|
html += '</div>';
|
|
|
|
html += '<div class="form-group" style="margin-bottom: 12px;">';
|
|
html += '<label>Data do</label>';
|
|
html += '<input type="date" name="date_to" class="form-control" value="' + dateTo + '" required>';
|
|
html += '</div>';
|
|
|
|
html += '<div class="form-group" style="margin-bottom: 12px;">';
|
|
html += '<label>Komentarz</label>';
|
|
html += '<textarea name="comment" class="form-control" rows="2">' + $('<div/>').text(comment).html() + '</textarea>';
|
|
html += '</div>';
|
|
|
|
html += '<button type="submit" class="btn btn-success" style="width: 100%;"><i class="fa fa-check"></i> Zapisz zmiany</button>';
|
|
html += '</form>';
|
|
|
|
$( '.default_popup .title' ).text( 'Edytuj urlop / nieobecność' );
|
|
show_default_popup( html );
|
|
});
|
|
|
|
// Submit formularza edycji
|
|
$( 'body' ).on( 'submit', '#vacation-edit-form', function(e) {
|
|
e.preventDefault();
|
|
var $form = $( this );
|
|
|
|
$.ajax({
|
|
url: '/users/vacation_edit/',
|
|
type: 'POST',
|
|
data: $form.serialize(),
|
|
success: function( response ) {
|
|
var data = typeof response === 'string' ? jQuery.parseJSON( response ) : response;
|
|
if ( data.status === 'success' ) {
|
|
$( '.default_popup .close' ).click();
|
|
$.alert({ title: 'Sukces', content: data.msg, type: 'green', buttons: { ok: { action: function(){ reloadPage(); } } } });
|
|
} else {
|
|
$.alert({ title: 'Błąd', content: data.msg, type: 'red' });
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Usunięcie urlopu
|
|
$( 'body' ).on( 'click', '.vacation-delete', function(e) {
|
|
e.preventDefault();
|
|
var id = $( this ).data( 'id' );
|
|
|
|
$.confirm({
|
|
title: 'Potwierdź',
|
|
content: 'Na pewno chcesz usunąć tę nieobecność?',
|
|
type: 'orange',
|
|
closeIcon: true,
|
|
closeIconClass: 'fa fa-close',
|
|
typeAnimated: true,
|
|
animation: 'opacity',
|
|
boxWidth: '500px',
|
|
useBootstrap: false,
|
|
theme: 'material',
|
|
buttons: {
|
|
confirm: {
|
|
text: 'Usuń',
|
|
btnClass: 'btn-red',
|
|
action: function(){
|
|
$.ajax({
|
|
type: 'POST',
|
|
url: '/users/vacation_delete/',
|
|
data: { id: id, csrf_token: csrfToken },
|
|
success: function( response ) {
|
|
var data = typeof response === 'string' ? jQuery.parseJSON( response ) : response;
|
|
if ( data.status === 'success' ) {
|
|
$.alert({ title: 'Sukces', content: data.msg, type: 'green', buttons: { ok: { action: function(){ reloadPage(); } } } });
|
|
}
|
|
}
|
|
});
|
|
}
|
|
},
|
|
cancel: {
|
|
text: 'Anuluj',
|
|
btnClass: 'btn-default',
|
|
action: function(){}
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Zmiana limitu
|
|
$( 'body' ).on( 'click', '.vacation-change-limit', function(e) {
|
|
e.preventDefault();
|
|
var userId = $( this ).data( 'user-id' );
|
|
var currentLimit = $( this ).data( 'current-limit' );
|
|
|
|
var html = '<form id="vacation-limit-form" style="padding: 15px;">';
|
|
html += '<input type="hidden" name="csrf_token" value="' + csrfToken + '">';
|
|
html += '<input type="hidden" name="user_id" value="' + userId + '">';
|
|
html += '<input type="hidden" name="year" value="' + currentYear + '">';
|
|
html += '<div class="form-group" style="margin-bottom: 12px;">';
|
|
html += '<label>Limit dni urlopowych na rok ' + currentYear + '</label>';
|
|
html += '<input type="number" name="days_limit" class="form-control" min="0" max="365" value="' + currentLimit + '" required>';
|
|
html += '</div>';
|
|
html += '<button type="submit" class="btn btn-success" style="width: 100%;"><i class="fa fa-check"></i> Zapisz</button>';
|
|
html += '</form>';
|
|
|
|
$( '.default_popup .title' ).text( 'Zmień limit urlopowy' );
|
|
show_default_popup( html );
|
|
});
|
|
|
|
// Submit formularza limitu
|
|
$( 'body' ).on( 'submit', '#vacation-limit-form', function(e) {
|
|
e.preventDefault();
|
|
var $form = $( this );
|
|
|
|
$.ajax({
|
|
url: '/users/vacation_limit_save/',
|
|
type: 'POST',
|
|
data: $form.serialize(),
|
|
success: function( response ) {
|
|
var data = typeof response === 'string' ? jQuery.parseJSON( response ) : response;
|
|
if ( data.status === 'success' ) {
|
|
$( '.default_popup .close' ).click();
|
|
$.alert({ title: 'Sukces', content: data.msg, type: 'green', buttons: { ok: { action: function(){ reloadPage(); } } } });
|
|
} else {
|
|
$.alert({ title: 'Błąd', content: data.msg, type: 'red' });
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
})();
|
|
</script>
|