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->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; // 1. Načteme všechny zákazníky (parametr 'vse' projde bez filtru AKTIVNI) $zakaznici = $this->zakaznikFacade->getFiltered('', 'vse'); $zakazniciPairs = []; foreach ($zakaznici as $z) { $nazev = trim(($z->PRIJMENI ?? '') . ' ' . ($z->JMENO ?? '')); if (!empty($z->IC)) { $nazev .= " (IČ: {$z->IC})"; } // Kličem musí být int $zakazniciPairs[(int) $z->ID] = $nazev; } $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; } 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'); } }