PYBS (Personel Yönetim Bilgi Sistemi)
<?php
// modules/izin-gir.php
session_start();
require_once '../config/db.php';
require_once '../config/functions.php';
// Yetkiler: Root, Yönetici, Muhasebe, İK
yetkiKontrol(['root', 'yonetici', 'muhasebe', 'insan_kaynaklari']);
include '../includes/header.php';
include '../includes/menu.php';
$mesaj = '';
$kullanici_id = $_SESSION['kullanici_id'];
$rol = $_SESSION['rol'];
// Tüm aktif çalışanlar
$tum_calisanlar = $pdo->query("SELECT id, ad, soyad, rol FROM kullanicilar WHERE durum=1 AND rol != 'root' ORDER BY ad ASC")->fetchAll();
// İzin türleri
$izin_turleri = [
'yillik' => 'Yıllık İzin (Hakedişe Göre)',
'hastalik' => 'Hastalık/Rapor İzni',
'evlilik' => 'Evlilik İzni (7 Gün)',
'babalik' => 'Babalık İzni (5 Gün)',
'olum' => 'Ölüm İzni (3 Gün)',
'saatlik' => 'Saatlik İzin (Ücretsiz İzin/Kesinti)',
'diger' => 'Diğer Ücretli İzin'
];
// Saat seçenekleri (tam ve buçuk)
$zaman_secenekleri = "";
for ($saat = 0; $saat < 24; $saat++) {
foreach (['00', '30'] as $dakika) {
$deger = sprintf('%02d:%s', $saat, $dakika);
$zaman_secenekleri .= "<option value='$deger'>$deger</option>";
}
}
// POST İŞLEMLERİ (değişmedi, sadece goto etiketi korundu)
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
csrfKontrol($_POST['csrf_token']);
$calisan_id = (int)$_POST['calisan_id'];
$izin_turu = $_POST['izin_turu'];
$aciklama = guvenlik($_POST['aciklama']);
$saatlik_sure = 0.00;
$toplam_gun = 0;
$baslangic_kayit = "";
$bitis_kayit = "";
$hata = false;
if ($izin_turu == 'saatlik') {
$tarih = $_POST['saatlik_tarih'];
$bas_saat = $_POST['saatlik_bas'];
$bit_saat = $_POST['saatlik_bit'];
$baslangic = "$tarih $bas_saat:00";
$bitis = "$tarih $bit_saat:00";
if (empty($tarih) || empty($bas_saat) || empty($bit_saat)) {
$mesaj = '<div class="alert alert-danger">Hata: Saatlik izin için Tarih, Başlangıç ve bitiş saati zorunludur.</div>';
$hata = true;
goto end_of_post;
}
if (strtotime($bitis) <= strtotime($baslangic)) {
$mesaj = '<div class="alert alert-danger">Hata: Bitiş saati başlangıçtan sonra olmalıdır.</div>';
$hata = true;
goto end_of_post;
}
$diff_saniye = strtotime($bitis) - strtotime($baslangic);
$ham_saat = $diff_saniye / 3600;
if ($ham_saat <= 0) {
$mesaj = '<div class="alert alert-danger">Hata: Saatlik izin süresi sıfırdan büyük olmalıdır.</div>';
$hata = true;
goto end_of_post;
}
// ÖĞLE MOLASI DÜŞÜMÜ (yeni kural)
$dt_tarih = new DateTime($tarih);
$gun_no = $dt_tarih->format('N'); // 1=Pzt ... 5=Cuma
if ($gun_no >= 1 && $gun_no <= 5) {
$mola_bas = strtotime($tarih . ' 12:00:00');
$mola_bit = strtotime($tarih . ' 13:00:00');
$izin_bas = strtotime($baslangic);
$izin_bit = strtotime($bitis);
$kesisim_bas = max($izin_bas, $mola_bas);
$kesisim_bit = min($izin_bit, $mola_bit);
if ($kesisim_bit > $kesisim_bas) {
$kesisim_saniye = $kesisim_bit - $kesisim_bas;
$kesisim_saat = $kesisim_saniye / 3600;
$saatlik_sure = round($ham_saat - $kesisim_saat, 2);
} else {
$saatlik_sure = round($ham_saat, 2);
}
} else {
$saatlik_sure = round($ham_saat, 2);
}
if ($saatlik_sure <= 0) {
$mesaj = '<div class="alert alert-danger">Hata: Net Saatlik izin süresi sıfırdan büyük olmalıdır (Moladan sonra).</div>';
$hata = true;
goto end_of_post;
}
$baslangic_kayit = $baslangic;
$bitis_kayit = $bitis;
} else {
$baslangic = $_POST['baslangic_gunluk'];
$bitis = $_POST['bitis_gunluk'];
if (empty($baslangic) || empty($bitis)) {
$mesaj = '<div class="alert alert-danger">Hata: Başlangıç ve bitiş tarihleri zorunludur.</div>';
$hata = true;
goto end_of_post;
}
$dt_bas = new DateTime($baslangic);
$dt_bit = new DateTime($bitis);
$interval = $dt_bas->diff($dt_bit);
$toplam_gun = $interval->days + 1;
if ($toplam_gun <= 0) {
$mesaj = '<div class="alert alert-danger">Hata: İzin süresi en az 1 gün olmalıdır.</div>';
$hata = true;
goto end_of_post;
}
$baslangic_kayit = $baslangic . " 08:00:00";
$bitis_kayit = $bitis . " 18:00:00";
}
// ÇAKIŞMA KONTROLÜ
if (!$hata) {
$kontrol_bas = date('Y-m-d', strtotime($baslangic_kayit));
$kontrol_bit = date('Y-m-d', strtotime($bitis_kayit));
if ($izin_turu != 'saatlik') {
$sql_izin_cakisma = "
SELECT COUNT(*) FROM izin_talepleri
WHERE calisan_id = ?
AND durum = 'onaylandi'
AND izin_turu != 'saatlik'
AND (
(? BETWEEN DATE(baslangic_tarihi) AND DATE(bitis_tarihi)) OR
(? BETWEEN DATE(baslangic_tarihi) AND DATE(bitis_tarihi))
)";
$stmt_izin_cakisma = $pdo->prepare($sql_izin_cakisma);
$stmt_izin_cakisma->execute([$calisan_id, $kontrol_bas, $kontrol_bit]);
if ($stmt_izin_cakisma->fetchColumn() > 0) {
$mesaj = '<div class="alert alert-danger">Hata: Bu tarihler arasında personel için zaten onaylanmış <strong>TAM GÜN İZİN</strong> kaydı bulunmaktadır!</div>';
$hata = true;
}
}
if (!$hata) {
$sql_mesai_cakisma = "
SELECT COUNT(*) FROM mesai_hareketleri
WHERE calisan_id = ?
AND durum = 'onaylandi'
AND tarih BETWEEN ? AND ?";
$stmt_mesai_cakisma = $pdo->prepare($sql_mesai_cakisma);
$stmt_mesai_cakisma->execute([$calisan_id, $kontrol_bas, $kontrol_bit]);
if ($stmt_mesai_cakisma->fetchColumn() > 0) {
$mesaj = '<div class="alert alert-danger">Hata: Bu tarihler arasında personel için zaten onaylanmış <strong>MESAİ</strong> kaydı bulunmaktadır!</div>';
$hata = true;
}
}
}
// KAYIT
if (!$hata) {
$sql = "INSERT INTO izin_talepleri (calisan_id, hedef_yonetici_id, onaylayan_id, izin_turu, baslangic_tarihi, bitis_tarihi, toplam_gun, saatlik_sure, aciklama, durum, onaylanma_tarihi)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'onaylandi', NOW())";
try {
$pdo->prepare($sql)->execute([
$calisan_id,
$kullanici_id,
$kullanici_id,
$izin_turu,
$baslangic_kayit,
$bitis_kayit,
$toplam_gun,
$saatlik_sure,
$aciklama
]);
$log_detay = "Yön. İzin Girişi: {$toplam_gun} Gün / {$saatlik_sure} Saat ({$izin_turu}) Personel ID: {$calisan_id}";
logKaydet($pdo, $kullanici_id, 'ekleme', $log_detay, 'izin_talepleri', $pdo->lastInsertId());
$mesaj = '<div class="alert alert-success border-success border-5 border-start shadow-sm">
<h5 class="alert-heading fw-bold"><i class="fas fa-check-circle me-2"></i>Başarılı!</h5>
İzin kaydı personel adına otomatik onaylanarak sisteme eklendi.
</div>';
} catch (PDOException $e) {
$mesaj = '<div class="alert alert-danger">Veritabanı Hatası: ' . htmlspecialchars($e->getMessage()) . '</div>';
}
}
}
end_of_post:
// AJAX bakiye sorgusu (değişmedi)
if (isset($_GET['action']) && $_GET['action'] == 'get_bakiye' && isset($_GET['personel_id'])) {
$personel_id_bakiye = (int)$_GET['personel_id'];
$stmt_u = $pdo->prepare("SELECT ise_giris_tarihi, devreden_izin, rol FROM kullanicilar WHERE id = ?");
$stmt_u->execute([$personel_id_bakiye]);
$user_data = $stmt_u->fetch();
$kalan_bakiye = 0;
if ($user_data) {
$ise_giris = new DateTime($user_data['ise_giris_tarihi']);
$bugun = new DateTime();
$kidem_yil = $ise_giris->diff($bugun)->y;
$yasal_hak = ($kidem_yil >= 15) ? 26 : (($kidem_yil >= 5) ? 20 : 14);
if ($user_data['rol'] == 'stajyer') $yasal_hak = 0;
$toplam_hak = $yasal_hak + (float)$user_data['devreden_izin'];
$sql_kul = "SELECT SUM(toplam_gun) FROM izin_talepleri WHERE calisan_id = ? AND izin_turu = 'yillik' AND durum = 'onaylandi' AND YEAR(baslangic_tarihi) = YEAR(CURDATE())";
$stmt_kul = $pdo->prepare($sql_kul);
$stmt_kul->execute([$personel_id_bakiye]);
$kullanilan = (float)$stmt_kul->fetchColumn();
$kalan_bakiye = $toplam_hak - $kullanilan;
}
header('Content-Type: application/json');
echo json_encode(['kalan_bakiye' => number_format($kalan_bakiye, 1)]);
exit;
}
?>
<!DOCTYPE html>
<html lang="tr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap 5 -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" rel="stylesheet">
<title>Personel Adına İzin Girişi</title>
<style>
body { background-color: #f8f9fa; }
.card { border: none; border-radius: 1.5rem; overflow: hidden; }
.card-header { background: linear-gradient(135deg, #0d6efd, #0dcaf0); color: white; }
.form-control, .form-select { border-radius: 0.75rem; }
.btn-primary { border-radius: 0.75rem; padding: 0.85rem; font-weight: 600; }
.alert-important { border-left-width: 6px; }
@media (max-width: 576px) {
.container-fluid { padding: 1rem; }
h3 { font-size: 1.4rem; }
}
</style>
</head>
<body>
<div class="container-fluid py-4 py-md-5">
<div class="row justify-content-center">
<div class="col-12 col-lg-10 col-xl-8">
<h3 class="mb-4 text-center text-primary fw-bold">
<i class="fas fa-calendar-plus me-2"></i>Personel Adına İzin Girişi
</h3>
<div class="alert alert-warning alert-important mb-4" role="alert">
<h6 class="alert-heading fw-bold"><i class="fas fa-exclamation-triangle me-2"></i>Önemli Uyarı</h6>
Bu sayfadan girilen izinler <strong>otomatik onaylı</strong> olarak personel kartına yansır.
Lütfen bilgileri dikkatle kontrol edin. Tarih aralığında onaylı mesai veya tam gün izin varsa kayıt engellenir.
</div>
<div class="card shadow-lg">
<div class="card-header py-4 text-center">
<h5 class="mb-0 text-white fw-bold">İzin Bilgilerini Giriniz</h5>
</div>
<div class="card-body p-4 p-md-5">
<?php echo $mesaj; ?>
<form method="POST" id="izinGirForm" novalidate>
<input type="hidden" name="csrf_token" value="<?php echo csrfTokenOlustur(); ?>">
<!-- Personel Seçimi -->
<div class="mb-4">
<label for="calisanIdSecim" class="form-label fw-semibold">
<i class="fas fa-user me-2 text-primary"></i>Personel <span class="text-danger">*</span>
</label>
<select name="calisan_id" id="calisanIdSecim" class="form-select form-select-lg" required onchange="personelSecildi()">
<option value="">Seçiniz...</option>
<?php foreach($tum_calisanlar as $c): ?>
<option value="<?php echo $c['id']; ?>">
<?php echo htmlspecialchars($c['ad'].' '.$c['soyad']).' ('.strtoupper($c['rol']).')'; ?>
</option>
<?php endforeach; ?>
</select>
</div>
<!-- İzin Türü -->
<div class="mb-4">
<label for="izinTuru" class="form-label fw-semibold">
<i class="fas fa-tasks me-2 text-primary"></i>İzin Türü <span class="text-danger">*</span>
</label>
<select name="izin_turu" id="izinTuru" class="form-select form-select-lg" required onchange="turDegisti()">
<option value="">Seçiniz...</option>
<?php foreach($izin_turleri as $k => $v): ?>
<option value="<?php echo $k; ?>"><?php echo $v; ?></option>
<?php endforeach; ?>
</select>
<div id="bakiyeBilgisi" class="mt-3 p-3 bg-info bg-opacity-10 border border-info rounded d-none">
<i class="fas fa-info-circle me-2"></i>
<strong>Kalan Yıllık İzin Bakiyesi:</strong> <span id="bakiyeText">Yükleniyor...</span>
</div>
</div>
<!-- Günlük İzin Alanları -->
<div id="gunlukIzin" class="row g-3 mb-4">
<div class="col-md-6">
<label for="baslangicGunluk" class="form-label fw-semibold">
<i class="fas fa-calendar-alt me-2 text-primary"></i>Başlangıç Tarihi <span class="text-danger">*</span>
</label>
<input type="date" name="baslangic_gunluk" id="baslangicGunluk" class="form-control form-control-lg">
</div>
<div class="col-md-6">
<label for="bitisGunluk" class="form-label fw-semibold">
<i class="fas fa-calendar-check me-2 text-primary"></i>Bitiş Tarihi <span class="text-danger">*</span>
</label>
<input type="date" name="bitis_gunluk" id="bitisGunluk" class="form-control form-control-lg">
</div>
</div>
<!-- Saatlik İzin Alanları -->
<div id="saatlikIzin" class="d-none">
<div class="row g-3 mb-3">
<div class="col-sm-4">
<label for="saatlikTarih" class="form-label fw-semibold">
<i class="fas fa-calendar-day me-2 text-primary"></i>Tarih <span class="text-danger">*</span>
</label>
<input type="date" name="saatlik_tarih" id="saatlikTarih" class="form-control form-control-lg">
</div>
<div class="col-sm-4">
<label for="saatlikBas" class="form-label fw-semibold">
<i class="fas fa-clock me-2 text-primary"></i>Başlangıç Saati <span class="text-danger">*</span>
</label>
<select name="saatlik_bas" id="saatlikBas" class="form-select form-select-lg">
<option value="">Seçiniz</option>
<?php echo $zaman_secenekleri; ?>
</select>
</div>
<div class="col-sm-4">
<label for="saatlikBit" class="form-label fw-semibold">
<i class="far fa-clock me-2 text-primary"></i>Bitiş Saati <span class="text-danger">*</span>
</label>
<select name="saatlik_bit" id="saatlikBit" class="form-select form-select-lg">
<option value="">Seçiniz</option>
<?php echo $zaman_secenekleri; ?>
</select>
</div>
</div>
<div class="alert alert-info small">
<i class="fas fa-info-circle me-2"></i>
Saatlik izin süresi otomatik hesaplanır. Hafta içi günlerde <strong>12:00–13:00 arası öğle molası</strong> düşülür.
</div>
</div>
<!-- Açıklama -->
<div class="mb-4">
<label for="aciklama" class="form-label fw-semibold">
<i class="fas fa-comment-dots me-2 text-primary"></i>Açıklama / Not
</label>
<textarea name="aciklama" id="aciklama" class="form-control form-control-lg" rows="4" placeholder="İzin nedeni veya ek bilgi..."></textarea>
</div>
<!-- Gönder Butonu -->
<div class="d-grid">
<button type="submit" class="btn btn-primary btn-lg shadow">
<i class="fas fa-save me-2"></i> KAYDET VE ONAYLA
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script>
function turDegisti() {
const tur = document.getElementById('izinTuru').value;
const gunlukDiv = document.getElementById('gunlukIzin');
const saatlikDiv = document.getElementById('saatlikIzin');
const bakiyeDiv = document.getElementById('bakiyeBilgisi');
// Alanları sıfırlama ve required ayarlama
const resetFields = (isGunluk) => {
if (isGunluk) {
document.getElementById('baslangicGunluk').value = '';
document.getElementById('bitisGunluk').value = '';
document.getElementById('baslangicGunluk').required = tur !== 'saatlik';
document.getElementById('bitisGunluk').required = tur !== 'saatlik';
} else {
document.getElementById('saatlikTarih').value = '';
document.getElementById('saatlikBas').selectedIndex = 0;
document.getElementById('saatlikBit').selectedIndex = 0;
document.getElementById('saatlikTarih').required = tur === 'saatlik';
document.getElementById('saatlikBas').required = tur === 'saatlik';
document.getElementById('saatlikBit').required = tur === 'saatlik';
}
};
if (tur === 'saatlik') {
gunlukDiv.classList.add('d-none');
saatlikDiv.classList.remove('d-none');
bakiyeDiv.classList.add('d-none');
resetFields(true);
resetFields(false);
} else {
gunlukDiv.classList.remove('d-none');
saatlikDiv.classList.add('d-none');
resetFields(true);
resetFields(false);
// Yıllık izin seçiliyse ve personel seçilmişse bakiye göster
if (tur === 'yillik' && document.getElementById('calisanIdSecim').value) {
personelSecildi();
} else {
bakiyeDiv.classList.add('d-none');
}
}
}
function personelSecildi() {
const personelId = document.getElementById('calisanIdSecim').value;
const tur = document.getElementById('izinTuru').value;
const bakiyeDiv = document.getElementById('bakiyeBilgisi');
const bakiyeText = document.getElementById('bakiyeText') || bakiyeDiv;
if (tur !== 'yillik' || !personelId) {
bakiyeDiv.classList.add('d-none');
return;
}
bakiyeDiv.classList.remove('d-none');
bakiyeText.innerHTML = 'Yükleniyor...';
fetch(`izin-gir.php?action=get_bakiye&personel_id=${personelId}`)
.then(r => r.ok ? r.json() : Promise.reject())
.then(data => {
bakiyeText.innerHTML = `<strong>${data.kalan_bakiye} gün</strong>`;
})
.catch(() => {
bakiyeText.innerHTML = 'Bilgi alınamadı.';
});
}
// Sayfa yüklendiğinde başlangıç durumu
document.addEventListener('DOMContentLoaded', () => {
turDegisti();
});
</script>
<?php include '../includes/footer.php'; ?>
</body>
</html>
DEMO SÜRÜMÜDÜR TAM SÜRÜM İÇİN İLETİŞİM KURUN
📖 PYBS (Personel Yönetim Bilgi Sistemi) Kullanım Kılavuzu
🚀 Proje Tanımı
PYBS, personel bilgilerini, izinleri, maaş bordrolarını ve performans değerlendirmelerini merkezi ve dijital bir platformda yönetmek için tasarlanmış kapsamlı bir Personel Yönetim Bilgi Sistemi'dir. Amacımız, İnsan Kaynakları (İK) süreçlerini otomatikleştirerek verimliliği artırmak ve veri tutarlılığını sağlamaktır.
✨ Temel Özellikler
Personel Yönetimi: Çalışanların kişisel, iletişim ve görev bilgilerini kaydetme/güncelleme.
İzin Yönetimi: Çalışanların izin taleplerini oluşturma, onaylama/reddetme ve kalan izin haklarını takip etme.
Performans Değerlendirme: Yöneticilerin ve çalışanların performans hedeflerini belirlemesi ve değerlendirmeleri kaydetmesi.
Bordro Entegrasyonu: Maaş ve avans bilgilerini kaydetme ve bordro çıktılarını oluşturma (Harici sistemlerle entegrasyon potansiyeli).
Raporlama: İK yöneticileri için özet ve detaylı personel, izin ve bordro raporları oluşturma.
💻 Son Kullanıcı Kullanımı🔑 Giriş Yapma
Demo için kullanıcı adı : test.test
Demo için şifre : 123456
Demo hesabında root / yonetici vb yetki yoktur.
Tam sürüm için iletişime geçin.
Sistem "Ramsa Makine" tarafından aktif olarak kullanılmaktadır
Meta Veri (Özet)
İşyeri çalışanlarının maaş, fazla mesai ve puantaj ile bordro takip, kontrol ve raporlama sistemi