403Webshell
Server IP : 193.86.120.172  /  Your IP : 216.73.216.215
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/hotel_jservices_cz/api/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /volume1/web/hotel_jservices_cz/api/dostupnost.php
<?php
// ============================================================
//  Hotel DEMO — api/dostupnost.php
//  Výpočet volných typů pokojů a dostupnosti kapacitních doplňků
//  Veřejný endpoint — nevyžaduje přihlášení
// ============================================================

$action = $_GET['action'] ?? 'pokoje';

match ($action) {
    'pokoje'   => dos_volne_pokoje(),
    'doplnky'  => dos_dostupne_doplnky(),
    'kalendar' => dos_kalendar(),
    'kapacity_tyden' => dos_kapacity_tyden(),
    default    => api_response(false, null, 'Neznámá akce', 400),
};

// ------------------------------------------------------------
//  VOLNÉ TYPY POKOJŮ pro daný termín (veřejný formulář)
//  Zákazník vybírá TYP, systém přiřadí konkrétní pokoj automaticky.
//  GET ?action=pokoje&datum_od=2025-07-14&datum_do=2025-07-17
//      &pocet_hostu=2
//      &admin=1 (admin vidí konkrétní pokoje pro interní použití)
// ------------------------------------------------------------
function dos_volne_pokoje(): never {
    $datum_od    = $_GET['datum_od'] ?? '';
    $datum_do    = $_GET['datum_do'] ?? '';
    $pocet_hostu = (int)($_GET['pocet_hostu'] ?? 1);
    $je_admin    = !empty($_GET['admin']) && _dos_overit_admina();

    if (!$datum_od || !$datum_do) {
        api_response(false, null, 'Zadejte datum příjezdu a odjezdu.', 400);
    }
    if (!_dos_validuj_datum($datum_od) || !_dos_validuj_datum($datum_do)) {
        api_response(false, null, 'Neplatný formát data.', 400);
    }
    if ($datum_od >= $datum_do) {
        api_response(false, null, 'Datum odjezdu musí být po datu příjezdu.', 400);
    }

    $min_predem = (int)nastaveni('rezervace_min_predem_dni', '1');
    if (!$je_admin && $datum_od < date('Y-m-d', strtotime("+{$min_predem} days"))) {
        api_response(false, null, "Rezervaci lze vytvořit nejdříve {$min_predem} den(dní) předem.", 400);
    }

    $pocet_noci = _dos_pocet_noci($datum_od, $datum_do);
    $vyjmout_rezervaci = (int)($_GET['vyjmout_rezervaci'] ?? 0);

    // Obsazené pokoje v daném termínu (vyjma rezervace, kterou právě potvrzujeme)
    $obsazene = array_column(db_rows(
        "SELECT DISTINCT pokoj_id FROM rezervace
         WHERE stav != 'zrusena'
           AND id != ?
           AND datum_prijezdu < ? AND datum_odjezdu > ?",
        [$vyjmout_rezervaci, $datum_do, $datum_od]
    ), 'pokoj_id');

    // Blokované termíny
    $blokovane = array_column(db_rows(
        "SELECT DISTINCT pokoj_id FROM blokovane_terminy
         WHERE datum_od < ? AND datum_do > ?",
        [$datum_do, $datum_od]
    ), 'pokoj_id');

    $nedostupne_pokoje = array_unique(array_merge($obsazene, $blokovane));

    // Nastavení automatické slevy
    $sleva_zapnuta = nastaveni('sleva_jednoluzko_zapnuta', '1') === '1';
    $sleva_procent = (int)nastaveni('sleva_jednoluzko_procent', '20');

    if ($je_admin) {
        // Admin vidí konkrétní pokoje (pro Gantt a interní výběr)
        $pokoje = db_rows(
            "SELECT p.id, p.cislo, p.nazev, p.aktivni, p.typ_id,
                    t.nazev AS typ_nazev, t.kapacita, t.cena_za_noc,
                    t.min_pobyt_noci, t.snidane_dostupne, t.popis
             FROM pokoje p
             JOIN typy_pokoju t ON t.id = p.typ_id
             WHERE p.aktivni = 1 AND t.aktivni = 1
             ORDER BY t.poradi ASC, p.poradi ASC, p.cislo ASC"
        );
        foreach ($pokoje as &$p) {
            $p['dostupny']   = !in_array($p['id'], $nedostupne_pokoje);
            $p['pocet_noci'] = $pocet_noci;
            $p['cena_pobyt'] = round($p['cena_za_noc'] * $pocet_noci, 2);
            $p['min_splnen'] = $pocet_noci >= $p['min_pobyt_noci'];
        }
        unset($p);
        api_response(true, [
            'pokoje' => $pokoje, 'datum_od' => $datum_od,
            'datum_do' => $datum_do, 'pocet_noci' => $pocet_noci,
            'pocet_hostu' => $pocet_hostu, 'rezim' => 'admin',
        ]);
    }

    // Veřejný formulář — vrací TYPY pokojů
    $typy = db_rows(
        "SELECT t.id, t.nazev, t.nazev_en, t.nazev_de, t.kapacita, t.cena_za_noc,
                t.min_pobyt_noci, t.snidane_dostupne, t.popis, t.popis_en, t.popis_de, t.poradi,
                COUNT(p.id) AS pocet_pokoju_celkem
         FROM typy_pokoju t
         JOIN pokoje p ON p.typ_id = t.id AND p.aktivni = 1
         WHERE t.aktivni = 1
         GROUP BY t.id
         ORDER BY t.poradi ASC, t.nazev ASC"
    );

    $max_kapacita = 0;
    foreach ($typy as $t) {
        if ((int)$t['kapacita'] > $max_kapacita) $max_kapacita = (int)$t['kapacita'];
    }

    foreach ($typy as &$typ) {
        $pokoje_typu = array_column(db_rows(
            'SELECT id FROM pokoje WHERE typ_id = ? AND aktivni = 1',
            [$typ['id']]
        ), 'id');

        $volne = array_filter($pokoje_typu, fn($id) => !in_array($id, $nedostupne_pokoje));
        $typ['volnych_pokoju']   = count($volne);
        $typ['dostupny']         = count($volne) > 0
                                    && $pocet_noci >= $typ['min_pobyt_noci']
                                    && $typ['kapacita'] >= $pocet_hostu;
        $typ['min_splnen']       = $pocet_noci >= $typ['min_pobyt_noci'];
        $typ['kapacita_splnena'] = (int)$typ['kapacita'] >= $pocet_hostu;
        $typ['pocet_noci']       = $pocet_noci;

        $cena_zaklad = round($typ['cena_za_noc'] * $pocet_noci, 2);

        $typ['sleva_jednoluzko']         = false;
        $typ['sleva_jednoluzko_procent'] = 0;
        $typ['cena_po_sleve']            = $cena_zaklad;
        $typ['cena_pobyt']               = $cena_zaklad;

        if ($sleva_zapnuta && $pocet_hostu === 1 && (int)$typ['kapacita'] > 1) {
            $sleva_castka                    = round($cena_zaklad * $sleva_procent / 100, 2);
            $typ['sleva_jednoluzko']         = true;
            $typ['sleva_jednoluzko_procent'] = $sleva_procent;
            $typ['cena_po_sleve']            = round($cena_zaklad - $sleva_castka, 2);
            $typ['cena_pobyt']               = $typ['cena_po_sleve'];
            $typ['sleva_castka_pobyt']       = $sleva_castka;
        }
    }
    unset($typ);

    api_response(true, [
        'typy'         => $typy,
        'datum_od'     => $datum_od,
        'datum_do'     => $datum_do,
        'pocet_noci'   => $pocet_noci,
        'pocet_hostu'  => $pocet_hostu,
        'max_kapacita' => $max_kapacita,
        'rezim'        => 'verejny',
    ]);
}

