sys/veri_detay/#008

PYBS (Personel Yönetim Bilgi Sistemi)

Son Senkronizasyon: 16.12.2025
admin-mesai-ekle.php 315 satır • 15.53 KB
<?php
// modules/admin-mesai-ekle.php
session_start();
require_once '../config/db.php';
require_once '../config/functions.php';

// Sadece Yetkililer
yetkiKontrol(['root', 'muhasebe', 'insan_kaynaklari']);

include '../includes/header.php';
include '../includes/menu.php';

$mesaj = '';
$kullanici_id = $_SESSION['kullanici_id'];
$hedef = 'tekil'; // Varsayılan: Tekil

// Resmi Tatil Listesi
$tatiller = $pdo->query("SELECT tarih FROM resmi_tatiller")->fetchAll(PDO::FETCH_COLUMN);
$tatiller_json = json_encode($tatiller);

// SAAT SEÇENEKLERİ
$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>";
    }
}

// İŞLEM
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    csrfKontrol($_POST['csrf_token']);

    $hedef = $_POST['hedef_kitle'];
    
    $eklenecekler = [];
    if ($hedef == 'toplu') {
        $eklenecekler = $pdo->query("SELECT id FROM kullanicilar WHERE durum=1 AND rol != 'root'")->fetchAll(PDO::FETCH_COLUMN);
    } elseif ($hedef == 'coklu') {
        $eklenecekler = $_POST['personel_id_coklu'] ?? [];
    } elseif ($hedef == 'tekil') {
        if (!empty($_POST['personel_id_tekil'])) {
            $eklenecekler[] = $_POST['personel_id_tekil'];
        }
    }

    $tarih = $_POST['tarih']; 
    $bas_saat = $_POST['baslangic_saati'];
    $bit_saat = $_POST['bitis_saati'];
    $mesai_turu = $_POST['mesai_turu'];
    $aciklama = guvenlik($_POST['aciklama']);

    // Brüt Süre Hesapla
    $t1 = strtotime($bas_saat);
    $t2 = strtotime($bit_saat);
    if ($t2 < $t1) $t2 += 24 * 60 * 60;
    
    $fark = round(($t2 - $t1) / 3600, 2);
    $net_mesai_kayit = $fark; // Mola düşümü yok, net süre

    $sayac = 0;
    $hata_mesajlari = [];
    $sql = "INSERT INTO mesai_hareketleri (calisan_id, hedef_yonetici_id, onaylayan_id, tarih, baslangic_saati, bitis_saati, toplam_saat, mesai_turu, aciklama, durum, onaylanma_tarihi) 
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'onaylandi', NOW())";
    $stmt = $pdo->prepare($sql);

    if (!empty($eklenecekler)) {
        // Personel verilerini çek
        $personel_data_stmt = $pdo->prepare("SELECT id, ad, soyad FROM kullanicilar WHERE id IN (" . implode(',', $eklenecekler) . ")");
        $personel_data_stmt->execute();
        $personel_bilgileri = $personel_data_stmt->fetchAll(PDO::FETCH_ASSOC | PDO::FETCH_GROUP); 
        
        foreach ($eklenecekler as $pid) {
            $pid = (int)$pid;
            $personel_info = $personel_bilgileri[$pid][0] ?? null;
            if (!$personel_info) continue; 
            
            $personel_ad = $personel_info['ad'] . ' ' . $personel_info['soyad'];
            $hata = false;

            // 1. ZATEN MESAI VAR MI?
            $kontrol_mesai = $pdo->prepare("SELECT count(*) FROM mesai_hareketleri WHERE calisan_id = ? AND tarih = ? AND durum = 'onaylandi' AND ( (baslangic_saati < ? AND bitis_saati > ?) )");
            $kontrol_mesai->execute([$pid, $tarih, $bit_saat, $bas_saat]);
            
            if ($kontrol_mesai->fetchColumn() > 0) {
                $hata_mesajlari[] = "({$personel_ad}) $tarih tarihinde belirtilen saatlerde ($bas_saat - $bit_saat) zaten mesai kaydı var.";
                $hata = true;
            }

            // 2. İZİN ÇAKIŞMASI
            if (!$hata) {
                $kontrol_izin = $pdo->prepare("SELECT izin_turu, baslangic_tarihi, bitis_tarihi FROM izin_talepleri WHERE calisan_id = ? AND durum = 'onaylandi' AND ? BETWEEN DATE(baslangic_tarihi) AND DATE(bitis_tarihi)");
                $kontrol_izin->execute([$pid, $tarih]);
                $izin_kaydi = $kontrol_izin->fetch();

                if ($izin_kaydi) {
                    $i_bas_ts = strtotime($izin_kaydi['baslangic_tarihi']);
                    $i_bit_ts = strtotime($izin_kaydi['bitis_tarihi']);
                    
                    $izin_bas_gun = date('Y-m-d', $i_bas_ts);
                    $izin_bit_gun = date('Y-m-d', $i_bit_ts);
                    
                    if ($izin_bas_gun != $izin_bit_gun) {
                        $hata_mesajlari[] = "({$personel_ad}) Personel çok günlü izinli ({$izin_bas_gun} / {$izin_bit_gun}). Bu tarihte mesai yazılamaz.";
                        $hata = true;
                    } 
                    else {
                        $izin_bitis_saati = date('H:i', $i_bit_ts);
                        $mesai_baslangic_saati = $bas_saat;

                        if ($mesai_baslangic_saati < $izin_bitis_saati) {
                            $hata_mesajlari[] = "({$personel_ad}) Tek günlük izin devam ediyor. Mesai saati ($bas_saat), izin bitişinden ($izin_bitis_saati) sonra olmalıdır.";
                            $hata = true;
                        }
                    }
                }
            }
            
            if (!$hata) {
                try {
                    $gercek_mesai_turu = $mesai_turu;
                    if ($mesai_turu === 'vardiya_gece') $gercek_mesai_turu = 'fazla_mesai';
                    
                    $stmt->execute([$pid, $kullanici_id, $kullanici_id, $tarih, $bas_saat, $bit_saat, $net_mesai_kayit, $gercek_mesai_turu, $aciklama]);
                    $sayac++;
                } catch (PDOException $e) {
                    $hata_mesajlari[] = "({$personel_ad}) Veritabanı Hatası: " . $e->getMessage();
                }
            }
        }
    }

    $mesaj_html = "";
    if ($sayac > 0) {
        $mesaj_html .= '<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>
                          Toplam <strong>'.$sayac.'</strong> personele mesai girişi yapıldı.
                        </div>';
    }
    if (!empty($hata_mesajlari)) {
        $hata_listesi = '<ul>';
        foreach ($hata_mesajlari as $hata) $hata_listesi .= '<li>'.$hata.'</li>';
        $hata_listesi .= '</ul>';

        $mesaj_html .= '
            <div class="alert alert-warning border-warning border-5 border-start shadow-sm">
                <h5 class="alert-heading fw-bold"><i class="fas fa-exclamation-triangle me-2"></i>Mesai İşlemi Uyarıları!</h5>
                Bazı kayıtlar kurallar gereği engellendi:
                <button type="button" class="btn btn-sm btn-warning mt-2" data-bs-toggle="modal" data-bs-target="#hataModal">
                    <i class="fas fa-search me-1"></i> Detayları Gör
                </button>
            </div>
            
            <div class="modal fade" id="hataModal" tabindex="-1">
              <div class="modal-dialog modal-dialog-centered modal-lg">
                <div class="modal-content">
                  <div class="modal-header bg-warning text-dark"><h5 class="modal-title">Engellenen İşlemler</h5><button type="button" class="btn-close" data-bs-dismiss="modal"></button></div>
                  <div class="modal-body"><div class="alert alert-light border-warning">'.$hata_listesi.'</div></div>
                  <div class="modal-footer"><button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Kapat</button></div>
                </div>
              </div>
            </div>';
    }
    if ($sayac == 0 && empty($hata_mesajlari)) {
        $mesaj_html .= '<div class="alert alert-danger">Lütfen işlem yapılacak personel seçin.</div>';
    }
    $mesaj = $mesaj_html;
}

