403Webshell
Server IP : 193.86.120.172  /  Your IP : 216.73.216.67
Web Server : Apache/2.4.63 (Unix)
System : Linux JServices 3.10.108 #86003 SMP Wed Oct 22 13:20:46 CST 2025 x86_64
User : kubec ( 1026)
PHP Version : 8.2.28
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /volume1/web/kadernictvidenisa_cz/includes/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /volume1/web/kadernictvidenisa_cz/includes/mailer.php
<?php
// ============================================
//  includes/mailer.php
//  Microsoft 365 – OAuth2 + SMTP AUTH XOAUTH2
//  Bez Composeru, čistě PHP streams
// ============================================

require_once __DIR__ . '/config.php';
require_once __DIR__ . '/db.php';

// -----------------------------------------------
//  OAuth2 – získání / obnova access tokenu
// -----------------------------------------------

function ms_get_access_token(): string {
    // Zkus načíst platný token z DB
    $stmt = db()->prepare(
        "SELECT access_token, expires_at FROM oauth_tokeny
         WHERE provider = 'microsoft' ORDER BY id DESC LIMIT 1"
    );
    $stmt->execute();
    $row = $stmt->fetch();

    if ($row && new DateTime() < new DateTime($row['expires_at'])) {
        return $row['access_token'];
    }

    // Token vypršel nebo neexistuje → obnov přes refresh_token
    if ($row) {
        $stmt2 = db()->prepare(
            "SELECT refresh_token FROM oauth_tokeny
             WHERE provider = 'microsoft' ORDER BY id DESC LIMIT 1"
        );
        $stmt2->execute();
        $r = $stmt2->fetch();
        if ($r) {
            return ms_refresh_token($r['refresh_token']);
        }
    }

    throw new RuntimeException(
        'OAuth2 token není k dispozici. Dokončete prvotní autorizaci na /admin/oauth-setup.php'
    );
}