// ------------------------------------------------------------
//  DOSTUPNÉ DOPLŇKY pro daný termín
// ------------------------------------------------------------
function dos_dostupne_doplnky(): never {
    $datum_od    = $_GET['datum_od'] ?? '';
    $datum_do    = $_GET['datum_do'] ?? '';
    $typ_id      = (int)($_GET['typ_id'] ?? 0);
    $pocet_hostu = (int)($_GET['pocet_hostu'] ?? 1);

    if (!$datum_od || !$datum_do) {
        api_response(false, null, 'Zadejte termín.', 400);
    }

    $pocet_noci = _dos_pocet_noci($datum_od, $datum_do);

    // Zjistit zda typ pokoje nabízí snídaně
    $snidane_dostupne = true;
    if ($typ_id) {
        $snidane_dostupne = (bool)db_val(
            'SELECT snidane_dostupne FROM typy_pokoju WHERE id = ?',
            [$typ_id]
        );
    }

    $doplnky = db_rows('SELECT * FROM doplnky WHERE aktivni = 1 ORDER BY poradi ASC');

    $dobijeni_vybrano = false;
    $dobijeni_id      = null;
    $parkovani_id     = null;

    // Nejdřív zjistíme ID doplňků dobíjení a parkování
    foreach ($doplnky as $d) {
        $n = mb_strtolower($d['nazev']);
        if (str_contains($n, 'dob') || str_contains($n, 'elektro') || str_contains($n, 'nabíj')) {
            $dobijeni_id = $d['id'];
        }
        if (str_contains($n, 'parkov')) {
            $parkovani_id = $d['id'];
        }
    }

    foreach ($doplnky as &$d) {
        $d['dostupny']    = true;
        $noci_pro_vypocet  = in_array($d['typ_uctovani'], ['za_noc', 'za_osobu_noc'], true) ? $pocet_noci : 1;
        $hostu_pro_vypocet = $d['typ_uctovani'] === 'za_osobu_noc' ? $pocet_hostu : 1;
        $d['cena_celkem'] = round($d['cena'] * $noci_pro_vypocet * $hostu_pro_vypocet, 2);

        $n = mb_strtolower($d['nazev']);

        // Snídaně — filtr dle typu pokoje
        if (str_contains($n, 'snídaně') || str_contains($n, 'snidane')) {
            if (!$snidane_dostupne) {
                $d['dostupny']            = false;
                $d['duvod_nedostupnosti'] = 'Pro tento typ pokoje není snídaně k dispozici.';
                continue;
            }
        }

        // Kapacitní doplňky — ověřit obsazenost
        if ($d['kapacita'] !== null) {
            $obsazeno = (int)db_val(
                "SELECT COUNT(*) FROM rezervace_doplnky rd
                 JOIN rezervace r ON r.id = rd.rezervace_id
                 WHERE rd.doplnek_id = ?
                   AND r.stav != 'zrusena'
                   AND r.datum_prijezdu < ? AND r.datum_odjezdu > ?",
                [$d['id'], $datum_do, $datum_od]
            );
            $zbyva = (int)$d['kapacita'] - $obsazeno;
            $d['kapacita_obsazeno'] = $obsazeno;
            $d['kapacita_zbyva']    = max(0, $zbyva);

            if ($zbyva <= 0) {
                $d['dostupny']            = false;
                $d['duvod_nedostupnosti'] = 'Kapacita je pro tento termín vyčerpána.';
            }
        }
    }
    unset($d);

    api_response(true, [
        'doplnky'      => $doplnky,
        'pocet_noci'   => $pocet_noci,
        'dobijeni_id'  => $dobijeni_id,
        'parkovani_id' => $parkovani_id,
    ]);
}

