From bf9a5e1c8ded251a549bd9fe741f5e46db3dc6a6 Mon Sep 17 00:00:00 2001 From: Kowalski Date: Mon, 3 Aug 2026 10:29:25 +0200 Subject: [PATCH] SecurityPredicate --- .../Database/KufrikConnectionFactory.php | 16 +- app/UI/@layout.latte | 41 +++-- app/UI/Faktura/FakturaPresenter.php | 102 +++++++++++- app/UI/Faktura/default.latte | 149 ++++++++++++++++++ app/UI/Sign/SignPresenter.php | 2 +- 5 files changed, 289 insertions(+), 21 deletions(-) create mode 100644 app/UI/Faktura/default.latte diff --git a/app/Model/Database/KufrikConnectionFactory.php b/app/Model/Database/KufrikConnectionFactory.php index 4c7df93..9813bdf 100644 --- a/app/Model/Database/KufrikConnectionFactory.php +++ b/app/Model/Database/KufrikConnectionFactory.php @@ -29,28 +29,34 @@ class KufrikConnectionFactory $identity = $this->user->getIdentity(); - // Server i Databáze se načtou z Identity přihlášeného uživatele (z tabulky LOGIN) + // Server, Databáze i FirmaId se načtou z Identity přihlášeného uživatele $host = $identity->server ?? null; $databaseName = $identity->database ?? null; + $firmaId = $identity->firma_id ?? null; - if (empty($host) || empty($databaseName)) { - throw new \LogicException('Přihlášený uživatel nemá v tabulce LOGIN definovaný SERVER nebo DATABASE.'); + if (empty($host) || empty($databaseName) || empty($firmaId)) { + throw new \LogicException('Přihlášený uživatel nemá v tabulce LOGIN definovaný SERVER, DATABASE nebo FIRMA_ID.'); } // Dynamický DSN řetězec $dsn = "sqlsrv:Server={$host};Database={$databaseName};LoginTimeout=3;"; - return new Connection( + $connection = new Connection( $dsn, $this->dbUser, $this->dbPassword, [ - 'lazy' => false, + 'lazy' => false, // Spojení musí vzniknout ihned 'driverOptions' => [ \PDO::SQLSRV_ATTR_ENCODING => \PDO::SQLSRV_ENCODING_UTF8, ] ] ); + + // NASTAVENÍ RLS KONTEXTU PRO MS SQL SERVER + $connection->query('EXEC sp_set_session_context @key = N\'FirmaId\', @value = ?', (int)$firmaId); + + return $connection; } public function createExplorer(): Explorer diff --git a/app/UI/@layout.latte b/app/UI/@layout.latte index 01d363c..952f5c6 100644 --- a/app/UI/@layout.latte +++ b/app/UI/@layout.latte @@ -109,10 +109,10 @@
- +
- -
+ + - + {for $r = $aktualniRok; $r >= $aktualniRok - 3; $r--} + + {/for} - + + + + + + + + + + + + +
diff --git a/app/UI/Faktura/FakturaPresenter.php b/app/UI/Faktura/FakturaPresenter.php index 1eda63f..578e0e5 100644 --- a/app/UI/Faktura/FakturaPresenter.php +++ b/app/UI/Faktura/FakturaPresenter.php @@ -7,19 +7,113 @@ use Nette\Database\Explorer; class FakturaPresenter extends BasePresenter { + /** @persistent */ + public int $rok; + + /** @persistent */ + public string $mesic = ''; + public function __construct( private Explorer $kufrikExplorer ) { parent::__construct(); + $this->rok = (int) date('Y'); } - public function actionDefault(): void + public function renderDefault(): void { - // Seznam faktur + $firmaId = $this->getUser()->getIdentity()->firma_id ?? null; + + if (!$firmaId) { + $this->flashMessage('K účtu není přiřazena žádná aktivní firma.', 'danger'); + $this->template->faktury = []; + $this->template->celkemSum = 0; + $this->template->neuhrazenoCount = 0; + return; + } + + // Dynamické sestavení podmínek WHERE pro T-SQL + $where = ['F.FIRMA_ID = ?']; + $params = [$firmaId]; + + if ($this->rok) { + $where[] = 'YEAR(F.DATUM_VYSTAVENI) = ?'; + $params[] = $this->rok; + } + + if ($this->mesic !== '') { + $where[] = 'MONTH(F.DATUM_VYSTAVENI) = ?'; + $params[] = (int) $this->mesic; + } + + $whereSql = implode(' AND ', $where); + + // Čisté T-SQL zaručující 100% kompatibilitu s MS SQL Serverem bez magických Nette relací + $sql = " + SELECT + F.*, + ISNULL((SELECT SUM(P.CENA) FROM dbo.POLOZKA P WHERE P.FAKTURA = F.ID), 0) AS CASTKA_CELKEM + FROM dbo.FAKTURA F + WHERE {$whereSql} + ORDER BY F.DATUM_VYSTAVENI DESC, F.ID DESC + "; + + // Provedeme dotaz přímo na Explorer connection + $faktury = $this->kufrikExplorer->query($sql, ...$params)->fetchAll(); + + // Součty pro karty + $celkemSum = 0; + $neuhrazenoCount = 0; + + foreach ($faktury as $f) { + $suma = (float) ($f->CASTKA_CELKEM ?? 0); + $celkemSum += $suma; + if ($f->STAV !== 'PAID') { + $neuhrazenoCount++; + } + } + + $this->template->faktury = $faktury; + $this->template->celkemSum = $celkemSum; + $this->template->neuhrazenoCount = $neuhrazenoCount; + $this->template->vybranyRok = $this->rok; + $this->template->vybranyMesic = $this->mesic; } - public function actionAdd(): void + public function handleUhradit(int $id): void { - // Přidání faktury + $firmaId = $this->getUser()->getIdentity()->firma_id; + $faktura = $this->kufrikExplorer->table('FAKTURA') + ->where('ID', $id) + ->where('FIRMA_ID', $firmaId) + ->fetch(); + + if ($faktura) { + $novyStav = ($faktura->STAV === 'PAID') ? 'ISSUED' : 'PAID'; + $faktura->update(['STAV' => $novyStav]); + + $this->flashMessage( + $novyStav === 'PAID' ? 'Faktura byla označena jako zaplacená.' : 'Stav faktury byl změněn na neuhrazeno.', + 'success' + ); + } + + $this->redirect('this'); + } + + public function handleDelete(int $id): void + { + $firmaId = $this->getUser()->getIdentity()->firma_id; + + $deleted = $this->kufrikExplorer->table('FAKTURA') + ->where('ID', $id) + ->where('FIRMA_ID', $firmaId) + ->delete(); + + if ($deleted) { + $this->flashMessage('Faktura byla smazána.', 'info'); + } + + $this->redirect('this'); } } \ No newline at end of file diff --git a/app/UI/Faktura/default.latte b/app/UI/Faktura/default.latte new file mode 100644 index 0000000..8f2f6f9 --- /dev/null +++ b/app/UI/Faktura/default.latte @@ -0,0 +1,149 @@ +{block content} + +
+ + + + + +
+
+
+
+
+
Celkem fakturováno ({$vybranyRok}{if $vybranyMesic}/{$vybranyMesic}{/if})
+
{$celkemSum|number:2, ',', ' '} CZK
+
+
+
+
+
+
+
+
Neuhrazené faktury v období
+
{$neuhrazenoCount} ks
+
+
+
+
+ + +
+
+

+ Vydané faktury +

+ + Vystavit novou fakturu + +
+ +
+ + + + + + + + + + + + + + {foreach $faktury as $faktura} + + + + + + + + + + {else} + + + + {/foreach} + +
Číslo fakturyOdběratelVystavenoSplatnostCelková částkaStavAkce
+ + {$faktura->CISLO} + + +
{$faktura->O_PRAJM ?: 'Nespecifikovaný odběratel'}
+
IČ: {$faktura->O_IC}
+
{$faktura->DATUM_VYSTAVENI|date:'d.m.Y'} + + {$faktura->DATUM_SPLATNOSTI|date:'d.m.Y'} + + + {($faktura->CASTKA_CELKEM ?? 0)|number:2, ',', ' '} CZK + + {if $faktura->STAV === 'PAID'} + + Uhrazeno + + {else} + + Neuhrazeno + + {/if} + +
+ + + + + + + + + + + + + + + + + + + +
+
+ + Pro zadaný filtr (rok {$vybranyRok}{if $vybranyMesic}, měsíc {$vybranyMesic}{/if}) nebyly nalezeny žádné faktury. +
+
+
+ +
+ + \ No newline at end of file diff --git a/app/UI/Sign/SignPresenter.php b/app/UI/Sign/SignPresenter.php index c78535a..9989eb2 100644 --- a/app/UI/Sign/SignPresenter.php +++ b/app/UI/Sign/SignPresenter.php @@ -41,7 +41,7 @@ class SignPresenter extends Presenter $this->flashMessage('Přihlášení proběhlo úspěšně.', 'success'); // Přesměrování do hlavní části aplikace (např. HomePresenter) - $this->redirect('Home:'); + $this->redirect('Faktura:'); } catch (AuthenticationException $e) { $form->addError('Nespravný e-mail nebo heslo.');