File: /home/muratemr/theotto.tr/includes/functions.php
<?php
/**
* includes/functions.php
* Genel yardımcı fonksiyonlar
*/
declare(strict_types=1);
/**
* WhatsApp numarasını normalleştirir
* "0532 111 22 33" → "905321112233"
*/
function normalize_whatsapp_number(string $number): string
{
// Boşluk, parantez, +, - ve diğer gereksiz karakterleri temizle
$clean = preg_replace('/[\s\(\)\+\-]/', '', $number);
// Başındaki 0'ı kaldır
$clean = ltrim($clean, '0');
// 90 ile başlamıyorsa ekle
if (!str_starts_with($clean, '90')) {
$clean = '90' . $clean;
}
return $clean;
}
/**
* WhatsApp linki oluşturur
*/
function whatsapp_link(string $number, string $message = ''): string
{
$normalized = normalize_whatsapp_number($number);
if ($message !== '') {
return 'https://wa.me/' . $normalized . '?text=' . rawurlencode($message);
}
return 'https://wa.me/' . $normalized;
}
/**
* Güvenli HTML çıktısı
*/
function e(mixed $value): string
{
return htmlspecialchars((string)$value, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}
/**
* Tarihi Türkçe formatlar (2024-01-15 → 15.01.2024)
*/
function format_date(string $date): string
{
if (!$date) return '-';
return date('d.m.Y', strtotime($date));
}
/**
* Tarih + saati formatlar
*/
function format_datetime(string $dt): string
{
if (!$dt) return '-';
return date('d.m.Y H:i', strtotime($dt));
}
/**
* Saati formatlar (09:00:00 → 09:00)
*/
function format_time(string $time): string
{
if (!$time) return '-';
return substr($time, 0, 5);
}
/**
* Dakikayı saat:dakika formatına çevirir
*/
function minutes_to_hm(int $minutes): string
{
$h = intdiv($minutes, 60);
$m = $minutes % 60;
return sprintf('%02d:%02d', $h, $m);
}
/**
* JSON API cevabı döner ve çıkar
*/
function json_response(bool $success, string $message = '', array $data = []): never
{
header('Content-Type: application/json; charset=utf-8');
echo json_encode(array_merge(['success' => $success, 'message' => $message], $data));
exit;
}
/**
* Sayfalama verisi hesaplar
* @return array ['offset'=>int, 'limit'=>int, 'total_pages'=>int, 'current_page'=>int]
*/
function paginate(int $total, int $page = 1, int $per_page = 25): array
{
$page = max(1, $page);
$total_pages = (int)ceil($total / $per_page);
$page = min($page, max(1, $total_pages));
return [
'offset' => ($page - 1) * $per_page,
'limit' => $per_page,
'total_pages' => $total_pages,
'current_page'=> $page,
'total' => $total,
'per_page' => $per_page,
];
}
/**
* Rezervasyon durumuna göre Bootstrap badge sınıfı
*/
function reservation_status_badge(string $status): string
{
return match ($status) {
'bekliyor' => '<span class="badge bg-warning text-dark">Bekliyor</span>',
'onaylandi' => '<span class="badge bg-success">Onaylandı</span>',
'reddedildi' => '<span class="badge bg-danger">Reddedildi</span>',
'iptal' => '<span class="badge bg-secondary">İptal</span>',
'arsiv' => '<span class="badge bg-info text-dark">Arşiv</span>',
default => '<span class="badge bg-dark">' . e($status) . '</span>',
};
}
/**
* Devam durumuna göre badge
*/
function attendance_status_badge(string $status): string
{
return match ($status) {
'pending' => '<span class="badge bg-secondary">Bekliyor</span>',
'present' => '<span class="badge bg-success">Geldi</span>',
'absent' => '<span class="badge bg-danger">Gelmedi</span>',
'late' => '<span class="badge bg-warning text-dark">Geç Kaldı</span>',
'early_leave' => '<span class="badge bg-warning text-dark">Erken Çıktı</span>',
'incomplete' => '<span class="badge bg-orange text-dark">Eksik</span>',
default => '<span class="badge bg-dark">' . e($status) . '</span>',
};
}
/**
* İzin türü Türkçe adı
*/
function leave_type_label(string $type): string
{
return match ($type) {
'none' => '-',
'annual' => 'Yıllık İzin',
'sick' => 'Raporlu',
'unpaid' => 'Ücretsiz İzin',
'excuse' => 'Mazeret İzni',
default => $type,
};
}
/**
* Rezervasyon için WhatsApp onay mesajı
*/
function reservation_whatsapp_message(array $r, string $type = 'confirm'): string
{
$date = format_date($r['date']);
$time = format_time($r['time']);
return match ($type) {
'confirm' => "Sayın {$r['full_name']},\n\nRezervasyonunuz onaylanmıştır. ✅\n\nTarih: $date\nSaat: $time\nKişi: {$r['guest_count']}\nMasa No: " . ($r['table_no'] ?? '-') . "\n\nSizi bekliyoruz! 🌟",
'reject' => "Sayın {$r['full_name']},\n\nÜzgünüz, rezervasyon talebiniz onaylanamadı. ❌\n\nTarih: $date\nSaat: $time\n\nBaşka bir tarih için rezervasyon yapabilirsiniz.",
default => '',
};
}
/**
* Günlük sipariş WhatsApp mesajı oluşturur
*/
function order_whatsapp_message(array $order, array $items, string $supplier_name): string
{
$date = format_date($order['order_date']);
$lines = ["Merhaba, aşağıdaki siparişi oluşturmak istiyoruz.\n"];
$lines[] = "Tarih: $date";
$lines[] = "Tedarikçi: $supplier_name\n";
$lines[] = "Sipariş Listesi:";
foreach ($items as $i => $item) {
$no = $i + 1;
$line = "$no. {$item['product_name']} - {$item['quantity']} {$item['unit']}";
if (!empty($item['approx_price'])) {
$line .= " (~{$item['approx_price']} ₺)";
}
$lines[] = $line;
}
if (!empty($order['general_note'])) {
$lines[] = "\nNot: {$order['general_note']}";
}
$lines[] = "\nTeşekkürler.";
return implode("\n", $lines);
}
/**
* İki zaman arasındaki dakika farkı (gece vardiyası desteği)
*/
function time_diff_minutes(string $start, string $end, bool $next_day = false): int
{
$base = new DateTime('2000-01-01 ' . $start);
$endDt = new DateTime('2000-01-01 ' . $end);
if ($next_day || $endDt <= $base) {
$endDt->modify('+1 day');
}
return (int)(($endDt->getTimestamp() - $base->getTimestamp()) / 60);
}
/**
* Devam kaydı istatistiklerini hesaplar
*/
function calculate_attendance(array $shift, array $attendance): array
{
$result = [
'late_minutes' => 0,
'early_leave_minutes' => 0,
'missing_minutes' => 0,
'status' => 'pending',
'auto_note' => '',
];
if (empty($attendance['actual_start_time'])) {
return $result;
}
$is_next_day = (bool)($shift['is_next_day'] ?? false);
// Geç kalma
if (!empty($shift['planned_start_time']) && $attendance['actual_start_time'] > $shift['planned_start_time']) {
$result['late_minutes'] = time_diff_minutes($shift['planned_start_time'], $attendance['actual_start_time']);
}
// Erken çıkış
if (!empty($shift['planned_end_time']) && !empty($attendance['actual_end_time'])) {
$plannedEnd = $shift['planned_end_time'];
$actualEnd = $attendance['actual_end_time'];
// Gece vardiyası hesabı
if ($is_next_day || $actualEnd < $shift['planned_start_time']) {
// planlanan bitiş ertesi gün
}
if ($actualEnd < $plannedEnd && !$is_next_day) {
$result['early_leave_minutes'] = time_diff_minutes($actualEnd, $plannedEnd);
}
}
// Toplam eksik
$result['missing_minutes'] = $result['late_minutes'] + $result['early_leave_minutes'];
// Durum belirleme
if (empty($attendance['actual_start_time'])) {
$result['status'] = 'absent';
} elseif ($result['late_minutes'] > 0 && $result['early_leave_minutes'] > 0) {
$result['status'] = 'incomplete';
} elseif ($result['late_minutes'] > 0) {
$result['status'] = 'late';
} elseif ($result['early_leave_minutes'] > 0) {
$result['status'] = 'early_leave';
} else {
$result['status'] = 'present';
}
return $result;
}
/**
* Site ayarını döner
*/
function get_setting(string $key, string $default = ''): string
{
static $settings = null;
if ($settings === null) {
try {
$rows = db_rows('SELECT `key`, `value` FROM site_settings');
$settings = array_column($rows, 'value', 'key');
} catch (\Throwable $e) {
return $default;
}
}
return $settings[$key] ?? $default;
}
/**
* Türkçe gün adları
*/
function day_names_tr(): array
{
return ['Pzt', 'Sal', 'Çar', 'Per', 'Cum', 'Cmt', 'Paz'];
}
/**
* Türkçe ay adları
*/
function month_names_tr(): array
{
return [
1=>'Ocak',2=>'Şubat',3=>'Mart',4=>'Nisan',5=>'Mayıs',6=>'Haziran',
7=>'Temmuz',8=>'Ağustos',9=>'Eylül',10=>'Ekim',11=>'Kasım',12=>'Aralık'
];
}
/**
* POST string değerini temizler
*/
function post_str(string $key, string $default = ''): string
{
return trim((string)($_POST[$key] ?? $default));
}
/**
* POST int değerini döner
*/
function post_int(string $key, int $default = 0): int
{
return (int)($_POST[$key] ?? $default);
}
/**
* GET int değerini döner
*/
function get_int(string $key, int $default = 0): int
{
return (int)($_GET[$key] ?? $default);
}
/**
* GET string değerini döner
*/
function get_str(string $key, string $default = ''): string
{
return trim((string)($_GET[$key] ?? $default));
}
/**
* Telefon numarasını standart forma dönüştürür (müşteri eşleştirme için)
* 905312440567, 05312440567, 5312440567 → 5312440567 (10 haneli TR formatı)
*/
function normalize_phone(string $number): string
{
// Sadece rakam bırak
$clean = preg_replace('/\D/', '', $number);
// Başındaki 90'ı kaldır (uluslararası TR kodu)
if (str_starts_with($clean, '90') && strlen($clean) === 12) {
$clean = substr($clean, 2);
}
// Başındaki tek 0'ı kaldır → 10 haneli format
if (str_starts_with($clean, '0') && strlen($clean) === 11) {
$clean = substr($clean, 1);
}
return $clean;
}