// ------------------------------------------------------------
//  KALENDÁŘ OBSAZENOSTI (pro admin Gantt)
// ------------------------------------------------------------
function dos_kapacity_tyden(): never {
    $user = auth_check();

    $datum_od = $_GET['datum_od'] ?? date('Y-m-d');
    $pocet_dni = max(1, min(31, (int)($_GET['pocet_dni'] ?? 7)));
    $datum_do_excl = date('Y-m-d', strtotime($datum_od . " +{$pocet_dni} days"));

    $parkovani_kap = (int)nastaveni('parkovani_kapacita', '5');
    $dobijeni_kap  = (int)nastaveni('dobijeni_kapacita', '2');

    // Rezervace zasahující do rozsahu
    $rezervace = db_rows(
        "SELECT r.id, r.jmeno, r.prijmeni, r.datum_prijezdu, r.datum_odjezdu, r.pocet_hostu
         FROM rezervace r
         WHERE r.stav != 'zrusena'
           AND r.datum_prijezdu < ?
           AND r.datum_odjezdu  > ?",
        [$datum_do_excl, $datum_od]
    );

    $rez_ids = array_column($rezervace, 'id');
    $rez_doplnky_map = [];
    if ($rez_ids) {
        $placeholders = implode(',', array_fill(0, count($rez_ids), '?'));
        $rez_doplnky = db_rows(
            "SELECT rd.rezervace_id, rd.nazev
             FROM rezervace_doplnky rd
             WHERE rd.rezervace_id IN ($placeholders)",
            $rez_ids
        );
        foreach ($rez_doplnky as $rd) {
            $rez_doplnky_map[$rd['rezervace_id']][] = strtolower($rd['nazev']);
        }
    }

    $rozpoznat_typy = function(array $nazvy): array {
        $typy = [];
        foreach ($nazvy as $n) {
            if (str_contains($n, 'park')) $typy[] = 'parking';
            elseif (str_contains($n, 'dobíj') || str_contains($n, 'dobij') || str_contains($n, 'elektro')) $typy[] = 'charging';
            elseif (str_contains($n, 'snídaně') || str_contains($n, 'snidane') || str_contains($n, 'snídaň')) $typy[] = 'breakfast';
        }
        return array_unique($typy);
    };

    $dny = [];
    $d = $datum_od;
    for ($i = 0; $i < $pocet_dni; $i++) {
        $parkObsaz = 0; $dobiObsaz = 0; $snidanePorci = 0;
        $parkHoste = []; $dobiHoste = []; $snidaneHoste = [];

        foreach ($rezervace as $rez) {
            if ($rez['datum_prijezdu'] > $d || $rez['datum_odjezdu'] <= $d) continue;
            $jmeno = $rez['jmeno'] . ' ' . $rez['prijmeni'];
            $typy  = $rozpoznat_typy($rez_doplnky_map[$rez['id']] ?? []);

            if (in_array('parking', $typy, true))   { $parkObsaz++; $parkHoste[] = $jmeno; }
            if (in_array('charging', $typy, true))  { $dobiObsaz++; $dobiHoste[] = $jmeno; }
            if (in_array('breakfast', $typy, true)) { $snidanePorci += (int)$rez['pocet_hostu']; $snidaneHoste[] = ['jmeno' => $jmeno, 'pocet' => (int)$rez['pocet_hostu']]; }
        }

        $dny[] = [
            'datum'          => $d,
            'parkovani'      => ['obsazeno' => $parkObsaz, 'kapacita' => $parkovani_kap, 'hoste' => $parkHoste],
            'dobijeni'       => ['obsazeno' => $dobiObsaz, 'kapacita' => $dobijeni_kap, 'hoste' => $dobiHoste],
            'snidane'        => ['porci' => $snidanePorci, 'hoste' => $snidaneHoste],
        ];
        $d = date('Y-m-d', strtotime($d . ' +1 day'));
    }

    api_response(true, ['dny' => $dny]);
}

