PYBS (Personel Yönetim Bilgi Sistemi)
<?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;">✓</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;">✓</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>
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