PYBS (Personel Yönetim Bilgi Sistemi) / modules/maas-rapor.php
maas-rapor.php 450 satır • 19.00 KB
<?php
// modules/maas-rapor.php
session_start();
require_once '../config/db.php';
require_once '../config/functions.php';

// Yetkili Roller: Root, Yönetici, Muhasebe, İnsan Kaynakları
yetkiKontrol(['root', 'yonetici', 'muhasebe', 'insan_kaynaklari']);

// --- FİLTRELER VE PARAMETRELER ---
$yil = $_GET['yil'] ?? date('Y');
$ay = $_GET['ay'] ?? date('m');
$format = $_GET['format'] ?? 'print'; // 'excel' veya 'pdf' (print)
$personel_filtre_id = $_GET['personel_id'] ?? 'tumu'; // ID, Rol adı veya 'tumu'

// Rapor tarihi, saat ve zaman dilimi ayarı
date_default_timezone_set('Europe/Istanbul'); 
$rapor_tarihi_saati = date('d.m.Y H:i');

$ay_isimleri = ['01'=>'OCAK','02'=>'ŞUBAT','03'=>'MART','04'=>'NİSAN','05'=>'MAYIS','06'=>'HAZİRAN','07'=>'TEMMUZ','08'=>'AĞUSTOS','09'=>'EYLÜL','10'=>'EKİM','11'=>'KASIM','12'=>'ARALIK'];
// BAŞLIK
$baslik = "MAAŞ BORDROSU - " . $ay_isimleri[$ay] . " " . $yil;

// --- YARDIMCI FORMAT FONKSİYONU ---
function formatSaat($saat) {
    if ($saat === null || $saat === 0.0 || $saat === 0) return 0;
    // Eğer saat tam sayı ise ondalık kısmı gösterme (örn: 2.0 -> 2)
    if ($saat == floor($saat)) {
        return (int)$saat;
    }
    // Değilse, bir ondalık basamak göster (örn: 2.5)
    return number_format($saat, 1, '.', '');
}
// -------------------------------------

// --- HESAPLAMA MANTIKLARI ---

$gun_sayisi = cal_days_in_month(CAL_GREGORIAN, $ay, $yil);
$carpan_15 = 1.5; 
$carpan_20 = 2.0; 
$gunluk_saat_std = 9.0; // Sabit 9 saat varsayımı

$tatiller = $pdo->query("SELECT tarih FROM resmi_tatiller")->fetchAll(PDO::FETCH_COLUMN);

// Rol Bazlı Toplu Filtreleme Seçenekleri (maas-hesapla.php'den taşındı)
$rol_filtreleri = [
    'yonetici' => 'Tüm Yöneticiler',
    'mudur' => 'Tüm Müdürler',
    // Diğer roller...
];

// Personel Listesi SQL'i
// Sorguya TC No'yu da ekledik
$sql_per = "SELECT id, ad, soyad, aylik_net_maas, tc_no FROM kullanicilar WHERE durum=1 AND rol != 'root'"; // root hariç
$tek_personel_bilgi = null; // TC no bilgisini tutmak için

if ($personel_filtre_id != 'tumu') {
    if (is_numeric($personel_filtre_id)) {
        $sql_per .= " AND id = " . (int)$personel_filtre_id;
    } elseif (isset($rol_filtreleri[$personel_filtre_id])) {
        $sql_per .= " AND rol = " . $pdo->quote($personel_filtre_id);
    }
}
$sql_per .= " ORDER BY ad ASC";
$personeller = $pdo->query($sql_per)->fetchAll();

// Raporlanacak veriyi tutacak dizi
$rapor_verileri = [];