function dos_kalendar(): never {
    $user = auth_check();

    $datum_od = $_GET['datum_od'] ?? date('Y-m-01');
    $datum_do = $_GET['datum_do'] ?? date('Y-m-t');

    $pokoje = db_rows(
        'SELECT p.id, p.cislo, p.nazev, p.aktivni, t.nazev AS typ_nazev
         FROM pokoje p
         JOIN typy_pokoju t ON t.id = p.typ_id
         ORDER BY p.poradi ASC, p.cislo ASC'
    );

    $rezervace = db_rows(
        "SELECT r.id, r.pokoj_id, r.datum_prijezdu, r.datum_odjezdu,
                r.jmeno, r.prijmeni, r.stav, r.pocet_noci,
                r.checkin_cas, r.checkout_cas,
                r.sleva_stav, r.cena_zaklad, r.cena_upravena,
                r.pokoj_zadost_stav, r.cas_zadost_stav
         FROM rezervace r
         WHERE r.stav != 'zrusena'
           AND r.datum_prijezdu < ?
           AND r.datum_odjezdu  > ?
         ORDER BY r.datum_prijezdu ASC",
        [$datum_do, $datum_od]
    );

    // Načíst doplňky pro každou rezervaci (ikonky v kalendáři)
    $rez_ids = array_column($rezervace, 'id');
    $rez_doplnky_map = [];
    if ($rez_ids) {
        $placeholders = implode(',', array_fill(0, count($rez_ids), '?'));
        $rez_doplnky = db_rows(
            "SELECT rd.rezervace_id, rd.nazev
             FROM rezervace_doplnky rd
             WHERE rd.rezervace_id IN ($placeholders)",
            $rez_ids
        );
        foreach ($rez_doplnky as $rd) {
            $rez_doplnky_map[$rd['rezervace_id']][] = strtolower($rd['nazev']);
        }
    }
    // Rozpoznání typu doplňku podle názvu
    foreach ($rezervace as &$r) {
        $nazvy = $rez_doplnky_map[$r['id']] ?? [];
        $typy  = [];
        foreach ($nazvy as $n) {
            if (str_contains($n, 'park'))   $typy[] = 'parking';
            elseif (str_contains($n, 'dobíj') || str_contains($n, 'dobij') || str_contains($n, 'elektro')) $typy[] = 'charging';
            elseif (str_contains($n, 'snídaně') || str_contains($n, 'snidane') || str_contains($n, 'snídaň')) $typy[] = 'breakfast';
            elseif (str_contains($n, 'check-out') || str_contains($n, 'checkout') || str_contains($n, 'pozdní') || str_contains($n, 'pozdn')) $typy[] = 'late_checkout';
            else $typy[] = 'other';
        }
        $r['doplnky_typy'] = array_values(array_unique($typy));
    }
    unset($r);

    $blokovane = db_rows(
        'SELECT * FROM blokovane_terminy
         WHERE datum_od < ? AND datum_do > ?
         ORDER BY datum_od ASC',
        [$datum_do, $datum_od]
    );

    api_response(true, [
        'pokoje'    => $pokoje,
        'rezervace' => $rezervace,
        'blokovane' => $blokovane,
        'datum_od'  => $datum_od,
        'datum_do'  => $datum_do,
    ]);
}

// ------------------------------------------------------------
//  INTERNÍ HELPERY
// ------------------------------------------------------------
function _dos_pocet_noci(string $od, string $do): int {
    return max(1, (int)(new DateTime($od))->diff(new DateTime($do))->days);
}

function _dos_validuj_datum(string $datum): bool {
    $d = DateTime::createFromFormat('Y-m-d', $datum);
    return $d && $d->format('Y-m-d') === $datum;
}

function _dos_overit_admina(): bool {
    $token = $_COOKIE['session_token'] ?? $_SERVER['HTTP_X_SESSION_TOKEN'] ?? '';
    if (!$token) return false;
    $row = db_row(
        "SELECT u.role FROM uzivatel_session s
         JOIN uzivatele u ON u.id = s.uzivatel_id
         WHERE s.token = ? AND s.platnost_do > NOW() AND u.aktivni = 1",
        [$token]
    );
    return $row && in_array($row['role'], ['admin', 'manazer', 'zamestnanec'], true);
}

Youez - 2016 - github.com/yon3zu
LinuXploit