$personeller = $pdo->query("SELECT id, ad, soyad FROM kullanicilar WHERE durum=1 AND rol != 'root' ORDER BY ad ASC")->fetchAll();
?>

<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
    <style>
        body { background-color: #f8f9fa; }
        .card { border: none; border-radius: 1.5rem; overflow: hidden; }
        .card-header { background: linear-gradient(135deg, #0d6efd, #0dcaf0); color: white; }
        .flatpickr-day.resmi-tatil { background: #ffebee !important; border-color: #ffcdd2 !important; color: #c62828 !important; font-weight: bold; }
        .flatpickr-day.pazar-gunu { background: #fff3e0 !important; border-color: #ffe0b2 !important; color: #ef6c00 !important; font-weight: bold; }
    </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-clock me-2"></i>Yönetici Mesai Girişi</h3>
            <div class="card shadow-lg">
                <div class="card-header py-4 text-center"><h5 class="mb-0 text-white fw-bold">Mesai Bilgilerini Giriniz</h5></div>
                <div class="card-body p-4 p-md-5">
                    <?php echo $mesaj; ?>
                    <form method="POST" id="mesaiForm">
                        <input type="hidden" name="csrf_token" value="<?php echo csrfTokenOlustur(); ?>">

                        <div class="mb-4">
                            <label class="form-label fw-semibold">Kime Mesai Eklenecek?</label>
                            <div class="btn-group w-100">
                                <input type="radio" class="btn-check" name="hedef_kitle" id="toplu" value="toplu" onchange="togglePersonel()">
                                <label class="btn btn-outline-primary" for="toplu">Tüm Personel</label>
                                <input type="radio" class="btn-check" name="hedef_kitle" id="coklu" value="coklu" onchange="togglePersonel()">
                                <label class="btn btn-outline-primary" for="coklu">Çoklu Seçim</label>
                                <input type="radio" class="btn-check" name="hedef_kitle" id="tekil" value="tekil" checked onchange="togglePersonel()">
                                <label class="btn btn-outline-primary" for="tekil">Tek Personel</label>
                            </div>
                        </div>

                        <div class="mb-4" id="tekilDiv">
                            <label class="form-label fw-semibold">Personel Seçiniz</label>
                            <select name="personel_id_tekil" id="personel_id_tekil" class="form-select form-select-lg">
                                <option value="">Seçiniz...</option>
                                <?php foreach($personeller as $p) echo "<option value='{$p['id']}'>{$p['ad']} {$p['soyad']}</option>"; ?>
                            </select>
                        </div>

                        <div class="mb-4 d-none" id="cokluDiv">
                            <label class="form-label fw-semibold">Personelleri Seçiniz (Çoklu)</label>
                            <select name="personel_id_coklu[]" id="personel_id_coklu" class="form-select form-select-lg" multiple size="8">
                                <?php foreach($personeller as $p) echo "<option value='{$p['id']}'>{$p['ad']} {$p['soyad']}</option>"; ?>
                            </select>
                            <div class="form-text">Çoklu seçim için Ctrl tuşuna basılı tutun.</div>
                        </div>

                        <div class="row g-3 mb-4">
                            <div class="col-md-6">
                                <label class="form-label fw-semibold">Tarih</label>
                                <input type="text" name="tarih" id="mesaiTarihInput" class="form-control bg-white fw-bold" required value="<?php echo date('Y-m-d'); ?>">
                            </div>
                            <div class="col-md-6">
                                <label class="form-label fw-semibold">Mesai Türü</label>
                                <select name="mesai_turu" id="mesaiTuruSelect" class="form-select bg-light fw-bold">
                                    <option value="fazla_mesai">Fazla Mesai (1.5x)</option>
                                    <option value="resmi_tatil_mesaisi">Resmi Tatil / Bayram (2.0x)</option>
                                    <option value="vardiya_gece">Vardiya Girişi</option>
                                </select>
                            </div>
                        </div>

                        <div class="row g-3 mb-4">
                            <div class="col-md-6">
                                <label class="form-label fw-semibold">Başlangıç Saati</label>
                                <select name="baslangic_saati" class="form-select form-select-lg" required>
                                    <option value="">Seçiniz</option><?php echo $zaman_secenekleri; ?>
                                </select>
                            </div>
                            <div class="col-md-6">
                                <label class="form-label fw-semibold">Bitiş Saati</label>
                                <select name="bitis_saati" class="form-select form-select-lg" required>
                                    <option value="">Seçiniz</option><?php echo $zaman_secenekleri; ?>
                                </select>
                            </div>
                        </div>

                        <div class="mb-4"><label class="form-label fw-semibold">Açıklama</label><input type="text" name="aciklama" class="form-control form-control-lg"></div>
                        <div class="d-grid"><button type="submit" class="btn btn-primary btn-lg shadow">KAYDET VE İŞLE</button></div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/flatpickr"></script>
<script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/l10n/tr.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
<script>
const resmiTatiller = <?php echo $tatiller_json; ?>;
document.addEventListener('DOMContentLoaded', function() {
    flatpickr("#mesaiTarihInput", {
        locale: "tr", 
        dateFormat: "Y-m-d", 
        altInput: true, 
        altFormat: "d F Y", 
        defaultDate: "today", 
        disableMobile: true,
        onChange: function(selectedDates, dateStr) { mesaiTuruOtoSec(dateStr); },
        onDayCreate: function(dObj, dStr, fp, dayElem){
            // DÜZELTME: toISOString() yerine Flatpickr'ın kendi formatlayıcısını kullanıyoruz
            // Bu sayede timezone (saat dilimi) kayması önlenir.
            let d = fp.formatDate(dayElem.dateObj, "Y-m-d");
            
            if (resmiTatiller.includes(d)) {
                dayElem.className += " resmi-tatil";
            } else if (dayElem.dateObj.getDay() === 0) {
                dayElem.className += " pazar-gunu";
            }
        }
    });
    togglePersonel();
    mesaiTuruOtoSec(new Date().toISOString().split('T')[0]);
    if(document.getElementById('hataModal')) new bootstrap.Modal(document.getElementById('hataModal')).show();
});

function togglePersonel() {
    const hedef = document.querySelector('input[name="hedef_kitle"]:checked').value;
    document.getElementById('tekilDiv').classList.toggle('d-none', hedef !== 'tekil');
    document.getElementById('cokluDiv').classList.toggle('d-none', hedef !== 'coklu');
    document.getElementById('personel_id_tekil').required = (hedef === 'tekil');
    document.getElementById('personel_id_coklu').required = (hedef === 'coklu');
}

function mesaiTuruOtoSec(dateStr) {
    if (!dateStr) return;
    const date = new Date(dateStr);
    const day = date.getDay();
    let tur = (resmiTatiller.includes(dateStr) || day === 0) ? 'resmi_tatil_mesaisi' : 'fazla_mesai';
    document.getElementById('mesaiTuruSelect').value = tur;
}
</script>
<?php include '../includes/footer.php'; ?>
</body>
</html>
DATA_PAYLOAD (Açıklama)
Kapak

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

9,549
Sinyal (Ağ Hiti)
1.54 MB
Kapasite

Ağda Paylaş