function ms_refresh_token(string $refresh_token): string {
    $url  = 'https://login.microsoftonline.com/' . MS_TENANT_ID . '/oauth2/v2.0/token';
    $body = http_build_query([
        'client_id'     => MS_CLIENT_ID,
        'client_secret' => MS_CLIENT_SECRET,
        'grant_type'    => 'refresh_token',
        'refresh_token' => $refresh_token,
        'scope'         => 'https://outlook.office365.com/SMTP.Send offline_access',
    ]);

    $ctx = stream_context_create(['http' => [
        'method'  => 'POST',
        'header'  => "Content-Type: application/x-www-form-urlencoded\r\n",
        'content' => $body,
        'timeout' => 10,
    ]]);

    $resp = file_get_contents($url, false, $ctx);
    if ($resp === false) throw new RuntimeException('Nepodařilo se kontaktovat Microsoft OAuth2 server.');

    $data = json_decode($resp, true);
    if (!isset($data['access_token'])) {
        throw new RuntimeException('OAuth2 refresh selhal: ' . ($data['error_description'] ?? $resp));
    }

    $expires_at = date('Y-m-d H:i:s', time() + (int)$data['expires_in'] - 60);

    db()->prepare("
        UPDATE oauth_tokeny
        SET access_token = ?, refresh_token = ?, expires_at = ?
        WHERE provider = 'microsoft'
    ")->execute([$data['access_token'], $data['refresh_token'] ?? $refresh_token, $expires_at]);

    return $data['access_token'];
}

// -----------------------------------------------
//  SMTP odesílání s XOAUTH2
// -----------------------------------------------

function smtp_send(string $to, string $to_name, string $subject, string $html_body): bool {
    try {
        $access_token = ms_get_access_token();
    } catch (RuntimeException $e) {
        error_log('[Mailer] Token error: ' . $e->getMessage());
        return false;
    }

    $smtp_user = defined('MS_SMTP_USER') ? MS_SMTP_USER : MS_FROM_EMAIL;
    $xoauth2   = base64_encode("user=" . $smtp_user . "\x01auth=Bearer " . $access_token . "\x01\x01");

    $boundary = md5(uniqid('', true));
    $headers  = "MIME-Version: 1.0\r\n";
    $headers .= "Content-Type: multipart/alternative; boundary=\"{$boundary}\"\r\n";
    $headers .= "From: " . mime_encode(MS_FROM_NAME) . " <" . MS_FROM_EMAIL . ">\r\n";
    $headers .= "To: " . mime_encode($to_name) . " <{$to}>\r\n";
    $headers .= "Subject: " . mime_encode($subject) . "\r\n";
    $headers .= "X-Mailer: KadernictviMailer/2.0\r\n";

    $plain = html_entity_decode(
        strip_tags(str_replace('<br>', "\n", str_replace('<br/>', "\n", str_replace('<br />', "\n", $html_body)))),
        ENT_QUOTES, 'UTF-8'
    );

    $body  = "--{$boundary}\r\n";
    $body .= "Content-Type: text/plain; charset=utf-8\r\n";
    $body .= "Content-Transfer-Encoding: base64\r\n\r\n";
    $body .= chunk_split(base64_encode($plain)) . "\r\n";
    $body .= "--{$boundary}\r\n";
    $body .= "Content-Type: text/html; charset=utf-8\r\n";
    $body .= "Content-Transfer-Encoding: base64\r\n\r\n";
    $body .= chunk_split(base64_encode($html_body)) . "\r\n";
    $body .= "--{$boundary}--\r\n";

    $errno = 0; $errstr = '';
    $sock = fsockopen('smtp.office365.com', 587, $errno, $errstr, 15);
    if (!$sock) {
        error_log("[Mailer] fsockopen selhal: {$errstr}");
        return false;
    }

    $read = function() use ($sock): string {
        $resp = '';
        while ($line = fgets($sock, 512)) {
            $resp .= $line;
            if (isset($line[3]) && $line[3] === ' ') break;
        }
        return $resp;
    };
    $cmd = function(string $c) use ($sock, $read): string {
        fwrite($sock, $c . "\r\n");
        $r = $read();
        error_log('[Mailer] ' . substr($c, 0, 20) . ' => ' . trim(substr($r, 0, 80)));
        return $r;
    };

    $read(); // banner
    $cmd('EHLO ' . gethostname());
    $cmd('STARTTLS');
    stream_socket_enable_crypto($sock, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
    $cmd('EHLO ' . gethostname());

    // AUTH
    fwrite($sock, 'AUTH XOAUTH2 ' . $xoauth2 . "\r\n");
    $r = $read();
    error_log('[Mailer] AUTH => ' . trim(substr($r, 0, 80)));
    if (strpos($r, '235') === false) {
        error_log("[Mailer] AUTH selhal: {$r}");
        fclose($sock);
        return false;
    }

    $r = $cmd('MAIL FROM:<' . MS_FROM_EMAIL . '>');
    if (strpos($r, '250') === false) {
        error_log("[Mailer] MAIL FROM selhal: {$r}");
        fclose($sock);
        return false;
    }

    $r = $cmd('RCPT TO:<' . $to . '>');
    if (strpos($r, '250') === false) {
        error_log("[Mailer] RCPT TO selhal: {$r}");
        fclose($sock);
        return false;
    }

    $cmd('DATA');
    fwrite($sock, $headers . "\r\n" . $body . "\r\n.\r\n");
    $r = $read();
    error_log('[Mailer] DATA response: ' . trim($r));
    $cmd('QUIT');
    fclose($sock);

    $ok = strpos($r, '250') !== false;
    if (!$ok) error_log("[Mailer] Odesílání selhalo: {$r}");
    return $ok;
}


function mime_encode(string $text): string {
    return '=?UTF-8?B?' . base64_encode($text) . '?=';
}

// -----------------------------------------------
//  E-mailové šablony
// -----------------------------------------------

function email_potvrzeni(array $rez, string $sluzba_nazev): bool {
    $zmena_url   = BASE_URL . '/zmena-rezervace.php?token=' . urlencode($rez['token_zmena']);
    $zruseni_url = BASE_URL . '/zruseni-rezervace.php?token=' . urlencode($rez['token_zmena']);
    $ics_url     = BASE_URL . '/api/ics?token=' . urlencode($rez['token_zmena']);
    $datum_fmt   = datum_cs($rez['datum']);

    $html = email_layout("
        <h2 style='color:#6b21a8;margin:0 0 16px'>Vaše rezervace je přijata ✂️</h2>
        <p>Dobrý den, <strong>{$rez['jmeno']} {$rez['prijmeni']}</strong>,</p>
        <p>potvrzujeme přijetí vaší rezervace.<br><strong>Jakmile ji kadeřnice potvrdí, dostanete další e-mail.</strong></p>
        " . tabulka_rezervace($sluzba_nazev, $datum_fmt, $rez['cas_od'], $rez['cena'], $rez['poznamka'] ?? '', $rez['doplnky'] ?? [], isset($rez['cena_upravena']) ? (float)$rez['cena_upravena'] : null) . "
        <p>Potřebujete termín změnit nebo zrušit?</p>
        <p style='text-align:center;margin:24px 0'>
            <a href='{$zmena_url}'   style='background:#9333ea;color:#fff;padding:12px 24px;border-radius:24px;text-decoration:none;margin-right:8px'>Změnit termín</a>
            <a href='{$zruseni_url}' style='background:#f3e8ff;color:#6b21a8;padding:12px 24px;border-radius:24px;text-decoration:none;border:1px solid #e9d5ff'>Zrušit rezervaci</a>
        </p>
        <p style='text-align:center;margin-top:12px'>
            <a href='{$ics_url}' style='background:#f3e8ff;color:#6b21a8;padding:10px 20px;border-radius:24px;text-decoration:none;border:1px solid #e9d5ff;font-size:13px'>📅 Přidat do kalendáře</a>
        </p>
    ");
    return smtp_send($rez['email'], $rez['jmeno'] . ' ' . $rez['prijmeni'],
        'Přijetí rezervace – ' . salon_nazev(), $html);
}

function email_potvrzeni_adminem(array $rez, string $sluzba_nazev, bool $nova = false): bool {
    $datum_fmt = datum_cs($rez['datum']);
    $nadpis  = $nova ? 'Rezervace potvrzena ✅' : 'Rezervace potvrzena ✅';
    $zprava  = $nova
        ? 'vaše rezervace byla vytvořena a <strong>potvrzena</strong>. Těšíme se na vás!'
        : 'vaši rezervaci jsme potvrdili. Těšíme se na vás!';
    $zmena_url   = BASE_URL . '/zmena-rezervace.php?token=' . urlencode($rez['token_zmena']);
    $zruseni_url = BASE_URL . '/zruseni-rezervace.php?token=' . urlencode($rez['token_zmena']);
    $ics_url     = BASE_URL . '/api/ics?token=' . urlencode($rez['token_zmena']);
    $html = email_layout("
        <h2 style='color:#6b21a8;margin:0 0 16px'>{$nadpis}</h2>
        <p>Dobrý den, <strong>{$rez['jmeno']} {$rez['prijmeni']}</strong>,</p>
        <p>{$zprava}</p>
        " . tabulka_rezervace($sluzba_nazev, $datum_fmt, $rez['cas_od'], $rez['cena'], $rez['poznamka'] ?? '', $rez['doplnky'] ?? [], isset($rez['cena_upravena']) ? (float)$rez['cena_upravena'] : null) . "
        <p>Potřebujete termín změnit nebo zrušit?</p>
        <p style='text-align:center;margin:24px 0'>
            <a href='{$zmena_url}' style='background:#9333ea;color:#fff;padding:12px 24px;border-radius:24px;text-decoration:none;margin-right:8px'>Změnit termín</a>
            <a href='{$zruseni_url}' style='background:#f3e8ff;color:#6b21a8;padding:12px 24px;border-radius:24px;text-decoration:none;border:1px solid #e9d5ff'>Zrušit rezervaci</a>
        </p>
        <p style='text-align:center;margin-top:12px'>
            <a href='{$ics_url}' style='background:#f3e8ff;color:#6b21a8;padding:10px 20px;border-radius:24px;text-decoration:none;border:1px solid #e9d5ff;font-size:13px'>📅 Přidat do kalendáře</a>
        </p>
    ");
    return smtp_send($rez['email'], $rez['jmeno'] . ' ' . $rez['prijmeni'],
        'Rezervace potvrzena – ' . salon_nazev(), $html);
}

function email_zmena_ceny(array $rez, string $sluzba_nazev): bool {
    $zmena_url   = BASE_URL . '/zmena-rezervace.php?token=' . urlencode($rez['token_zmena']);
    $zruseni_url = BASE_URL . '/zruseni-rezervace.php?token=' . urlencode($rez['token_zmena']);
    $datum_fmt   = datum_cs($rez['datum']);
    $html = email_layout("
        <h2 style='color:#6b21a8;margin:0 0 16px'>Aktualizace ceny rezervace ✂️</h2>
        <p>Dobrý den, <strong>{$rez['jmeno']} {$rez['prijmeni']}</strong>,</p>
        <p>cena vaší rezervace byla upravena. Níže najdete aktuální přehled.</p>
        " . tabulka_rezervace($sluzba_nazev, $datum_fmt, $rez['cas_od'], $rez['cena'], $rez['poznamka'] ?? '', $rez['doplnky'] ?? [], isset($rez['cena_upravena']) ? (float)$rez['cena_upravena'] : null) . "
        <p>Potřebujete termín změnit nebo zrušit?</p>
        <p style='text-align:center;margin:24px 0'>
            <a href='{$zmena_url}' style='background:#9333ea;color:#fff;padding:12px 24px;border-radius:24px;text-decoration:none;margin-right:8px'>Změnit termín</a>
            <a href='{$zruseni_url}' style='background:#f3e8ff;color:#6b21a8;padding:12px 24px;border-radius:24px;text-decoration:none;border:1px solid #e9d5ff'>Zrušit rezervaci</a>
        </p>
    ");
    return smtp_send($rez['email'], $rez['jmeno'] . ' ' . $rez['prijmeni'],
        'Aktualizace ceny – ' . salon_nazev(), $html);
}

function email_pripominka(array $rez, string $sluzba_nazev, int $hodin_predem): bool {
    $zmena_url   = BASE_URL . '/zmena-rezervace.php?token=' . urlencode($rez['token_zmena']);
    $zruseni_url = BASE_URL . '/zruseni-rezervace.php?token=' . urlencode($rez['token_zmena']);
    $ics_url     = BASE_URL . '/api/ics?token=' . urlencode($rez['token_zmena']);
    $datum_fmt   = datum_cs($rez['datum']);

    $kdy = $hodin_predem >= 24 && $hodin_predem % 24 === 0
        ? ($hodin_predem === 24 ? 'zítra' : 'za ' . ($hodin_predem / 24) . ' dny')
        : 'za ' . $hodin_predem . ' hodin';

    $html = email_layout("
        <h2 style='color:#6b21a8;margin:0 0 16px'>Připomenutí rezervace ⏰</h2>
        <p>Dobrý den, <strong>{$rez['jmeno']} {$rez['prijmeni']}</strong>,</p>
        <p>připomínáme, že máte {$kdy} naplánovanou návštěvu u nás.</p>
        " . tabulka_rezervace($sluzba_nazev, $datum_fmt, $rez['cas_od'], $rez['cena'], $rez['poznamka'] ?? '', $rez['doplnky'] ?? [], isset($rez['cena_upravena']) ? (float)$rez['cena_upravena'] : null) . "
        <p>Potřebujete termín změnit nebo zrušit?</p>
        <p style='text-align:center;margin:24px 0'>
            <a href='{$zmena_url}' style='background:#9333ea;color:#fff;padding:12px 24px;border-radius:24px;text-decoration:none;margin-right:8px'>Změnit termín</a>
            <a href='{$zruseni_url}' style='background:#f3e8ff;color:#6b21a8;padding:12px 24px;border-radius:24px;text-decoration:none;border:1px solid #e9d5ff'>Zrušit rezervaci</a>
        </p>
        <p style='text-align:center;margin-top:12px'>
            <a href='{$ics_url}' style='background:#f3e8ff;color:#6b21a8;padding:10px 20px;border-radius:24px;text-decoration:none;border:1px solid #e9d5ff;font-size:13px'>📅 Přidat do kalendáře</a>
        </p>
    ");
    return smtp_send($rez['email'], $rez['jmeno'] . ' ' . $rez['prijmeni'],
        'Připomenutí rezervace – ' . salon_nazev(), $html);
}

function email_zadost_hodnoceni(array $rez, string $sluzba_nazev): bool {
    $datum_fmt = datum_cs($rez['datum']);
    $hodnoceni_url = BASE_URL . '/hodnoceni.php?token=' . urlencode($rez['token_zmena']);

    $stars_html = '';
    for ($i = 1; $i <= 5; $i++) {
        $stars_html .= "<a href='{$hodnoceni_url}&hvezdy={$i}' style='display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:50%;background:#faf5ff;border:2px solid #e9d5ff;text-decoration:none;font-size:20px;color:#d8b4fe;margin:0 4px'>&#9733;</a>";
    }

    $html = email_layout("
        <h2 style='color:#6b21a8;margin:0 0 16px'>Jak jste byl spokojen? ⭐</h2>
        <p>Dobrý den, <strong>{$rez['jmeno']} {$rez['prijmeni']}</strong>,</p>
        <p>děkujeme za návštěvu. Ohodnotíte nám prosím vaši zkušenost?</p>
        <p style='font-weight:600;margin:16px 0 4px'>{$sluzba_nazev} · {$datum_fmt}</p>
        <p style='text-align:center;margin:20px 0'>{$stars_html}</p>
        <p style='text-align:center;color:#9ca3af;font-size:13px'>Klikněte na počet hvězdiček, hodnocení se uloží okamžitě</p>
    ");
    return smtp_send($rez['email'], $rez['jmeno'] . ' ' . $rez['prijmeni'],
        'Jak jste byl spokojen? – ' . salon_nazev(), $html);
}

function email_nove_hodnoceni(array $rez, int $hvezdy): bool {
    $admin_email = nastaveni('salon_email');
    if (!$admin_email) return false;

    $stars_html = '';
    for ($i = 1; $i <= 5; $i++) {
        $color = $i <= $hvezdy ? '#f59e0b' : '#e5e7eb';
        $stars_html .= "<span style='color:{$color};font-size:20px'>&#9733;</span>";
    }

    $kalendar_url = BASE_URL . '/admin.html#kalendar/' . $rez['datum'];

    $html = email_layout("
        <div style='background:#f3e8ff;border-radius:10px;padding:12px 16px;margin-bottom:20px;color:#6b21a8;font-weight:600;font-size:16px'>
            ⭐ Nové hodnocení rezervace
        </div>
        <table style='width:100%;border-collapse:collapse;margin-bottom:20px;font-size:14px'>
            <tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Zákazník</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff'>" . htmlspecialchars($rez['jmeno'] . ' ' . $rez['prijmeni']) . "</td></tr>
            <tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Datum</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff'>" . datum_cs($rez['datum']) . "</td></tr>
            <tr><td style='padding:8px;color:#6b7280'>Hodnocení</td><td style='padding:8px'>{$stars_html}</td></tr>
        </table>
        <p style='text-align:center'>
            <a href='{$kalendar_url}' style='background:#9333ea;color:#fff;padding:11px 24px;border-radius:24px;text-decoration:none;font-size:14px'>Otevřít v kalendáři</a>
        </p>
    ");
    return smtp_send($admin_email, salon_nazev(), 'Nové hodnocení – ' . salon_nazev(), $html);
}

function email_zmena_terminu(array $rez, string $sluzba_nazev): bool {
    $zmena_url   = BASE_URL . '/zmena-rezervace.php?token=' . urlencode($rez['token_zmena']);
    $zruseni_url = BASE_URL . '/zruseni-rezervace.php?token=' . urlencode($rez['token_zmena']);
    $ics_url     = BASE_URL . '/api/ics?token=' . urlencode($rez['token_zmena']);
    $datum_fmt   = datum_cs($rez['datum']);

    $html = email_layout("
        <h2 style='color:#6b21a8;margin:0 0 16px'>Změna termínu rezervace ✂️</h2>
        <p>Dobrý den, <strong>{$rez['jmeno']} {$rez['prijmeni']}</strong>,</p>
        <p>váš termín byl změněn. Níže najdete aktuální informace o rezervaci.</p>
        " . tabulka_rezervace($sluzba_nazev, $datum_fmt, $rez['cas_od'], $rez['cena'], $rez['poznamka'] ?? '') . "
        <p>Potřebujete termín dále změnit nebo zrušit?</p>
        <p style='text-align:center;margin:24px 0'>
            <a href='{$zmena_url}'   style='background:#9333ea;color:#fff;padding:12px 24px;border-radius:24px;text-decoration:none;margin-right:8px'>Změnit termín</a>
            <a href='{$zruseni_url}' style='background:#f3e8ff;color:#6b21a8;padding:12px 24px;border-radius:24px;text-decoration:none;border:1px solid #e9d5ff'>Zrušit rezervaci</a>
        </p>
        <p style='text-align:center;margin-top:12px'>
            <a href='{$ics_url}' style='background:#f3e8ff;color:#6b21a8;padding:10px 20px;border-radius:24px;text-decoration:none;border:1px solid #e9d5ff;font-size:13px'>📅 Přidat do kalendáře</a>
        </p>
    ");
    return smtp_send($rez['email'], $rez['jmeno'] . ' ' . $rez['prijmeni'],
        'Změna termínu – ' . salon_nazev(), $html);
}

function email_zruseni(array $rez, string $sluzba_nazev, string $kym): bool {
    $datum_fmt = datum_cs($rez['datum']);
    $zprava = $kym === 'admin'
        ? 'Vaši rezervaci jsme museli zrušit. Omlouváme se za komplikace.'
        : 'Vaše rezervace byla úspěšně zrušena na vaši žádost.';
    $duvod = !empty($rez['duvod_zruseni'])
        ? "<p style='background:#fff3f3;border-left:3px solid #991b1b;padding:10px 14px;border-radius:4px;margin:12px 0;font-size:14px'><strong>Důvod:</strong> " . htmlspecialchars($rez['duvod_zruseni'], ENT_QUOTES, 'UTF-8') . "</p>"
        : '';
    $html = email_layout("
        <h2 style='color:#991b1b;margin:0 0 16px'>Rezervace zrušena</h2>
        <p>Dobrý den, <strong>{$rez['jmeno']} {$rez['prijmeni']}</strong>,</p>
        <p>{$zprava}</p>
        {$duvod}
        " . tabulka_rezervace($sluzba_nazev, $datum_fmt, $rez['cas_od'], null) . "
        <p style='text-align:center;margin-top:24px'>
            <a href='" . BASE_URL . "' style='background:#9333ea;color:#fff;padding:12px 24px;border-radius:24px;text-decoration:none'>Rezervovat nový termín</a>
        </p>
    ");
    return smtp_send($rez['email'], $rez['jmeno'] . ' ' . $rez['prijmeni'],
        'Zrušení rezervace – ' . salon_nazev(), $html);
}

function tabulka_rezervace(string $sluzba, string $datum, string $cas, ?string $cena, string $poznamka = '', array $doplnky = [], ?float $cena_upravena = null): string {
    $cena_upravena_val = $cena_upravena;
    $extra_cena_tbl = 0;
    foreach ($doplnky as $d) { $extra_cena_tbl += (float)$d['cena']; }
    $zakladni_num = ($cena !== null && $cena !== '' && $cena !== '0' && $cena !== 'Individuální') ? (float)str_replace(' ', '', $cena) : 0;

    if ($cena_upravena_val !== null) {
        // Cena byla ručně upravena — zobrazit jen finální cenu
        $cena_row = '';
        $doplnky = []; // Neskrýváme doplňky — ale v emailu je nezobrazujeme
        $celkem_row = "<tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff;font-weight:600'>Celkem</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff;color:#6b21a8'>" . number_format((float)$cena_upravena_val, 0, ',', ' ') . " Kč</td></tr>";
    } else {
        $celkem_tbl = $zakladni_num + $extra_cena_tbl;
        if ($celkem_tbl > 0 && !empty($doplnky)) {
            $cena_row = "<tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Základní cena</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff'>{$cena} Kč</td></tr>";
        } elseif ($zakladni_num > 0) {
            $cena_row = "<tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Cena</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff'>{$cena} Kč</td></tr>";
        } else {
            $cena_row = '';
        }
        $celkem_row = ($celkem_tbl > 0 && !empty($doplnky))
            ? "<tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff;font-weight:600'>Celkem</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff;color:#6b21a8'>" . number_format($celkem_tbl, 0, ',', ' ') . " Kč</td></tr>"
            : '';
    }

    $doplnky_row = '';
    if (!empty($doplnky)) {
        $doplnky_html = "<div style='background:#faf5ff;border-radius:6px;padding:8px 10px;'>";
        $extra_cena = 0;
        foreach ($doplnky as $d) {
            $doplnky_html .= "<div style='display:flex;justify-content:space-between;font-size:13px;padding:3px 0;color:#6b21a8'><span>" . htmlspecialchars($d['nazev']) . "</span><span>+" . number_format((float)$d['cena'], 0, ',', ' ') . " Kč</span></div>";
            $extra_cena += (float)$d['cena'];
        }
        $doplnky_html .= "</div>";
        $doplnky_row = "<tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Doplňky</td><td style='padding:8px;border-bottom:1px solid #f3e8ff'>{$doplnky_html}</td></tr>";
    }

    $poznamka_row = !empty($poznamka)
        ? "<tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Poznámka</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff'>" . htmlspecialchars($poznamka) . "</td></tr>"
        : '';
    return "
    <table style='width:100%;border-collapse:collapse;margin:20px 0;font-size:14px'>
        <tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Služba</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff'>{$sluzba}</td></tr>
        <tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Datum</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff'>{$datum}</td></tr>
        <tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Čas</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff'>{$cas}</td></tr>
        {$cena_row}
        {$doplnky_row}
        {$celkem_row}
        {$poznamka_row}
    </table>";
}

function email_footer(): string {
    return "
        <div style='margin-top:24px;padding-top:16px;border-top:1px solid #f3e8ff;text-align:center;font-size:11px;color:#9ca3af'>
            &copy; " . date('Y') . " " . htmlspecialchars(salon_nazev()) . "
            &nbsp;&middot;&nbsp;
            Rezervační systém vytvořil <a href='https://jservices.cz' style='color:#a855f7;text-decoration:none;font-weight:500'>J Services</a>
        </div>
    ";
}

function email_layout(string $content): string {
    return "<!DOCTYPE html><html><head><meta charset='utf-8'><meta name='viewport' content='width=device-width,initial-scale=1'></head>
    <body style='margin:0;padding:0;background:#f9fafb;font-family:Arial,sans-serif;font-size:15px;line-height:1.6'>
    <table width='100%' cellpadding='0' cellspacing='0'><tr><td align='center' style='padding:32px 16px'>
    <table width='100%' style='max-width:560px;background:#fff;border-radius:16px;overflow:hidden;border:1px solid #f3e8ff' cellpadding='0' cellspacing='0'>
        <tr><td style='background:#9333ea;padding:20px 32px;text-align:center'>
            <span style='color:#fff;font-size:20px;font-weight:600'>✂️ " . salon_nazev() . "</span>
        </td></tr>
        <tr><td style='padding:28px 32px'>{$content}</td></tr>
        <tr><td style='background:#faf5ff;padding:14px 32px;text-align:center;font-size:12px;color:#9ca3af'>
            © " . date('Y') . " " . htmlspecialchars(salon_nazev()) . " · Automaticky generovaný e-mail, neodpovídejte na něj.<br>
            Rezervační systém vytvořil <a href='https://jservices.cz' style='color:#a855f7;text-decoration:none;font-weight:500'>J Services</a>
        </td></tr>
    </table></td></tr></table></body></html>";
}

function datum_cs(string $datum): string {
    $ts     = strtotime($datum);
    $mesice = ['','ledna','února','března','dubna','května','června','července','srpna','září','října','listopadu','prosince'];
    $dny    = ['neděle','pondělí','úterý','středa','čtvrtek','pátek','sobota'];
    return $dny[date('w', $ts)] . ' ' . (int)date('j', $ts) . '. ' . $mesice[(int)date('n', $ts)] . ' ' . date('Y', $ts);
}

// -----------------------------------------------
//  Notifikace pro admina
// -----------------------------------------------

function email_notifikace_admin(array $rez, string $sluzba_nazev, string $typ): bool {
    $admin_email = nastaveni('salon_email', MS_FROM_EMAIL);
    $datum_fmt   = datum_cs($rez['datum']);

    $barva  = $typ === 'nova' ? '#166534' : ($typ === 'zrusena' ? '#991b1b' : '#92400e');
    $bgbarva = $typ === 'nova' ? '#dcfce7' : ($typ === 'zrusena' ? '#fee2e2' : '#fef3c7');
    $ikona  = $typ === 'nova' ? '🆕' : ($typ === 'zrusena' ? '❌' : ($typ === 'zmenena' ? '💰' : '🔄'));
    $nadpis = $typ === 'nova' ? 'Nová rezervace' : ($typ === 'zrusena' ? 'Rezervace zrušena' : ($typ === 'zmenena' ? 'Změna ceny rezervace' : 'Rezervace změněna'));
    $predmet = $ikona . ' ' . $nadpis . ' – ' . $rez['jmeno'] . ' ' . $rez['prijmeni'];

    $telefon_row = !empty($rez['telefon'])
        ? "<tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Telefon</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff'>" . htmlspecialchars($rez['telefon']) . "</td></tr>"
        : '';
    $poznamka_row = !empty($rez['poznamka'])
        ? "<tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Poznámka</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff'>" . htmlspecialchars($rez['poznamka']) . "</td></tr>"
        : '';

    // Doplňky
    $doplnky_admin = $rez['doplnky'] ?? [];
    $extra_cena = 0;
    $doplnky_admin_row = '';
    if (!empty($doplnky_admin)) {
        $doplnky_html = "<div style='background:#faf5ff;border-radius:6px;padding:6px 10px;'>";
        foreach ($doplnky_admin as $d) {
            $extra_cena += (float)$d['cena'];
            $doplnky_html .= "<div style='display:flex;justify-content:space-between;font-size:13px;padding:2px 0;color:#6b21a8'><span>" . htmlspecialchars($d['nazev']) . "</span><span>+" . number_format((float)$d['cena'], 0, ',', ' ') . " Kč</span></div>";
        }
        $doplnky_html .= "</div>";
        $doplnky_admin_row = "<tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Doplňky</td><td style='padding:8px;border-bottom:1px solid #f3e8ff'>{$doplnky_html}</td></tr>";
    }
    // Pokud existuje cena_upravena, je to finální — nepřičítat doplňky
    if (isset($rez['cena_upravena']) && $rez['cena_upravena'] !== null && $rez['cena_upravena'] !== '') {
        $celkem_cena  = (float)$rez['cena_upravena'];
        $doplnky_admin_row = ''; // Při upravené ceně nezobrazujeme doplňky zvlášť
    } else {
        $zakladni_cena = (float)str_replace(' ', '', $rez['cena'] ?? '0');
        $celkem_cena   = $zakladni_cena + $extra_cena;
    }
    $cena_display = $celkem_cena > 0 ? number_format($celkem_cena, 0, ',', ' ') . ' Kč' : ($rez['cena'] ? $rez['cena'] . ' Kč' : 'Individuální');

    $html = email_layout("
        <div style='background:{$bgbarva};border-radius:10px;padding:12px 16px;margin-bottom:20px;color:{$barva};font-weight:600;font-size:16px'>
            {$ikona} {$nadpis}
        </div>
        <table style='width:100%;border-collapse:collapse;margin-bottom:20px;font-size:14px'>
            <tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Zákazník</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff'>" . htmlspecialchars($rez['jmeno'] . ' ' . $rez['prijmeni']) . "</td></tr>
            <tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>E-mail</td><td style='padding:8px;border-bottom:1px solid #f3e8ff'><a href='mailto:" . htmlspecialchars($rez['email']) . "' style='color:#7c3aed'>" . htmlspecialchars($rez['email']) . "</a></td></tr>
            {$telefon_row}
            <tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Služba</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff'>" . htmlspecialchars($sluzba_nazev) . "</td></tr>
            {$doplnky_admin_row}
            <tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Datum</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff'>{$datum_fmt}</td></tr>
            <tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Čas</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff'>" . htmlspecialchars($rez['cas_od']) . "</td></tr>
            <tr><td style='padding:8px;color:#6b7280;border-bottom:1px solid #f3e8ff'>Celkem</td><td style='padding:8px;font-weight:600;border-bottom:1px solid #f3e8ff'>{$cena_display}</td></tr>
            {$poznamka_row}
        </table>
        <p style='text-align:center'>
            <a href='" . BASE_URL . "/admin.html#kalendar/" . $rez['datum'] . "' style='background:#9333ea;color:#fff;padding:11px 24px;border-radius:24px;text-decoration:none;font-size:14px'>Otevřít v kalendáři</a>
        </p>
    ");

    return smtp_send($admin_email, salon_nazev(), $predmet, $html);
}

Youez - 2016 - github.com/yon3zu
LinuXploit