Kufrik/app/UI/Faktura/FakturaPresenter.php

239 lines
7.2 KiB
PHP

<?php
namespace App\UI\Faktura;
use App\Model\Faktura\FakturaPdf;
use App\Model\Faktura\SeznamFakturPdf;
use App\UI\BasePresenter;
use App\Model\Facade\FakturaFacade;
use Nette\Application\Attributes\Persistent;
use Nette\Application\Responses\CallbackResponse;
class FakturaPresenter extends BasePresenter
{
private const FILTER_COOKIE = 'kufrikFakturaFiltr';
private const FILTER_SESSION = 'fakturaFilter';
#[Persistent]
public ?int $rok = null;
#[Persistent]
public string $mesic = '';
public function __construct(
private FakturaFacade $fakturaFacade,
private FakturaPdf $fakturaPdf,
private SeznamFakturPdf $seznamFakturPdf,
) {
parent::__construct();
}
public function actionPdf(int $id, bool $tisk = false): void
{
$faktura = $this->fakturaFacade->getById($id);
if (!$faktura) {
$this->error('Faktura nebyla nalezena.', 404);
}
$pdf = $this->fakturaPdf->render($faktura, $this->fakturaFacade->getPolozky($id), $tisk);
$fileName = FakturaPdf::fileName((string) $faktura->CISLO);
$disposition = $tisk ? 'inline' : 'attachment';
$this->sendPdf($pdf, $fileName, $disposition);
}
/**
* Tisk seznamu faktur podle filtru rok / měsíc.
*/
public function actionSeznam(): void
{
$rok = $this->rok ?? (int) date('Y');
$mesic = $this->normalizeMesic($this->mesic);
$this->fakturaFacade->reconcileUhrady();
$faktury = $this->fakturaFacade->getFiltered($rok, $mesic);
foreach ($faktury as $faktura) {
$celkem = (float) ($faktura->CASTKA_CELKEM ?? 0);
$zaplaceno = (float) ($faktura->ZAPLACENO ?? 0);
$faktura->STAV_UHRADY = FakturaFacade::stavZCastek($celkem, $zaplaceno);
}
$pdf = $this->seznamFakturPdf->render($faktury, $rok, $mesic, autoPrint: true);
$this->sendPdf($pdf, SeznamFakturPdf::fileName($rok, $mesic), 'inline');
}
private function sendPdf(string $pdf, string $fileName, string $disposition): void
{
$this->sendResponse(new CallbackResponse(function ($httpRequest, $httpResponse) use ($pdf, $fileName, $disposition): void {
$httpResponse->setContentType('application/pdf');
$httpResponse->setHeader(
'Content-Disposition',
$disposition . '; filename="' . $fileName . '"'
);
echo $pdf;
}));
}
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
{
$rok = $this->rok ?? (int) date('Y');
$mesic = $this->normalizeMesic($this->mesic);
$this->fakturaFacade->reconcileUhrady();
$faktury = $this->fakturaFacade->getFiltered($rok, $mesic);
$celkemSum = 0;
$zbyvaSum = 0;
$neuhrazenoCount = 0;
foreach ($faktury as $f) {
$celkem = (float) ($f->CASTKA_CELKEM ?? 0);
$zaplaceno = (float) ($f->ZAPLACENO ?? 0);
$zbyva = max(0, round($celkem - $zaplaceno, 2));
$f->STAV_UHRADY = FakturaFacade::stavZCastek($celkem, $zaplaceno);
$f->ZBYVA = $zbyva;
$celkemSum += $celkem;
$zbyvaSum += $zbyva;
if ($f->STAV_UHRADY !== FakturaFacade::STAV_ZAPLACENO) {
$neuhrazenoCount++;
}
}
$this->template->faktury = $faktury;
$this->template->celkemSum = $celkemSum;
$this->template->zbyvaSum = $zbyvaSum;
$this->template->neuhrazenoCount = $neuhrazenoCount;
$this->template->dnes = date('Y-m-d');
$this->template->selectedRok = $rok;
$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),
];
}
/**
* Smazání faktury
*/
public function handleDelete(int $id): void
{
$this->fakturaFacade->delete($id);
$this->flashMessage('Faktura byla smazána.', 'info');
$this->redirect('this');
}
/**
* Kopie faktury — nové číslo, dnešní data, stejné položky; otevře editaci.
*/
public function handleDuplicate(int $id): void
{
$firmaId = (int) $this->getUser()->getIdentity()->firma_id;
try {
$novaId = $this->fakturaFacade->duplicate($id, $firmaId);
} catch (\InvalidArgumentException $e) {
$this->flashMessage($e->getMessage(), 'danger');
$this->redirect('this');
}
$this->flashMessage('Kopie faktury byla vytvořena.', 'success');
$this->redirect('FakturaEdit:edit', $novaId);
}
}