<?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İ (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>";
}
}
// İŞ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 = ($t2 - $t1) / 3600;
// Mola Düş (Otomatik)
$mola = 0;
if ($fark > 7.5) $mola = 1; elseif ($fark > 4) $mola = 0.5;
$net_saat_brut = $fark - $mola;
if($net_saat_brut < 0) $net_saat_brut = 0;
// Döngü ile Ekle
$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 topluca çek
$personel_data_stmt = $pdo->prepare("SELECT id, ad, soyad, gunluk_calisma_saati FROM kullanicilar WHERE id IN (" . implode(',', $eklenecekler) . ")");
$personel_data_stmt->execute();
// HATA DÜZELTME: FETCH_KEY_PAIR hatası giderildi, ID'ye göre gruplayarak ilişkisel dizi çekildi.
$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 bulunamazsa atla
$personel_ad = $personel_info['ad'] . ' ' . $personel_info['soyad'];
$gunluk_mesai = (float)($personel_info['gunluk_calisma_saati'] ?? 9.00); // Varsayılan 9 saat
// 1. Kontrol: Onaylanmış mevcut mesai kaydı var mı?
$kontrol_mesai = $pdo->prepare("SELECT count(*) FROM mesai_hareketleri WHERE calisan_id = ? AND tarih = ? AND durum = 'onaylandi'");
$kontrol_mesai->execute([$pid, $tarih]);
// 2. Kontrol: Onaylanmış TAM GÜN izin kaydı var mı?
$kontrol_izin_tam = $pdo->prepare("
SELECT count(*) FROM izin_talepleri
WHERE calisan_id = ?
AND durum = 'onaylandi'
AND ? BETWEEN DATE(baslangic_tarihi) AND DATE(bitis_tarihi)
AND izin_turu != 'saatlik'
");
$kontrol_izin_tam->execute([$pid, $tarih]);
$hata = false;
if ($kontrol_mesai->fetchColumn() > 0) {
$hata_mesajlari[] = "({$personel_ad}) $tarih tarihinde zaten onaylanmış <strong>MESAİ</strong> kaydı var.";
$hata = true;
} elseif ($kontrol_izin_tam->fetchColumn() > 0) {
$hata_mesajlari[] = "({$personel_ad}) $tarih tarihinde onaylanmış <strong>TAM GÜN İZİN</strong> kaydı var. Mesai eklenemez.";
$hata = true;
}
// Eğer tam gün veya mesai çakışması yoksa, saatlik izin borcunu hesapla
if (!$hata) {
// 3. Saatlik İzin Borcunu Hesapla
$stmt_saatlik_izin = $pdo->prepare("
SELECT SUM(saatlik_sure) as toplam_izin
FROM izin_talepleri
WHERE calisan_id = ?
AND durum = 'onaylandi'
AND DATE(baslangic_tarihi) = ?
AND izin_turu = 'saatlik'
");
$stmt_saatlik_izin->execute([$pid, $tarih]);
$toplam_saatlik_izin = (float)$stmt_saatlik_izin->fetchColumn() ?? 0.0;
$net_mesai_kayit = $net_saat_brut;
// Eğer saatlik izin varsa ve bu mesai borç kapatmak için kullanılıyorsa
if ($toplam_saatlik_izin > 0) {
// Yeni mesai süresi = Girilen süre - (Borç olan izin süresi)
$gercek_fazla_mesai = $net_saat_brut - $toplam_saatlik_izin;
if ($gercek_fazla_mesai > 0) {
$net_mesai_kayit = round($gercek_fazla_mesai, 2);
// İzin borcunun kapatıldığı bilgisini uyarı olarak ekle
$hata_mesajlari[] = "({$personel_ad}) $tarih tarihinde {$toplam_saatlik_izin} saatlik izin borcu kapatıldı. Fazla mesai süresi: **{$net_mesai_kayit} Saat** olarak kaydedildi.";
} else {
// Fazla mesai, izin borcunu tamamen kapatıyorsa ve geriye bir şey kalmıyorsa, mesaiyi kaydetme
$hata_mesajlari[] = "({$personel_ad}) $tarih tarihinde {$toplam_saatlik_izin} saatlik izin borcu olduğu için, girilen {$net_saat_brut} saat mesai kaydı tamamen izin borcunu kapatmıştır. Fazla mesai **0.0 Saat** olarak kaydedilmedi.";
$hata = true; // <-- KAYDI ENGELLE
}
}
if (!$hata) {
try {
$gercek_mesai_turu = $mesai_turu;
if ($mesai_turu === 'vardiya_gece') {
$gercek_mesai_turu = 'fazla_mesai';
}
// Güncellenmiş net mesai süresini kullan
$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 mesajlarını modalda göstermek için hazırlıyoruz
$hata_listesi = '<ul>';
foreach ($hata_mesajlari as $hata) {
$hata_listesi .= '<li>'.$hata.'</li>';
}
$hata_listesi .= '</ul>';
// Mesajı modalı tetikleyecek şekilde ayarlıyoruz
$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ı/Detayları!</h5>
Bazı personel için süreler ayarlandı/kayıt engellendi. Detaylar için aşağıdaki butona tıklayın:
<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" aria-labelledby="hataModalLabel" aria-hidden="true">
<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" id="hataModalLabel"><i class="fas fa-exclamation-triangle me-2"></i> Mesai İşlemi Detayları</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p class="fw-bold">Aşağıdaki personel için izin/mesai çakışması kontrol edildi. Mesai süreleri ayarlandı veya kayıt engellendi:</p>
<div class="alert alert-light border-warning">
'.$hata_listesi.'
</div>
<p class="small text-muted">Tam gün izin veya mevcut mesai kaydı olanlara işlem yapılmamıştır.</p>
</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;
}
// Personel Listesi
$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">
<meta name="viewport" content="width=device-width, initial-scale=1">
<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>Yönetici Mesai 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; }
.btn-check:checked + .btn-outline-primary { background-color: #0d6efd; border-color: #0d6efd; }
.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-clock me-2"></i>Yönetici Mesai Girişi
</h3>
<div class="alert alert-info alert-important mb-4" role="alert">
<h6 class="alert-heading fw-bold"><i class="fas fa-info-circle me-2"></i>Bilgi</h6>
Bu sayfadan yapılan mesai girişleri <strong>otomatik onaylı</strong> olarak sisteme işlenir.<br>
Aynı güne onaylı tam gün izin veya mevcut mesai kaydı olanlara işlem **yapılmaz**. Saatlik izin borcu varsa, girilen fazla mesai süresi öncelikle bu borcu kapatır.
</div>
<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" novalidate>
<input type="hidden" name="csrf_token" value="<?php echo csrfTokenOlustur(); ?>">
<div class="mb-4">
<label class="form-label fw-semibold">
<i class="fas fa-users me-2 text-primary"></i>Kime Mesai Eklenecek? <span class="text-danger">*</span>
</label>
<div class="btn-group w-100" role="group" aria-label="Hedef kitle">
<input type="radio" class="btn-check" name="hedef_kitle" id="toplu" value="toplu" onchange="togglePersonel()">
<label class="btn btn-outline-primary rounded-start" for="toplu">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 rounded-end" for="tekil">Tek Personel</label>
</div>
</div>
<div class="mb-4" id="tekilDiv">
<label for="personel_id_tekil" class="form-label fw-semibold">
<i class="fas fa-user me-2 text-primary"></i>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): ?>
<option value="<?php echo $p['id']; ?>">
<?php echo htmlspecialchars($p['ad'].' '.$p['soyad']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-4 d-none" id="cokluDiv">
<label for="personel_id_coklu" class="form-label fw-semibold">
<i class="fas fa-users-cog me-2 text-primary"></i>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): ?>
<option value="<?php echo $p['id']; ?>">
<?php echo htmlspecialchars($p['ad'].' '.$p['soyad']); ?>
</option>
<?php endforeach; ?>
</select>
<div class="form-text mt-2">
<i class="fas fa-info-circle me-2"></i>
Birden fazla seçim için <kbd>Ctrl</kbd> (Windows) veya <kbd>Cmd</kbd> (Mac) tuşunu basılı tutun.
</div>
</div>
<hr class="my-5">
<div class="row g-3 mb-4">
<div class="col-md-6">
<label for="tarih" 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="tarih" id="mesaiTarihInput" class="form-control form-control-lg"
value="<?php echo date('Y-m-d'); ?>" required onchange="mesaiTuruOtoSec()">
</div>
<div class="col-md-6">
<label for="mesai_turu" class="form-label fw-semibold">
<i class="fas fa-tags me-2 text-primary"></i>Mesai Türü <span class="text-danger">*</span>
</label>
<select name="mesai_turu" id="mesaiTuruSelect" class="form-select form-select-lg bg-light fw-bold">
<option value="fazla_mesai">Fazla Mesai (Hafta İçi / Cumartesi)</option>
<option value="resmi_tatil_mesaisi">Resmi Tatil / Bayram (2.0x)</option>
<option value="vardiya_gece">Vardiya Girişi (18:00 - 03:00)</option>
</select>
</div>
</div>
<div class="row g-3 mb-4">
<div class="col-md-6">
<label for="baslangic_saati" 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="baslangic_saati" id="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 for="bitis_saati" 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="bitis_saati" id="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 for="aciklama" class="form-label fw-semibold">
<i class="fas fa-comment-dots me-2 text-primary"></i>Açıklama (İsteğe Bağlı)
</label>
<input type="text" name="aciklama" id="aciklama" class="form-control form-control-lg"
placeholder="Örn: Ek üretim vardiyası, bayram mesaisi...">
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary btn-lg shadow">
<i class="fas fa-save me-2"></i> KAYDET VE İŞLE
</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>
const resmiTatiller = <?php echo $tatiller_json; ?>;
function togglePersonel() {
const hedef = document.querySelector('input[name="hedef_kitle"]:checked').value;
const tekilDiv = document.getElementById('tekilDiv');
const cokluDiv = document.getElementById('cokluDiv');
const tekilSelect = document.getElementById('personel_id_tekil');
const cokluSelect = document.getElementById('personel_id_coklu');
tekilDiv.classList.toggle('d-none', hedef !== 'tekil');
cokluDiv.classList.toggle('d-none', hedef !== 'coklu');
// Required ayarı
if (hedef === 'tekil') {
tekilSelect.required = true;
cokluSelect.required = false;
} else if (hedef === 'coklu') {
tekilSelect.required = false;
cokluSelect.required = true;
} else { // toplu
tekilSelect.required = false;
cokluSelect.required = false;
}
}
function mesaiTuruOtoSec() {
const tarihInput = document.getElementById('mesaiTarihInput');
const mesaiSelect = document.getElementById('mesaiTuruSelect');
const tarih = tarihInput.value;
if (!tarih) {
mesaiSelect.value = 'fazla_mesai';
return;
}
const date = new Date(tarih + 'T00:00:00');
const day = date.getDay(); // 0=Pazar, 6=Cumartesi
let tur = 'fazla_mesai';
if (resmiTatiller.includes(tarih) || day === 0) {
tur = 'resmi_tatil_mesaisi';
}
mesaiSelect.value = tur;
}
// Sayfa yüklendiğinde
document.addEventListener('DOMContentLoaded', () => {
togglePersonel();
mesaiTuruOtoSec();
// PHP'den gelen hatayı kontrol et ve modalı tetikle
const hataModal = document.getElementById('hataModal');
if (hataModal) {
const bsHataModal = new bootstrap.Modal(hataModal);
bsHataModal.show();
}
});
</script>
<?php include '../includes/footer.php'; ?>
</body>
</html>