// --- PUANTAJ DETAYI HAZIRLIĞI (Sadece tek kişi seçiliyse) ---
$puantaj_html = '';
$gun_kisa = ['Mon'=>'Pzt', 'Tue'=>'Sal', 'Wed'=>'Çar', 'Thu'=>'Per', 'Fri'=>'Cum', 'Sat'=>'Cts', 'Sun'=>'Pzr'];
$izin_turleri_map = ['yillik'=>'Y.İZ', 'mazeret'=>'MAZ', 'hastalik'=>'RAP', 'evlilik'=>'EVL', 'babalik'=>'BAB', 'olum'=>'ÖLM', 'diger'=>'ÜCR.İZ', 'saatlik'=>'S.İZ'];

if (count($personeller) == 1 && is_numeric($personel_filtre_id)) {
    $per = $personeller[0];
    $tek_personel_bilgi = $per; // TC No bilgisini çekmek için
    
    // PUANTAJ BAŞLIK SATIRI
    $puantaj_baslik_html = '<tr><th style="width: 150px; position: sticky; left: 0;">PERSONEL / GÜN</th>';
    for($d=1; $d<=$gun_sayisi; $d++):
        $tarih_str = "$yil-$ay-" . sprintf('%02d', $d);
        $gun_ing = date('D', strtotime($tarih_str));
        $gun_tr = $gun_kisa[$gun_ing];
        $is_tatil_gunu = in_array($tarih_str, $tatiller) || $gun_ing == 'Sun';
        $renk = $is_tatil_gunu ? 'style="background-color: #fdd; color: #a00;"' : '';
        $puantaj_baslik_html .= "<th {$renk}>{$d}<br>{$gun_tr}</th>";
    endfor;
    $puantaj_baslik_html .= '</tr>';
    
    $normal_calisma_satiri = '<tr class="normal-calisma-satiri" style="font-weight: bold;"><td>NM / İZ</td>';
    $fazla_mesai_satiri = '<tr><td style="font-weight: bold;">FM</td>';
    
    // VERİ SATIRLARI
    for($d=1; $d<=$gun_sayisi; $d++) {
        $g_tarih = "$yil-$ay-" . sprintf('%02d', $d);
        $haftanin_gunu = date('N', strtotime($g_tarih)); 
        $is_tatil = in_array($g_tarih, $tatiller);
        $is_haftasonu = ($haftanin_gunu >= 6);
        $is_tatil_gunu = $is_tatil || $is_haftasonu;

        $nm_hucre_content = '';
        $fm_hucre_content = '';
        $nm_hucre_style = '';
        $net_kesinti_saati = 0;
        
        // --- 1. İzinleri Kontrol Et ---
        $izin = $pdo->query("SELECT izin_turu, saatlik_sure, baslangic_tarihi, bitis_tarihi FROM izin_talepleri 
                             WHERE calisan_id={$per['id']} AND durum='onaylandi' AND '$g_tarih' BETWEEN DATE(baslangic_tarihi) AND DATE(bitis_tarihi)")->fetch();
        
        // --- 2. Mesaileri Kontrol Et ---
        $mesai = $pdo->query("SELECT SUM(toplam_saat) FROM mesai_hareketleri 
                              WHERE calisan_id={$per['id']} AND durum='onaylandi' AND tarih='$g_tarih' 
                              AND mesai_turu IN ('fazla_mesai', 'hafta_tatili', 'resmi_tatil_mesaisi')")->fetchColumn() ?: 0;

        // --- İZİN / NORMAL SAAT KONTROLÜ ---
        if ($izin) {
            $tur_kisaltma = $izin_turleri_map[$izin['izin_turu']] ?? 'İZ';
            
            if (in_array($izin['izin_turu'], ['saatlik', 'diger'])) {
                 // Kesintili İzin Hesabı (Maaş Hesaplama mantığı ile uyumlu)
                 if ($izin['izin_turu'] == 'diger') {
                    $net_kesinti_saati = 9.0; 
                 } elseif ($izin['izin_turu'] == 'saatlik') {
                    $bas_saat_str = date('H:i', strtotime($izin['baslangic_tarihi']));
                    $bit_saat_str = date('H:i', strtotime($izin['bitis_tarihi']));
                    
                    if ($haftanin_gunu <= 5 && $bas_saat_str === '08:00' && $bit_saat_str === '12:00') {
                        $net_kesinti_saati = 4.0;
                    } elseif ($haftanin_gunu <= 5 && $bas_saat_str === '13:00' && $bit_saat_str === '18:00') {
                        $net_kesinti_saati = 5.0;
                    } else {
                        $net_kesinti_saati = (float)$izin['saatlik_sure'];
                    }
                 }
                 
                 // Hücre İçeriği: Kesinti Gösterimi
                 $nm_hucre_content = "<span style='color: red;'>- " . formatSaat($net_kesinti_saati) . "</span>";
                 $nm_hucre_style = 'style="background-color: #fce4e4;"'; // Kırmızımsı arka plan
                 
            } else {
                // Tam Gün Ücretli İzin
                $nm_hucre_content = $tur_kisaltma;
                $nm_hucre_style = 'style="background-color: #e3f2fd;"'; // Mavimsi arka plan
            }
        } elseif (!$is_tatil_gunu) {
             // Hafta içi ve izinsiz: Tam Çalışma (Tik işareti)
             $nm_hucre_content = '<span style="color: green; font-size: 1.2em;">&#x2713;</span>'; // Unicode tik işareti
             $nm_hucre_style = 'style="background-color: #e6ffe6;"'; // Açık yeşil arka plan
        } else {
            // Tatil veya Hafta Sonu: T işareti (Tatil)
             $nm_hucre_content = 'T';
             $nm_hucre_style = 'style="background-color: #f7f7f7;"'; // Açık gri arka plan
        }

        // --- FAZLA MESAİ KONTROLÜ ---
        if ($mesai > 0) {
             $fm_hucre_content = "<span style='color: green;'>+ " . formatSaat($mesai) . "</span>";
        } else {
             $fm_hucre_content = '-';
        }
        
        $normal_calisma_satiri .= "<td {$nm_hucre_style}>{$nm_hucre_content}</td>";
        $fazla_mesai_satiri .= "<td>{$fm_hucre_content}</td>";
    }
    $normal_calisma_satiri .= '</tr>';
    $fazla_mesai_satiri .= '</tr>';
    
    // Detaylı Puantaj HTML'i oluştur
    $puantaj_html = '
        <h2 style="font-size: 14px; margin-top: 30px; border-bottom: 1px solid #ccc; padding-bottom: 5px;">
            Aylık Puantaj Detayı
        </h2>
        <table style="font-size: 10px; table-layout: fixed;">
            <thead>
                ' . $puantaj_baslik_html . '
            </thead>
            <tbody>
                ' . $normal_calisma_satiri . '
                ' . $fazla_mesai_satiri . '
            </tbody>
        </table>
        <p style="font-size: 9px; margin-top: 5px;">
            Açıklamalar: NM/İZ: Normal Çalışma/İzin Durumu | FM: Onaylı Fazla Mesai Saati. | <span style="color: red;">- X</span>: Kesinti Saati | <span style="color: green;">&#x2713;</span>: Tam Çalışma (9s) | T: Tatil/Hafta Sonu.
        </p>
    ';
}
// --- PUANTAJ DETAYI HAZIRLIĞI SONU ---


foreach($personeller as $per) {
    // ... Finansal Hesaplamalar (Aynı kalır) ...
    $aylik_net_maas = (float)$per['aylik_net_maas'];
    
    if ($aylik_net_maas <= 0) continue; 
    
    $saatlik_ucret = $aylik_net_maas / 225;
    $kazanc_15_saat = 0; 
    $kazanc_20_saat = 0; 
    $kesinti_saat = 0; 

    // --- AVANS ÇEKİMİ ---
    $stmt_avans = $pdo->prepare("SELECT SUM(avans_miktari) FROM avans_hareketleri WHERE calisan_id = ? AND islem_tarihi BETWEEN ? AND ? AND durum = 'onaylandi'");
    $stmt_avans->execute([$per['id'], date('Y-m-01', strtotime("$yil-$ay-01")), date('Y-m-t', strtotime("$yil-$ay-01"))]);
    $aylik_avans_tutar = $stmt_avans->fetchColumn() ?: 0.00;
    // ---------------------

    // GÜNLÜK DÖNGÜ (Fazla mesai ve izin kesintilerini toplama)
    for($d=1; $d<=$gun_sayisi; $d++) {
        $tarih = "$yil-$ay-" . sprintf('%02d', $d);
        $gun_no = date('N', strtotime($tarih)); 
        $is_tatil = in_array($tarih, $tatiller);
        
        $izin = $pdo->query("SELECT izin_turu, saatlik_sure, baslangic_tarihi, bitis_tarihi FROM izin_talepleri 
                             WHERE calisan_id={$per['id']} AND durum='onaylandi' 
                             AND '$tarih' BETWEEN DATE(baslangic_tarihi) AND DATE(bitis_tarihi)")->fetch();

        if ($izin) {
            if ($izin['izin_turu'] == 'diger') {
                $kesinti_saat += 9; 
            } elseif ($izin['izin_turu'] == 'saatlik') {
                $izin_sure = (float)$izin['saatlik_sure'];
                $bas_saat_str = date('H:i', strtotime($izin['baslangic_tarihi']));
                $bit_saat_str = date('H:i', strtotime($izin['bitis_tarihi']));
                
                if ($gun_no <= 5 && $bas_saat_str === '08:00' && $bit_saat_str === '12:00') {
                    $kesinti_saat += 4.0;
                } elseif ($gun_no <= 5 && $bas_saat_str === '13:00' && $bit_saat_str === '18:00') {
                    $kesinti_saat += 5.0;
                } else {
                    $kesinti_saat += $izin_sure;
                }
            }
        }

        $mesai = $pdo->query("SELECT SUM(toplam_saat) FROM mesai_hareketleri 
                              WHERE calisan_id={$per['id']} AND durum='onaylandi' 
                              AND tarih='$tarih' 
                              AND mesai_turu IN ('fazla_mesai', 'hafta_tatili', 'resmi_tatil_mesaisi')")->fetchColumn() ?: 0;
        
        if ($mesai > 0) {
            $gun_no = date('N', strtotime($tarih)); 
            $is_pazar = ($gun_no == 7);
            if ($is_pazar || $is_tatil) {
                $kazanc_20_saat += $mesai;
            } else {
                $kazanc_15_saat += $mesai;
            }
        }
    }

    // Nihai Hesaplama
    $tutar_15 = $kazanc_15_saat * ($saatlik_ucret * $carpan_15);
    $tutar_20 = $kazanc_20_saat * ($saatlik_ucret * $carpan_20);
    $toplam_ek = $tutar_15 + $tutar_20;
    $tutar_izin_kesinti = $kesinti_saat * $saatlik_ucret;
    
    $toplam_kesinti_tutar = $tutar_izin_kesinti + $aylik_avans_tutar;
    
    $toplam_hakedis = $aylik_net_maas + $toplam_ek - $toplam_kesinti_tutar;
    
    $rapor_verileri[] = [
        'ad_soyad' => $per['ad'].' '.$per['soyad'],
        'net_maas' => number_format($aylik_net_maas, 2, '.', ''),
        'saat_15' => formatSaat($kazanc_15_saat),
        'saat_20' => formatSaat($kazanc_20_saat),
        'tutar_ek' => number_format($toplam_ek, 2, '.', ''),
        'saat_izin_kesinti' => formatSaat($kesinti_saat),
        'tutar_avans' => number_format($aylik_avans_tutar, 2, '.', ''),
        'tutar_toplam_kesinti' => number_format($tutar_izin_kesinti + $aylik_avans_tutar, 2, '.', ''),
        'toplam_hakedis' => number_format($toplam_hakedis, 2, '.', '')
    ];
}

// --- RAPOR ÇIKTI BAŞLIKLARI (Excel/PDF) ---
if ($format == 'excel') {
    header("Content-Type: application/vnd.ms-excel; charset=utf-8");
    header("Content-Disposition: attachment; filename=Maas_Bordrosu_{$yil}_{$ay}.xls");
    header("Pragma: no-cache");
    header("Expires: 0");
    echo "\xEF\xBB\xBF"; // BOM
} elseif ($format == 'pdf') {
    // Print/PDF çıktısı için özel CSS eklenecek
}

?>
<!DOCTYPE html>
<html lang="tr">
<head>
    <meta charset="UTF-8">
    <title>Ramsa Makine Sanayii Personel Yönetim Bilgi Sistemi - Bordro</title>
    <style>
        body { font-family: Arial, sans-serif; font-size: 11px; margin: 0; padding: 20px; }
        
        /* RAPOR ANTEPİ VE LOGO */
        .rapor-header { 
            display: flex; 
            justify-content: space-between; 
            align-items: center; 
            border-bottom: 3px solid #333; 
            padding-bottom: 10px; 
            margin-bottom: 20px;
        }
        .rapor-header img { max-height: 50px; }
        .rapor-header h1 { 
            font-size: 16px; 
            font-weight: bold; 
            margin: 0; 
            color: #333;
        }
        .rapor-header p { 
            font-size: 10px; 
            margin: 0; 
            color: #666;
        }

        /* TABLO STİLİ */
        table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
        th, td { border: 1px solid #000; padding: 5px; text-align: center; }
        th { background-color: #ddd; font-weight: bold; }
        .text-start { text-align: left !important; }
        .bg-success-light { background-color: #d1e7dd; }
        
        /* İmza Alanı Stilleri */
        .imza-blogu { display: flex; justify-content: space-around; margin-top: 50px; page-break-inside: avoid; }
        .imza-kutu { width: 25%; text-align: center; padding: 10px; }
        .imza-baslik { font-weight: bold; border-top: 1px solid #000; padding-top: 5px; margin-top: 40px; font-size: 11px; }

        /* PUANTAJ DETAY TABLOSU ÖZEL STİLLER */
        .puantaj-detay table { table-layout: fixed; width: 100%; }
        .puantaj-detay th, .puantaj-detay td { padding: 3px; }
        .puantaj-detay .normal-calisma-satiri td { font-size: 9px; }
        .puantaj-detay .tik-isareti { font-family: Arial, "DejaVu Sans", sans-serif; font-weight: bold; font-size: 1.2em; color: green; }


        /* PDF/PRINT ÖZEL STİLLER */
        @media print {
            body { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
            .no-print { display: none; }
            .rapor-header { border-bottom-color: #000; }
            th { background-color: #eee !important; }
            .bg-success-light { background-color: #d1e7dd !important; }
            .imza-blogu { margin-top: 80px; }
            .imza-baslik { border-top-color: #000 !important; }
            /* Excel için tek sayfaya sığdırma (Sadece CSS'te yatay ayar ile desteklenir) */
            @page { 
                size: landscape; 
                margin: 15mm; 
                /* Aşağıdaki satırlar URL'yi gizler */
                @bottom-left { content: ""; }
                @bottom-right { content: ""; }
                @top-left { content: ""; }
                @top-right { content: ""; }
            } 
        }
    </style>
</head>
<body>

    <?php if($format == 'pdf'): ?>
        <div class="no-print" style="margin-bottom: 20px;">
            <button onclick="window.print()" style="padding: 10px 20px; font-weight: bold; cursor: pointer;">🖨️ YAZDIR / PDF OLUŞTUR</button>
        </div>
    <?php endif; ?>

    <div class="rapor-header">
        <img src="../assets/img/logo.png" alt="Şirket Logosu">
        <div class="text-center">
            <h1><?php echo $baslik; ?></h1>
            <p>Rapor Tarihi: <?php echo $rapor_tarihi_saati; ?></p>
        </div>
        <div style="width: 50px;"></div>
    </div>
    
    <?php if ($tek_personel_bilgi): ?>
        <table style="width: 50%; margin-bottom: 10px; font-size: 10px; float: left;">
            <tr>
                <td class="text-start" style="width: 30%; background-color: #eee; font-weight: bold;">Personel Adı Soyadı</td>
                <td class="text-start"><?php echo $tek_personel_bilgi['ad'] . ' ' . $tek_personel_bilgi['soyad']; ?></td>
            </tr>
            <tr>
                 <td class="text-start" style="width: 30%; background-color: #eee; font-weight: bold;">TC Kimlik No</td>
                <td class="text-start"><?php echo $tek_personel_bilgi['tc_no']; ?></td>
            </tr>
        </table>
        <div style="clear: both;"></div>
    <?php endif; ?>

    <table>
        <thead>
            <tr>
                <th rowspan="2" class="text-start">PERSONEL</th>
                <th rowspan="2">NET MAAŞ</th>
                <th colspan="3">EK KAZANÇLAR</th>
                <th colspan="3">KESİNTİLER</th>
                <th rowspan="2" class="bg-success-light">TOPLAM HAKEDİŞ</th>
            </tr>
            <tr>
                <th>FM (1.5x) Saat</th>
                <th>HT/RT (2.0x) Saat</th>
                <th>Tutar</th>
                <th>İzin Kesinti Saat</th>
                <th>Avans (Tutar)</th>
                <th>Toplam Tutar</th>
            </tr>
        </thead>
        <tbody>
            <?php foreach($rapor_verileri as $veri): ?>
            <tr>
                <td class="text-start"><?php echo $veri['ad_soyad']; ?></td>
                <td><?php echo number_format($veri['net_maas'], 2); ?> ₺</td>
                <td><?php echo $veri['saat_15']; ?> s</td>
                <td><?php echo $veri['saat_20']; ?> s</td>
                <td style="color: green; font-weight: bold;">+<?php echo number_format($veri['tutar_ek'], 2); ?> ₺</td>
                <td><?php echo $veri['saat_izin_kesinti'] > 0 ? $veri['saat_izin_kesinti'].' s' : '-'; ?></td>
                <td style="color: red; font-weight: bold;">-<?php echo number_format($veri['tutar_avans'], 2); ?> ₺</td>
                <td style="color: red; font-weight: bold;">-<?php echo number_format($veri['tutar_toplam_kesinti'], 2); ?> ₺</td>
                <td class="bg-success-light" style="font-weight: bold; font-size: 13px;"><?php echo number_format($veri['toplam_hakedis'], 2); ?> ₺</td>
            </tr>
            <?php endforeach; ?>
        </tbody>
    </table>
    
    <?php if ($personel_filtre_id != 'tumu' && count($personeller) == 1): ?>
        <div class="puantaj-detay">
            <?php echo $puantaj_html; ?>
        </div>
    <?php endif; ?>

    <div class="imza-blogu">
        <div class="imza-kutu">
            <div class="imza-baslik">PERSONEL (Bordro Sahibi)</div>
        </div>
        <div class="imza-kutu">
            <div class="imza-baslik">MUHASEBE YETKİLİSİ</div>
        </div>
        <div class="imza-kutu">
            <div class="imza-baslik">YÖNETİCİ ONAYI</div>
        </div>
    </div>
    
    <?php if($format == 'pdf'): ?>
    <script>
        // PDF/Print için otomatik tetikleme
        window.onload = function() { setTimeout(function() { window.print(); }, 500); }
    </script>
    <?php endif; ?>

</body>
</html>