PYBS (Personel Yönetim Bilgi Sistemi) / modules/izin-gir.php
izin-gir.php 479 satır • 20.79 KB
<?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>