setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } catch (PDOException $e) { die("Błąd połączenia z bazą: " . $e->getMessage()); } define('ADMIN_SUBUNIT', 'Biuro - Stary Sącz'); if (isset($_GET['logout'])) { unset($_SESSION['grafik_emp_number'], $_SESSION['grafik_subunit_id'], $_SESSION['grafik_is_admin'], $_SESSION['grafik_emp_name']); header('Location: ' . strtok($_SERVER['REQUEST_URI'], '?')); exit; } if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'login_pin') { header('Content-Type: application/json; charset=utf-8'); $pin = trim($_POST['pin'] ?? ''); if ($pin === '') { echo json_encode(['ok' => false, 'msg' => 'Wprowadź PIN.']); exit; } $stmt = $pdo->prepare(" SELECT e.emp_number, e.emp_firstname, e.emp_lastname, e.work_station, s.name AS subunit_name FROM hs_hr_employee e LEFT JOIN ohrm_subunit s ON s.id = e.work_station WHERE e.employee_id = ? AND e.termination_id IS NULL LIMIT 1"); $stmt->execute([$pin]); $emp = $stmt->fetch(PDO::FETCH_ASSOC); if (!$emp) { echo json_encode(['ok' => false, 'msg' => 'Nieprawidłowy PIN.']); exit; } $_SESSION['grafik_emp_number'] = $emp['emp_number']; $_SESSION['grafik_subunit_id'] = $emp['work_station']; $_SESSION['grafik_subunit_name']= $emp['subunit_name']; $_SESSION['grafik_is_admin'] = ($emp['subunit_name'] === ADMIN_SUBUNIT); $_SESSION['grafik_emp_name'] = $emp['emp_lastname'] . ' ' . $emp['emp_firstname']; echo json_encode(['ok' => true, 'is_admin' => $_SESSION['grafik_is_admin']]); exit; } $auth_logged_in = isset($_SESSION['grafik_emp_number']); $auth_is_admin = $auth_logged_in && !empty($_SESSION['grafik_is_admin']); $auth_subunit_id = $_SESSION['grafik_subunit_id'] ?? null; $auth_subunit_name = $_SESSION['grafik_subunit_name'] ?? ''; $auth_emp_name = $_SESSION['grafik_emp_name'] ?? ''; $requested_subunit = (int)($_GET['subunit_id'] ?? 0); $access_denied = false; if ($auth_logged_in && $requested_subunit > 0 && !$auth_is_admin) if ($requested_subunit != $auth_subunit_id) $access_denied = true; if (isset($_GET['action']) && $_GET['action'] === 'autocomplete_emp') { header('Content-Type: application/json; charset=utf-8'); $term = '%' . ($_GET['term'] ?? '') . '%'; $stmt = $pdo->prepare(" SELECT e.emp_number, e.emp_firstname, e.emp_lastname, s.name AS subunit_name FROM hs_hr_employee e LEFT JOIN ohrm_subunit s ON s.id = e.work_station WHERE e.termination_id IS NULL AND (e.emp_lastname LIKE ? OR e.emp_firstname LIKE ?) ORDER BY e.emp_lastname, e.emp_firstname LIMIT 20"); $stmt->execute([$term, $term]); $wyniki = []; foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) $wyniki[] = ['value'=>$row['emp_lastname'].' '.$row['emp_firstname'], 'label'=>$row['emp_lastname'].' '.$row['emp_firstname'].($row['subunit_name']?' ('.$row['subunit_name'].')':''), 'id'=>$row['emp_number'], 'subunit_name'=>$row['subunit_name']??'']; echo json_encode($wyniki); exit; } if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) { header('Content-Type: application/json; charset=utf-8'); $action = $_POST['action']; if ($action === 'save_shift') { $id = (int)($_POST['id'] ?? 0); $emp_number = (int)($_POST['emp_number'] ?? 0); $subunit_id = (int)($_POST['subunit_id'] ?? 0); $shift_date = $_POST['shift_date'] ?? ''; $time_from = $_POST['time_from'] ?? ''; $time_to = $_POST['time_to'] ?? ''; $role_name = isset($_POST['role_name']) && $_POST['role_name'] !== '' ? $_POST['role_name'] : null; $is_sub = (int)($_POST['is_substitute'] ?? 0); $note = isset($_POST['note']) && $_POST['note'] !== '' ? $_POST['note'] : null; if (!$emp_number || !$subunit_id || !$shift_date || !$time_from || !$time_to) { echo json_encode(['ok'=>false,'msg'=>'Brakuje wymaganych pól']); exit; } try { if ($id > 0) { $stmt = $pdo->prepare("UPDATE ls_schedule_shift SET emp_number=?,subunit_id=?,shift_date=?,time_from=?,time_to=?,role_name=?,is_substitute=?,note=? WHERE id=?"); $stmt->execute([$emp_number,$subunit_id,$shift_date,$time_from,$time_to,$role_name,$is_sub,$note,$id]); } else { $stmt = $pdo->prepare("INSERT INTO ls_schedule_shift (emp_number,subunit_id,shift_date,time_from,time_to,role_name,is_substitute,note) VALUES (?,?,?,?,?,?,?,?)"); $stmt->execute([$emp_number,$subunit_id,$shift_date,$time_from,$time_to,$role_name,$is_sub,$note]); $id = (int)$pdo->lastInsertId(); } echo json_encode(['ok'=>true,'id'=>$id]); } catch (PDOException $e) { echo json_encode(['ok'=>false,'msg'=>$e->getMessage()]); } exit; } if ($action === 'delete_shift') { $id = (int)($_POST['id'] ?? 0); try { $pdo->prepare("DELETE FROM ls_schedule_shift WHERE id=?")->execute([$id]); echo json_encode(['ok'=>true]); } catch (PDOException $e) { echo json_encode(['ok'=>false,'msg'=>$e->getMessage()]); } exit; } if ($action === 'copy_week') { $subunit_id = (int)($_POST['subunit_id'] ?? 0); $from_week = $_POST['from_week'] ?? ''; $to_week = $_POST['to_week'] ?? ''; $overwrite = (int)($_POST['overwrite'] ?? 0); try { $from_end = date('Y-m-d', strtotime($from_week . ' +6 days')); $to_end = date('Y-m-d', strtotime($to_week . ' +6 days')); $diff_days = (strtotime($to_week) - strtotime($from_week)) / 86400; if ($overwrite) $pdo->prepare("DELETE FROM ls_schedule_shift WHERE subunit_id=? AND shift_date BETWEEN ? AND ?")->execute([$subunit_id,$to_week,$to_end]); $stmt = $pdo->prepare("SELECT * FROM ls_schedule_shift WHERE subunit_id=? AND shift_date BETWEEN ? AND ?"); $stmt->execute([$subunit_id,$from_week,$from_end]); $source = $stmt->fetchAll(PDO::FETCH_ASSOC); $ins = $pdo->prepare("INSERT IGNORE INTO ls_schedule_shift (emp_number,subunit_id,shift_date,time_from,time_to,role_name,is_substitute,note) VALUES (?,?,?,?,?,?,?,?)"); $count = 0; foreach ($source as $row) { $new_date = date('Y-m-d', strtotime($row['shift_date'] . " +{$diff_days} days")); $ins->execute([$row['emp_number'],$row['subunit_id'],$new_date,$row['time_from'],$row['time_to'],$row['role_name'],$row['is_substitute'],$row['note']]); $count++; } echo json_encode(['ok'=>true,'copied'=>$count]); } catch (PDOException $e) { echo json_encode(['ok'=>false,'msg'=>$e->getMessage()]); } exit; } echo json_encode(['ok'=>false,'msg'=>'Nieznana akcja']); exit; } $stmt = $pdo->query("SELECT id, name FROM ohrm_subunit ORDER BY lft, name"); $podjednostki = $stmt->fetchAll(PDO::FETCH_ASSOC); $subunit_id = (int)($_GET['subunit_id'] ?? 0); $week_start = $_GET['week_start'] ?? ''; if (!$week_start) { $dow = (int)date('N'); $week_start = date('Y-m-d', strtotime('-' . ($dow - 1) . ' days')); } $week_end = date('Y-m-d', strtotime($week_start . ' +6 days')); $prev_week = date('Y-m-d', strtotime($week_start . ' -7 days')); $next_week = date('Y-m-d', strtotime($week_start . ' +7 days')); $view = $_GET['view'] ?? 'week'; $month_param = $_GET['month_start'] ?? date('Y-m-01'); $month_start = date('Y-m-01', strtotime($month_param)); $month_end = date('Y-m-t', strtotime($month_start)); $prev_month = date('Y-m-01', strtotime($month_start . ' -1 month')); $next_month = date('Y-m-01', strtotime($month_start . ' +1 month')); $month_days = []; $d = new DateTime($month_start); $last = new DateTime($month_end); while ($d <= $last) { $month_days[] = $d->format('Y-m-d'); $d->modify('+1 day'); } $month_label = ['','Styczen','Luty','Marzec','Kwiecien','Maj','Czerwiec', 'Lipiec','Sierpien','Wrzesien','Pazdziernik','Listopad','Grudzien'][(int)date('n',strtotime($month_start))] . ' ' . date('Y', strtotime($month_start)); $month_label_pl = ['','Styczeń','Luty','Marzec','Kwiecień','Maj','Czerwiec', 'Lipiec','Sierpień','Wrzesień','Październik','Listopad','Grudzień'][(int)date('n',strtotime($month_start))] . ' ' . date('Y', strtotime($month_start)); $pracownicy = []; $shifts = []; $urlopy = []; $roles = []; $month_shifts = []; $month_leaves = []; $ms_idx = []; $ml_idx = []; $shifts_ext = []; $shifts_ext_idx = []; // zmiany pracowników w innych jednostkach $month_shifts_ext = []; $ms_ext_idx = []; // j.w. dla widoku miesięcznego if ($subunit_id > 0) { $stmt = $pdo->prepare(" SELECT e.emp_number, e.emp_firstname, e.emp_lastname, COALESCE(NULLIF(e.emp_other_id,''), '8') AS daily_norm FROM hs_hr_employee e WHERE e.work_station = ? AND e.termination_id IS NULL ORDER BY e.emp_lastname, e.emp_firstname"); $stmt->execute([$subunit_id]); $pracownicy = $stmt->fetchAll(PDO::FETCH_ASSOC); $stmt = $pdo->prepare(" SELECT s.id, s.emp_number, s.subunit_id, s.shift_date, TIME_FORMAT(s.time_from,'%H:%i') AS time_from, TIME_FORMAT(s.time_to, '%H:%i') AS time_to, s.role_name, s.is_substitute, s.note, e.emp_firstname, e.emp_lastname, COALESCE(NULLIF(e.emp_other_id,''), '8') AS daily_norm, r.color FROM ls_schedule_shift s JOIN hs_hr_employee e ON e.emp_number = s.emp_number LEFT JOIN ls_schedule_role r ON r.role_name = s.role_name AND (r.subunit_id = s.subunit_id OR r.subunit_id IS NULL) WHERE s.subunit_id = ? AND s.shift_date BETWEEN ? AND ? ORDER BY e.emp_lastname, e.emp_firstname, s.shift_date, s.time_from"); $stmt->execute([$subunit_id, $week_start, $week_end]); $shifts = $stmt->fetchAll(PDO::FETCH_ASSOC); foreach ($shifts as &$s) { $f = strtotime($s['shift_date'].' '.$s['time_from']); $t = strtotime($s['shift_date'].' '.$s['time_to']); if ($t < $f) $t += 86400; $s['minutes'] = (int)(($t - $f) / 60); } unset($s); $stmt = $pdo->prepare(" SELECT l.emp_number, DATE_FORMAT(l.date,'%Y-%m-%d') AS ldate, l.status, lt.name AS leave_type FROM ohrm_leave l JOIN hs_hr_employee e ON e.emp_number = l.emp_number JOIN ohrm_leave_type lt ON lt.id = l.leave_type_id WHERE e.work_station = ? AND l.date BETWEEN ? AND ? AND l.status IN (2,3) ORDER BY l.date"); $stmt->execute([$subunit_id, $week_start, $week_end]); $urlopy = $stmt->fetchAll(PDO::FETCH_ASSOC); $stmt = $pdo->prepare("SELECT role_name, color FROM ls_schedule_role WHERE subunit_id IS NULL OR subunit_id=? ORDER BY sort_order, role_name"); $stmt->execute([$subunit_id]); $roles = $stmt->fetchAll(PDO::FETCH_ASSOC); // ── Zmiany pracowników tej jednostki w INNYCH podjednostkach (widok tygodniowy) ── $emp_ids = array_column($pracownicy, 'emp_number'); if ($emp_ids) { $ph = implode(',', array_fill(0, count($emp_ids), '?')); $params = array_merge($emp_ids, [$subunit_id, $week_start, $week_end]); $stmt = $pdo->prepare(" SELECT s.id, s.emp_number, s.shift_date, TIME_FORMAT(s.time_from,'%H:%i') AS time_from, TIME_FORMAT(s.time_to, '%H:%i') AS time_to, s.role_name, su.name AS ext_subunit_name FROM ls_schedule_shift s LEFT JOIN ohrm_subunit su ON su.id = s.subunit_id WHERE s.emp_number IN ($ph) AND s.subunit_id != ? AND s.shift_date BETWEEN ? AND ? ORDER BY s.shift_date, s.time_from"); $stmt->execute($params); $shifts_ext = $stmt->fetchAll(PDO::FETCH_ASSOC); } if ($view === 'month') { $stmt = $pdo->prepare(" SELECT s.id, s.emp_number, s.shift_date, TIME_FORMAT(s.time_from,'%H:%i') AS time_from, TIME_FORMAT(s.time_to, '%H:%i') AS time_to, s.role_name, s.is_substitute, r.color, ROUND(TIMESTAMPDIFF(MINUTE, CONCAT(s.shift_date,' ',s.time_from), CONCAT(s.shift_date,' ',s.time_to))/60,2) AS godziny, e.emp_firstname, e.emp_lastname, COALESCE(NULLIF(e.emp_other_id,''),'8') AS daily_norm FROM ls_schedule_shift s JOIN hs_hr_employee e ON e.emp_number = s.emp_number LEFT JOIN ls_schedule_role r ON r.role_name=s.role_name AND (r.subunit_id=s.subunit_id OR r.subunit_id IS NULL) WHERE s.subunit_id=? AND s.shift_date BETWEEN ? AND ? ORDER BY s.shift_date, s.time_from"); $stmt->execute([$subunit_id, $month_start, $month_end]); $month_shifts = $stmt->fetchAll(PDO::FETCH_ASSOC); $stmt = $pdo->prepare(" SELECT l.emp_number, DATE_FORMAT(l.date,'%Y-%m-%d') AS ldate, lt.name AS leave_type FROM ohrm_leave l JOIN hs_hr_employee e ON e.emp_number=l.emp_number JOIN ohrm_leave_type lt ON lt.id=l.leave_type_id WHERE e.work_station=? AND l.date BETWEEN ? AND ? AND l.status IN (2,3)"); $stmt->execute([$subunit_id, $month_start, $month_end]); $month_leaves = $stmt->fetchAll(PDO::FETCH_ASSOC); $ms_idx = []; foreach ($month_shifts as $s) $ms_idx[$s['emp_number']][$s['shift_date']][] = $s; $ml_idx = []; foreach ($month_leaves as $l) $ml_idx[$l['emp_number']][$l['ldate']][] = $l; // ── Zmiany pracowników tej jednostki w INNYCH podjednostkach (widok miesięczny) ── if ($emp_ids) { $ph_m = implode(',', array_fill(0, count($emp_ids), '?')); $params_m = array_merge($emp_ids, [$subunit_id, $month_start, $month_end]); $stmt = $pdo->prepare(" SELECT s.id, s.emp_number, s.shift_date, TIME_FORMAT(s.time_from,'%H:%i') AS time_from, TIME_FORMAT(s.time_to, '%H:%i') AS time_to, s.role_name, su.name AS ext_subunit_name FROM ls_schedule_shift s LEFT JOIN ohrm_subunit su ON su.id = s.subunit_id WHERE s.emp_number IN ($ph_m) AND s.subunit_id != ? AND s.shift_date BETWEEN ? AND ? ORDER BY s.shift_date, s.time_from"); $stmt->execute($params_m); $month_shifts_ext = $stmt->fetchAll(PDO::FETCH_ASSOC); } } } $wszyscy = $pdo->query(" SELECT e.emp_number, e.emp_firstname, e.emp_lastname, s.name AS subunit_name FROM hs_hr_employee e LEFT JOIN ohrm_subunit s ON s.id = e.work_station WHERE e.termination_id IS NULL ORDER BY e.emp_lastname, e.emp_firstname ")->fetchAll(PDO::FETCH_ASSOC); $dni_pl = ['Poniedziałek','Wtorek','Środa','Czwartek','Piątek','Sobota','Niedziela']; $today = date('Y-m-d'); $week_days = []; for ($i = 0; $i < 7; $i++) $week_days[] = date('Y-m-d', strtotime($week_start." +$i days")); $emp_map = []; foreach ($pracownicy as $p) $emp_map[$p['emp_number']] = $p + ['is_sub_only'=>false]; foreach ($shifts as $s) { if (!isset($emp_map[$s['emp_number']])) $emp_map[$s['emp_number']] = ['emp_number'=>$s['emp_number'],'emp_firstname'=>$s['emp_firstname'],'emp_lastname'=>$s['emp_lastname'],'daily_norm'=>$s['daily_norm'],'is_sub_only'=>true]; } foreach ($month_shifts as $s) { if (!isset($emp_map[$s['emp_number']])) $emp_map[$s['emp_number']] = ['emp_number'=>$s['emp_number'],'emp_firstname'=>$s['emp_firstname'],'emp_lastname'=>$s['emp_lastname'],'daily_norm'=>$s['daily_norm'],'is_sub_only'=>true]; } $add_sub = (int)($_GET['add_sub'] ?? 0); if ($add_sub > 0 && !isset($emp_map[$add_sub])) { $stmt = $pdo->prepare("SELECT emp_number, emp_firstname, emp_lastname, COALESCE(NULLIF(emp_other_id,''),'8') AS daily_norm FROM hs_hr_employee WHERE emp_number=?"); $stmt->execute([$add_sub]); $sub_emp = $stmt->fetch(PDO::FETCH_ASSOC); if ($sub_emp) $emp_map[$sub_emp['emp_number']] = $sub_emp + ['is_sub_only'=>true]; } uasort($emp_map, function($a,$b) { if ($a['is_sub_only'] !== $b['is_sub_only']) return $a['is_sub_only'] ? 1 : -1; return strcmp($a['emp_lastname'].$a['emp_firstname'], $b['emp_lastname'].$b['emp_firstname']); }); $emp_map = array_combine(array_column($emp_map, 'emp_number'), array_values($emp_map)); $shifts_idx = []; foreach ($shifts as $s) $shifts_idx[$s['emp_number']][$s['shift_date']][] = $s; $leaves_idx = []; foreach ($urlopy as $l) $leaves_idx[$l['emp_number']][$l['ldate']][] = $l; $role_colors = []; foreach ($roles as $r) $role_colors[$r['role_name']] = $r['color']; $shifts_ext_idx = []; foreach ($shifts_ext as $s) $shifts_ext_idx[$s['emp_number']][$s['shift_date']][] = $s; $ms_ext_idx = []; foreach ($month_shifts_ext as $s) $ms_ext_idx[$s['emp_number']][$s['shift_date']][] = $s; $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http'; $script_path = str_replace($_SERVER['DOCUMENT_ROOT'], '', __FILE__); $self = $protocol . '://' . $_SERVER['HTTP_HOST'] . $script_path; function fmtWeekLabel($s,$e){ $m=['','sty','lut','mar','kwi','maj','cze','lip','sie','wrz','paź','lis','gru']; return date('j',strtotime($s)).' '.$m[(int)date('n',strtotime($s))].' – '.date('j',strtotime($e)).' '.$m[(int)date('n',strtotime($e))].' '.date('Y',strtotime($e)); } function h2rgba($hex,$a){ if(!$hex||strlen($hex)<6) return "rgba(255,118,0,$a)"; $hex=ltrim($hex,'#'); return "rgba(".hexdec(substr($hex,0,2)).",".hexdec(substr($hex,2,2)).",".hexdec(substr($hex,4,2)).",$a)"; } ?>
Wprowadź swój PIN pracownika, aby uzyskać dostęp.
Możesz przeglądać tylko grafik swojej podjednostki:
= htmlspecialchars($auth_subunit_name) ?>
| Pracownik | $day): $cls = 'th-day'.($i>=5?' th-weekend':'').($day===$today?' th-today':''); $mn = ['sty','lut','mar','kwi','maj','cze','lip','sie','wrz','paź','lis','gru'][(int)date('n',strtotime($day))-1]; ?>= $dni_pl[$i] ?> = date('j',strtotime($day)) ?> = $mn ?> |
Σ godz. |
|---|---|---|
|
= htmlspecialchars($emp['emp_lastname'].' '.$emp['emp_firstname']) ?>
↩ zastępstwo
|
$day):
$cls='td-day'.($i>=5?' weekend':'').($day===$today?' today':'');
?>
🏖 = htmlspecialchars($lv['leave_type']) ?>
= $s['time_from'] ?>–= $s['time_to'] ?>
= htmlspecialchars($s['role_name']) ?>
↩ Zastępstwo
= $s['time_from'] ?>–= $s['time_to'] ?>
= htmlspecialchars($s['role_name']) ?>
📍 = htmlspecialchars($s['ext_subunit_name'] ?? '') ?>
|
= $wmin>0 ? $wh.'h'.($wm>0?$wm.'m':'') : '–' ?>
0): ?> = $wlh ?>h= $wlm>0?$wlm.'m':'' ?> urlop
|
| – | ||
| SUMA DZIENNA | $day): $dm=0; foreach ($emp_map as $emp) if (!empty($shifts_idx[$emp['emp_number']][$day])) foreach ($shifts_idx[$emp['emp_number']][$day] as $s) $dm+=$s['minutes']; $gtot+=$dm; $dh=floor($dm/60); $dmm=$dm%60; ?>= $dm>0 ? ''.$dh.'h'.($dmm>0?$dmm.'m':'').'' : '–' ?> | = $gtot>0?$gh.'h'.($gm>0?$gm.'m':''):'–' ?> |
| Pracownik | = $dni_skr[$dow] ?> = (int)date('j',strtotime($day)) ?> |
Sh |
|---|---|---|
|
= htmlspecialchars($emp['emp_lastname'].' '.$emp['emp_firstname']) ?>
Norma: = $emp['daily_norm'] ?>h
0): ?>= $wh ?>h= $wm>0?$wm.'m':'' ?>
0): ?>= $mlh ?>h= $mlm>0?$mlm.'m':'' ?> urlop
|
🏖
= $s['time_from'] ?>
= $s['time_to'] ?>
= $s['time_from'] ?>
= $s['time_to'] ?> |
= $total_min>0 ? $wh.'h'.($wm>0?$wm.'m':'') : '–' ?>
0): ?> = $mlh ?>h= $mlm>0?$mlm.'m':'' ?> urlop
|
| SUMA | = $dm>0?''.$dh.'h':'-' ?> | = $gtot>0?$gh.'h'.($gm>0?$gm.'m':''):'–' ?> |
Zapisywanie…