Filtr faktur.
parent
dfd1305ad2
commit
7a98fb3f53
|
|
@ -24,9 +24,10 @@ class FakturaFacade
|
||||||
$params[] = $rok;
|
$params[] = $rok;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($mesic !== '') {
|
$mesicCislo = (int) $mesic;
|
||||||
|
if ($mesic !== '' && $mesicCislo >= 1 && $mesicCislo <= 12) {
|
||||||
$where[] = 'MONTH(F.DATUM_VYSTAVENI) = ?';
|
$where[] = 'MONTH(F.DATUM_VYSTAVENI) = ?';
|
||||||
$params[] = (int) $mesic;
|
$params[] = $mesicCislo;
|
||||||
}
|
}
|
||||||
|
|
||||||
$whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
$whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : '';
|
||||||
|
|
@ -43,6 +44,35 @@ class FakturaFacade
|
||||||
return $this->kufrikExplorer->query($sql, ...$params)->fetchAll();
|
return $this->kufrikExplorer->query($sql, ...$params)->fetchAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Roky, pro které existují faktury (plus aktuální / právě vybraný rok).
|
||||||
|
*
|
||||||
|
* @return int[]
|
||||||
|
*/
|
||||||
|
public function getDostupneRoky(?int $vybranyRok = null): array
|
||||||
|
{
|
||||||
|
$rows = $this->kufrikExplorer->query("
|
||||||
|
SELECT DISTINCT YEAR(DATUM_VYSTAVENI) AS ROK
|
||||||
|
FROM dbo.FAKTURA
|
||||||
|
WHERE DATUM_VYSTAVENI IS NOT NULL
|
||||||
|
ORDER BY ROK DESC
|
||||||
|
")->fetchAll();
|
||||||
|
|
||||||
|
$roky = [];
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$roky[] = (int) $row->ROK;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ([(int) date('Y'), $vybranyRok] as $rok) {
|
||||||
|
if ($rok && !in_array($rok, $roky, true)) {
|
||||||
|
$roky[] = $rok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rsort($roky, SORT_NUMERIC);
|
||||||
|
return $roky;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detail jedné faktury podle ID
|
* Detail jedné faktury podle ID
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -135,35 +135,34 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Filtr pro Faktury v Toolbaru -->
|
<!-- Filtr pro Faktury v Toolbaru -->
|
||||||
<form n:attr="method => 'get', action => $presenter->link('Faktura:default')" class="filter-panel ms-auto ms-lg-0">
|
<form n:attr="method => 'get', action => $presenter->link('Faktura:default', ['rok' => null, 'mesic' => null])" class="filter-panel ms-auto ms-lg-0">
|
||||||
<i class="bi bi-funnel-fill text-muted fs-5 ms-1"></i>
|
<i class="bi bi-funnel-fill text-muted fs-5 ms-1"></i>
|
||||||
|
|
||||||
{var $aktualniRok = (int) date('Y')}
|
{var $aktualniRok = (int) date('Y')}
|
||||||
{var $vybranyRok = $presenter->rok ?? $aktualniRok}
|
{var $vybranyRok = $selectedRok ?? $aktualniRok}
|
||||||
{var $vybranyMesic = $presenter->mesic ?? ''}
|
{var $vybranyMesic = (string) ($selectedMesic ?? '')}
|
||||||
|
{var $rokyFiltr = $roky ?? range($aktualniRok, $aktualniRok - 3)}
|
||||||
|
|
||||||
<!-- Výběr Roku -->
|
<!-- Výběr Roku -->
|
||||||
<select name="rok" class="form-select form-select-sm" style="width: 90px;" onchange="this.form.submit()">
|
<select name="rok" class="form-select form-select-sm" style="width: 90px;" onchange="this.form.submit()">
|
||||||
{for $r = $aktualniRok; $r >= $aktualniRok - 3; $r--}
|
<option n:foreach="$rokyFiltr as $r" value="{$r}" {if $vybranyRok == $r}selected{/if}>{$r}</option>
|
||||||
<option value="{$r}" {if $vybranyRok == $r}selected{/if}>{$r}</option>
|
|
||||||
{/for}
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- Výběr Měsíce -->
|
<!-- Výběr Měsíce -->
|
||||||
<select name="mesic" class="form-select form-select-sm" style="width: 140px;" onchange="this.form.submit()">
|
<select name="mesic" class="form-select form-select-sm" style="width: 140px;" onchange="this.form.submit()">
|
||||||
<option value="" {if $vybranyMesic === ''}selected{/if}>(všechny měsíce)</option>
|
<option value="" {if $vybranyMesic === ''}selected{/if}>(všechny měsíce)</option>
|
||||||
<option value="1" {if $vybranyMesic === '1'}selected{/if}>Leden</option>
|
<option value="1" {if $vybranyMesic == '1'}selected{/if}>Leden</option>
|
||||||
<option value="2" {if $vybranyMesic === '2'}selected{/if}>Únor</option>
|
<option value="2" {if $vybranyMesic == '2'}selected{/if}>Únor</option>
|
||||||
<option value="3" {if $vybranyMesic === '3'}selected{/if}>Březen</option>
|
<option value="3" {if $vybranyMesic == '3'}selected{/if}>Březen</option>
|
||||||
<option value="4" {if $vybranyMesic === '4'}selected{/if}>Duben</option>
|
<option value="4" {if $vybranyMesic == '4'}selected{/if}>Duben</option>
|
||||||
<option value="5" {if $vybranyMesic === '5'}selected{/if}>Květen</option>
|
<option value="5" {if $vybranyMesic == '5'}selected{/if}>Květen</option>
|
||||||
<option value="6" {if $vybranyMesic === '6'}selected{/if}>Červen</option>
|
<option value="6" {if $vybranyMesic == '6'}selected{/if}>Červen</option>
|
||||||
<option value="7" {if $vybranyMesic === '7'}selected{/if}>Červenec</option>
|
<option value="7" {if $vybranyMesic == '7'}selected{/if}>Červenec</option>
|
||||||
<option value="8" {if $vybranyMesic === '8'}selected{/if}>Srpen</option>
|
<option value="8" {if $vybranyMesic == '8'}selected{/if}>Srpen</option>
|
||||||
<option value="9" {if $vybranyMesic === '9'}selected{/if}>Září</option>
|
<option value="9" {if $vybranyMesic == '9'}selected{/if}>Září</option>
|
||||||
<option value="10" {if $vybranyMesic === '10'}selected{/if}>Říjen</option>
|
<option value="10" {if $vybranyMesic == '10'}selected{/if}>Říjen</option>
|
||||||
<option value="11" {if $vybranyMesic === '11'}selected{/if}>Listopad</option>
|
<option value="11" {if $vybranyMesic == '11'}selected{/if}>Listopad</option>
|
||||||
<option value="12" {if $vybranyMesic === '12'}selected{/if}>Prosinec</option>
|
<option value="12" {if $vybranyMesic == '12'}selected{/if}>Prosinec</option>
|
||||||
</select>
|
</select>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -4,29 +4,60 @@ namespace App\UI\Faktura;
|
||||||
|
|
||||||
use App\UI\BasePresenter;
|
use App\UI\BasePresenter;
|
||||||
use App\Model\Facade\FakturaFacade;
|
use App\Model\Facade\FakturaFacade;
|
||||||
|
use Nette\Application\Attributes\Persistent;
|
||||||
|
|
||||||
class FakturaPresenter extends BasePresenter
|
class FakturaPresenter extends BasePresenter
|
||||||
{
|
{
|
||||||
/** @persistent */
|
private const FILTER_COOKIE = 'kufrikFakturaFiltr';
|
||||||
public int $rok;
|
private const FILTER_SESSION = 'fakturaFilter';
|
||||||
|
|
||||||
/** @persistent */
|
#[Persistent]
|
||||||
|
public ?int $rok = null;
|
||||||
|
|
||||||
|
#[Persistent]
|
||||||
public string $mesic = '';
|
public string $mesic = '';
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
private FakturaFacade $fakturaFacade
|
private FakturaFacade $fakturaFacade
|
||||||
) {
|
) {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->rok = (int) date('Y');
|
}
|
||||||
|
|
||||||
|
protected function startup(): void
|
||||||
|
{
|
||||||
|
parent::startup();
|
||||||
|
|
||||||
|
$query = $this->getHttpRequest()->getQuery();
|
||||||
|
$fromUrl = array_key_exists('rok', $query) || array_key_exists('mesic', $query);
|
||||||
|
|
||||||
|
if ($fromUrl) {
|
||||||
|
$this->rok = $this->rok ?? (int) date('Y');
|
||||||
|
$this->mesic = $this->normalizeMesic($this->mesic);
|
||||||
|
$this->saveFilter($this->rok, $this->mesic);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$saved = $this->loadFilter();
|
||||||
|
if ($saved === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->rok = $saved['rok'];
|
||||||
|
$this->mesic = $saved['mesic'];
|
||||||
|
|
||||||
|
// Do URL doplníme uložený filtr, ale ne při signálu (úhrada / smazání).
|
||||||
|
if ($this->getSignal() === null) {
|
||||||
|
$this->redirect('this');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function renderDefault(): void
|
public function renderDefault(): void
|
||||||
{
|
{
|
||||||
// RLS v databázi se postará o filtraci podle firmy,
|
$rok = $this->rok ?? (int) date('Y');
|
||||||
// fasáda vrátí seřazené faktury s dopočítanou sumou.
|
$mesic = $this->normalizeMesic($this->mesic);
|
||||||
$faktury = $this->fakturaFacade->getFiltered($this->rok, $this->mesic);
|
|
||||||
|
$faktury = $this->fakturaFacade->getFiltered($rok, $mesic);
|
||||||
|
|
||||||
// Agregace pro přehledové karty nad aktuálním výběrem
|
|
||||||
$celkemSum = 0;
|
$celkemSum = 0;
|
||||||
$neuhrazenoCount = 0;
|
$neuhrazenoCount = 0;
|
||||||
|
|
||||||
|
|
@ -40,8 +71,79 @@ class FakturaPresenter extends BasePresenter
|
||||||
$this->template->faktury = $faktury;
|
$this->template->faktury = $faktury;
|
||||||
$this->template->celkemSum = $celkemSum;
|
$this->template->celkemSum = $celkemSum;
|
||||||
$this->template->neuhrazenoCount = $neuhrazenoCount;
|
$this->template->neuhrazenoCount = $neuhrazenoCount;
|
||||||
$this->template->selectedRok = $this->rok ?? (int) date('Y'); // <--- PŘIDÁNO
|
$this->template->selectedRok = $rok;
|
||||||
$this->template->selectedMesic = $this->mesic ?? ''; // <--- PŘIDÁNO
|
$this->template->selectedMesic = $mesic;
|
||||||
|
$this->template->roky = $this->fakturaFacade->getDostupneRoky($rok);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function normalizeMesic(string $mesic): string
|
||||||
|
{
|
||||||
|
if ($mesic === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$cislo = (int) $mesic;
|
||||||
|
return ($cislo >= 1 && $cislo <= 12) ? (string) $cislo : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{rok: int, mesic: string}|null
|
||||||
|
*/
|
||||||
|
private function loadFilter(): ?array
|
||||||
|
{
|
||||||
|
$uid = (int) $this->getUser()->getId();
|
||||||
|
$section = $this->getSession(self::FILTER_SESSION);
|
||||||
|
|
||||||
|
if (isset($section->rok) && (int) ($section->userId ?? 0) === $uid) {
|
||||||
|
return $this->validFilter((int) $section->rok, (string) ($section->mesic ?? ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
$raw = $this->getHttpRequest()->getCookie(self::FILTER_COOKIE);
|
||||||
|
if (!is_string($raw) || $raw === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = explode(':', $raw, 3);
|
||||||
|
if (count($parts) < 2 || (int) $parts[0] !== $uid) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->validFilter((int) $parts[1], (string) ($parts[2] ?? ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function saveFilter(int $rok, string $mesic): void
|
||||||
|
{
|
||||||
|
$uid = (int) $this->getUser()->getId();
|
||||||
|
$section = $this->getSession(self::FILTER_SESSION);
|
||||||
|
$section->userId = $uid;
|
||||||
|
$section->rok = $rok;
|
||||||
|
$section->mesic = $mesic;
|
||||||
|
|
||||||
|
$this->getHttpResponse()->setCookie(
|
||||||
|
self::FILTER_COOKIE,
|
||||||
|
$uid . ':' . $rok . ':' . $mesic,
|
||||||
|
'1 year',
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
'Lax'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{rok: int, mesic: string}|null
|
||||||
|
*/
|
||||||
|
private function validFilter(int $rok, string $mesic): ?array
|
||||||
|
{
|
||||||
|
if ($rok < 2000 || $rok > 2100) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
'rok' => $rok,
|
||||||
|
'mesic' => $this->normalizeMesic($mesic),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -30,31 +30,30 @@
|
||||||
|
|
||||||
<!-- Filtrační lišta (Rok / Měsíc) -->
|
<!-- Filtrační lišta (Rok / Měsíc) -->
|
||||||
<div class="card p-3 mb-4 border-0 shadow-sm bg-light">
|
<div class="card p-3 mb-4 border-0 shadow-sm bg-light">
|
||||||
<form method="get" class="row g-2 align-items-center">
|
<form n:attr="method => 'get', action => $presenter->link('this', ['rok' => null, 'mesic' => null])" class="row g-2 align-items-center">
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<label class="col-form-label fw-bold">Filtr roku/měsíce:</label>
|
<label class="col-form-label fw-bold">Filtr roku/měsíce:</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<select name="rok" class="form-select form-select-sm" onchange="this.form.submit()">
|
<select name="rok" class="form-select form-select-sm" onchange="this.form.submit()">
|
||||||
<option value="2026" {if ($vybranyRok ?? date('Y')) == 2026}selected{/if}>2026</option>
|
<option n:foreach="$roky as $r" value="{$r}" {if $selectedRok == $r}selected{/if}>{$r}</option>
|
||||||
<option value="2025" {if ($vybranyRok ?? date('Y')) == 2025}selected{/if}>2025</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<select name="mesic" class="form-select form-select-sm" onchange="this.form.submit()">
|
<select name="mesic" class="form-select form-select-sm" onchange="this.form.submit()">
|
||||||
<option value="">-- Všechny měsíce --</option>
|
<option value="" {if $selectedMesic === ''}selected{/if}>-- Všechny měsíce --</option>
|
||||||
<option value="1" {if ($vybranyMesic ?? '') == '1'}selected{/if}>Leden</option>
|
<option value="1" {if $selectedMesic == '1'}selected{/if}>Leden</option>
|
||||||
<option value="2" {if ($vybranyMesic ?? '') == '2'}selected{/if}>Únor</option>
|
<option value="2" {if $selectedMesic == '2'}selected{/if}>Únor</option>
|
||||||
<option value="3" {if ($vybranyMesic ?? '') == '3'}selected{/if}>Březen</option>
|
<option value="3" {if $selectedMesic == '3'}selected{/if}>Březen</option>
|
||||||
<option value="4" {if ($vybranyMesic ?? '') == '4'}selected{/if}>Duben</option>
|
<option value="4" {if $selectedMesic == '4'}selected{/if}>Duben</option>
|
||||||
<option value="5" {if ($vybranyMesic ?? '') == '5'}selected{/if}>Květen</option>
|
<option value="5" {if $selectedMesic == '5'}selected{/if}>Květen</option>
|
||||||
<option value="6" {if ($vybranyMesic ?? '') == '6'}selected{/if}>Červen</option>
|
<option value="6" {if $selectedMesic == '6'}selected{/if}>Červen</option>
|
||||||
<option value="7" {if ($vybranyMesic ?? '') == '7'}selected{/if}>Červenec</option>
|
<option value="7" {if $selectedMesic == '7'}selected{/if}>Červenec</option>
|
||||||
<option value="8" {if ($vybranyMesic ?? '') == '8'}selected{/if}>Srpen</option>
|
<option value="8" {if $selectedMesic == '8'}selected{/if}>Srpen</option>
|
||||||
<option value="9" {if ($vybranyMesic ?? '') == '9'}selected{/if}>Září</option>
|
<option value="9" {if $selectedMesic == '9'}selected{/if}>Září</option>
|
||||||
<option value="10" {if ($vybranyMesic ?? '') == '10'}selected{/if}>Říjen</option>
|
<option value="10" {if $selectedMesic == '10'}selected{/if}>Říjen</option>
|
||||||
<option value="11" {if ($vybranyMesic ?? '') == '11'}selected{/if}>Listopad</option>
|
<option value="11" {if $selectedMesic == '11'}selected{/if}>Listopad</option>
|
||||||
<option value="12" {if ($vybranyMesic ?? '') == '12'}selected{/if}>Prosinec</option>
|
<option value="12" {if $selectedMesic == '12'}selected{/if}>Prosinec</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue