Kufrik/app/UI/FakturaEdit/FakturaEditPresenter.php

336 lines
12 KiB
PHP

<?php
namespace App\UI\FakturaEdit;
use App\UI\BasePresenter;
use App\Model\Facade\FakturaFacade;
use App\Model\Facade\ZakaznikFacade;
use Nette\Application\UI\Form;
class FakturaEditPresenter extends BasePresenter
{
/** @persistent */
public ?int $id = null;
public function __construct(
private FakturaFacade $fakturaFacade,
private ZakaznikFacade $zakaznikFacade
) {
parent::__construct();
}
public function actionNew(): void
{
$this->id = null;
$this->setView('edit');
$firmaId = $this->getUser()->getIdentity()->firma_id;
$dalsi = $this->fakturaFacade->getNextCislo($firmaId);
$this['fakturaForm']->setDefaults([
'CISLO' => $dalsi['cislo'],
'CISLO_ABS' => $dalsi['cisloAbs'],
'DATUM_SPLATNOSTI' => (new \DateTimeImmutable('today'))
->modify('+' . $dalsi['splatnostDny'] . ' days')
->format('Y-m-d'),
]);
}
public function actionEdit(int $id): void
{
$this->id = $id;
$faktura = $this->fakturaFacade->getById($id);
if (!$faktura) {
$this->flashMessage('Faktura nebyla nalezena.', 'danger');
$this->redirect('Faktura:default');
}
$defaults = $faktura->toArray();
// Explicitně přiřadíme ID zákazníka
if ($faktura->ZAKAZNIK !== null) {
$defaults['ZAKAZNIK_ID'] = (int) $faktura->ZAKAZNIK;
}
if ($faktura->DATUM_VYSTAVENI) {
$defaults['DATUM_VYSTAVENI'] = $faktura->DATUM_VYSTAVENI->format('Y-m-d');
}
if ($faktura->DATUM_SPLATNOSTI) {
$defaults['DATUM_SPLATNOSTI'] = $faktura->DATUM_SPLATNOSTI->format('Y-m-d');
}
if ($faktura->DATUM_DUZP) {
$defaults['DATUM_DUZP'] = $faktura->DATUM_DUZP->format('Y-m-d');
}
// 1. Nastavení výchozích hodnot
$this['fakturaForm']->setDefaults($defaults);
// Společný CSS styl pro zablokované / zešedlé prvky (odpovídá Bootstrap disabled vzhledu)
$disabledStyle = 'pointer-events: none; background-color: #e9ecef; opacity: 1;';
// 2. Zamknutí prvků při editaci (Odběratel, Číslo faktury, Datum vystavení)
$this['fakturaForm']['ZAKAZNIK_ID']
->setHtmlAttribute('style', $disabledStyle)
->setHtmlAttribute('tabindex', '-1');
$this['fakturaForm']['CISLO']
->setHtmlAttribute('readonly', true)
->setHtmlAttribute('style', $disabledStyle)
->setHtmlAttribute('tabindex', '-1');
$this['fakturaForm']['DATUM_VYSTAVENI']
->setHtmlAttribute('readonly', true)
->setHtmlAttribute('style', $disabledStyle)
->setHtmlAttribute('tabindex', '-1');
}
public function renderEdit(?int $id = null): void
{
$this->template->isEdit = (bool) $this->id;
$polozky = $this->id ? $this->fakturaFacade->getPolozky($this->id) : [];
$platby = $this->id ? $this->fakturaFacade->getPlatby($this->id) : [];
$celkem = 0.0;
foreach ($polozky as $polozka) {
$celkem += (float) $polozka->CENA;
}
$zaplaceno = 0.0;
foreach ($platby as $platba) {
$zaplaceno += (float) $platba->CASTKA;
}
$splatnostIso = date('Y-m-d');
if ($this->id) {
$faktura = $this->fakturaFacade->getById($this->id);
if ($faktura && $faktura->DATUM_SPLATNOSTI) {
$splatnostIso = $faktura->DATUM_SPLATNOSTI->format('Y-m-d');
}
}
$this->template->katalogPolozekJson = json_encode(
$this->fakturaFacade->getKatalogPolozek(),
JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_THROW_ON_ERROR
);
$this->template->polozky = $polozky;
$this->template->platby = $platby;
$this->template->celkemFaktury = $celkem;
$this->template->zaplaceno = $zaplaceno;
$zbyva = max(0, round($celkem - $zaplaceno, 2));
$this->template->zbyva = $zbyva;
$this->template->zbyvaInput = $zbyva > 0 ? number_format($zbyva, 2, '.', '') : '';
$this->template->stavUhrady = FakturaFacade::stavZCastek($celkem, $zaplaceno);
$this->template->splatnostIso = $splatnostIso;
}
public function handleSmazatPlatbu(int $platbaId): void
{
if ($this->fakturaFacade->deletePlatba($platbaId) === null) {
$this->flashMessage('Platbu se nepodařilo smazat.', 'danger');
} else {
$this->flashMessage('Platba byla smazána.', 'info');
}
$this->redirect('this');
}
protected function createComponentFakturaForm(): Form
{
$form = new Form;
$zakaznici = $this->zakaznikFacade->getFiltered('', 'aktivni');
if ($this->id) {
$faktura = $this->fakturaFacade->getById($this->id);
$zakaznikId = $faktura ? (int) $faktura->ZAKAZNIK : 0;
$uzJeVSeznamu = false;
foreach ($zakaznici as $z) {
if ((int) $z->ID === $zakaznikId) {
$uzJeVSeznamu = true;
break;
}
}
if ($zakaznikId && !$uzJeVSeznamu) {
$stavajici = $this->zakaznikFacade->getById($zakaznikId);
if ($stavajici) {
$zakaznici[] = $stavajici;
}
}
}
$zakazniciPairs = [];
foreach ($zakaznici as $z) {
$zakazniciPairs[(int) $z->ID] = $this->nazevZakaznika($z);
}
$form->addSelect('ZAKAZNIK_ID', 'Odběratel:', $zakazniciPairs)
->setPrompt('-- Vyberte zákazníka --')
->setRequired('Vyberte odběratele.');
$form->addText('CISLO', 'Číslo faktury:')
->setDefaultValue(date('Y') . '0001');
$form->addHidden('CISLO_ABS');
$form->addText('DATUM_VYSTAVENI', 'Datum vystavení:')
->setHtmlType('date')
->setDefaultValue(date('Y-m-d'));
$splatnostDny = 15;
$firmaId = $this->getUser()->getIdentity()->firma_id ?? null;
if ($firmaId) {
$splatnostDny = $this->fakturaFacade->getNastaveni((int) $firmaId)['splatnostDny'];
}
$form->addText('DATUM_SPLATNOSTI', 'Datum splatnosti:')
->setHtmlType('date')
->setDefaultValue((new \DateTimeImmutable('today'))->modify('+' . $splatnostDny . ' days')->format('Y-m-d'))
->setRequired('Zadejte datum splatnosti.');
$form->addText('DATUM_DUZP', 'Datum UZP:')
->setHtmlType('date');
$form->addTextArea('CINNOSTI', 'Činnosti / Popis plnění:');
$form->addSubmit('save', 'Uložit fakturu')
->setHtmlAttribute('class', 'btn btn-primary');
$form->onSuccess[] = [$this, 'fakturaFormSucceeded'];
return $form;
}
private function nazevZakaznika(object $zakaznik): string
{
$nazev = trim(($zakaznik->PRIJMENI ?? '') . ' ' . ($zakaznik->JMENO ?? ''));
$doplnek = [];
if (!empty($zakaznik->MESTO)) {
$doplnek[] = (string) $zakaznik->MESTO;
}
if (!empty($zakaznik->IC)) {
$doplnek[] = 'IČ: ' . $zakaznik->IC;
}
if ($doplnek) {
$nazev .= ' (' . implode(', ', $doplnek) . ')';
}
return $nazev;
}
public function fakturaFormSucceeded(Form $form, \stdClass $data): void
{
$firmaId = $this->getUser()->getIdentity()->firma_id;
$httpRequest = $this->getHttpRequest();
// 1. Uložení hlavičky faktury
$fakturaId = $this->fakturaFacade->saveFaktura((array) $data, $this->id, $firmaId);
// 2. Získání položek z POSTu (z dynamického formuláře z Latte/JS)
$polozkyRaw = $httpRequest->getPost('polozky', []);
// 3. Uložení položek s automatickým výpočtem PORADI a celkové ceny
$this->fakturaFacade->savePolozky($fakturaId, $polozkyRaw, $firmaId);
$this->fakturaFacade->syncStav($fakturaId);
$this->flashMessage(
$this->id ? 'Faktura byla úspěšně upravena.' : 'Nová faktura byla vystavena.',
'success'
);
$this->redirect('Faktura:default');
}
protected function createComponentPlatbyForm(): Form
{
$form = new Form;
$platby = $form->addContainer('platby');
if ($this->id) {
foreach ($this->fakturaFacade->getPlatby($this->id) as $platba) {
$datum = $platba->DATUM instanceof \DateTimeInterface
? $platba->DATUM->format('Y-m-d')
: substr((string) $platba->DATUM, 0, 10);
$row = $platby->addContainer((string) $platba->ID);
$row->addText('castka')
->setHtmlType('number')
->setHtmlAttribute('step', '0.01')
->setHtmlAttribute('min', '0.01')
->setDefaultValue(number_format((float) $platba->CASTKA, 2, '.', ''))
->setRequired('Zadejte částku platby.')
->addRule(Form::FLOAT, 'Částka musí být číslo.')
->addRule(Form::MIN, 'Částka musí být větší než 0.', 0.01);
$row->addText('datum')
->setHtmlType('date')
->setDefaultValue($datum)
->setRequired('Zadejte datum platby.');
$row->addText('poznamka')
->setDefaultValue((string) ($platba->POZNAMKA ?? ''));
}
}
$nova = $form->addContainer('nova');
$nova->addText('castka')
->setHtmlType('number')
->setHtmlAttribute('step', '0.01')
->setHtmlAttribute('min', '0.01')
->setHtmlAttribute('id', 'edit-platba-castka')
->setHtmlAttribute('placeholder', 'Částka')
->addCondition(Form::FILLED)
->addRule(Form::FLOAT, 'Částka musí být číslo.')
->addRule(Form::MIN, 'Částka musí být větší než 0.', 0.01);
$nova->addText('datum')
->setHtmlType('date')
->setHtmlAttribute('id', 'edit-platba-datum')
->setDefaultValue(date('Y-m-d'));
$nova->addText('poznamka')
->setHtmlAttribute('id', 'edit-platba-poznamka');
$form->addSubmit('save', 'Uložit platby')
->setHtmlAttribute('class', 'btn btn-success');
$form->onSuccess[] = $this->platbyFormSucceeded(...);
return $form;
}
public function platbyFormSucceeded(Form $form, array $data): void
{
if (!$this->id) {
$form->addError('Platby lze zadat až u uložené faktury.');
return;
}
try {
foreach ($data['platby'] ?? [] as $platbaId => $platba) {
$this->fakturaFacade->updatePlatba(
(int) $platbaId,
(float) $platba['castka'],
new \DateTimeImmutable((string) $platba['datum']),
(string) ($platba['poznamka'] ?? '')
);
}
$novaCastka = trim((string) ($data['nova']['castka'] ?? ''));
if ($novaCastka !== '') {
$datumText = trim((string) ($data['nova']['datum'] ?? ''));
$datum = $datumText !== ''
? new \DateTimeImmutable($datumText)
: new \DateTimeImmutable('today');
$this->fakturaFacade->addPlatba(
$this->id,
(float) $novaCastka,
$datum,
(string) ($data['nova']['poznamka'] ?? '')
);
} else {
$this->fakturaFacade->syncStav($this->id);
}
} catch (\Throwable $e) {
$form->addError($e->getMessage());
return;
}
$this->flashMessage('Platby byly uloženy.', 'success');
$this->redirect('this');
}
}