470 lines
17 KiB
PHP
470 lines
17 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;
|
|
|
|
/** @var list<object> Položky předvyplněné při kopii (ještě neuložená faktura). */
|
|
private array $kopiePolozky = [];
|
|
|
|
private ?int $ensureZakaznikId = null;
|
|
|
|
public function __construct(
|
|
private FakturaFacade $fakturaFacade,
|
|
private ZakaznikFacade $zakaznikFacade
|
|
) {
|
|
parent::__construct();
|
|
}
|
|
|
|
public function actionNew(): void
|
|
{
|
|
$this->id = null;
|
|
$this->setView('edit');
|
|
|
|
$firmaId = (int) $this->getUser()->getIdentity()->firma_id;
|
|
$dalsi = $this->fakturaFacade->getNextCislo($firmaId);
|
|
|
|
$this['fakturaForm']->setDefaults([
|
|
'CISLO' => $dalsi['cislo'],
|
|
'CISLO_ABS' => $dalsi['cisloAbs'],
|
|
'FORMA_UHRADY' => 1,
|
|
'DATUM_SPLATNOSTI' => (new \DateTimeImmutable('today'))
|
|
->modify('+' . $dalsi['splatnostDny'] . ' days')
|
|
->format('Y-m-d'),
|
|
] + $this->fakturaFacade->getDodavatelDefaults($firmaId));
|
|
}
|
|
|
|
/**
|
|
* Kopie existující faktury jako nová (všechna pole editovatelná, uloží se až po uložení).
|
|
*/
|
|
public function actionCopy(int $id): void
|
|
{
|
|
$this->id = null;
|
|
$this->setView('edit');
|
|
|
|
$zdroj = $this->fakturaFacade->getById($id);
|
|
if (!$zdroj) {
|
|
$this->flashMessage('Faktura nebyla nalezena.', 'danger');
|
|
$this->redirect('Faktura:default');
|
|
}
|
|
|
|
$firmaId = (int) $this->getUser()->getIdentity()->firma_id;
|
|
$dnes = new \DateTimeImmutable('today');
|
|
$dalsi = $this->fakturaFacade->getNextCislo($firmaId, $dnes);
|
|
$datumVystaveni = $dnes->format('Y-m-d');
|
|
|
|
if ($zdroj->ZAKAZNIK !== null) {
|
|
$this->ensureZakaznikId = (int) $zdroj->ZAKAZNIK;
|
|
}
|
|
|
|
$this['fakturaForm']->setDefaults([
|
|
'ZAKAZNIK_ID' => $this->ensureZakaznikId,
|
|
'CISLO' => $dalsi['cislo'],
|
|
'CISLO_ABS' => $dalsi['cisloAbs'],
|
|
'FORMA_UHRADY' => (int) ($zdroj->FORMA_UHRADY ?? 1),
|
|
'DATUM_VYSTAVENI' => $datumVystaveni,
|
|
'DATUM_SPLATNOSTI' => $dnes
|
|
->modify('+' . $dalsi['splatnostDny'] . ' days')
|
|
->format('Y-m-d'),
|
|
'DATUM_DUZP' => $datumVystaveni,
|
|
'CINNOSTI' => $zdroj->CINNOSTI,
|
|
'O_PRAJM' => $zdroj->O_PRAJM,
|
|
'O_ULICE' => $zdroj->O_ULICE,
|
|
'O_MESTO' => $zdroj->O_MESTO,
|
|
'O_PSC' => $zdroj->O_PSC,
|
|
'O_IC' => $zdroj->O_IC,
|
|
'O_DIC' => $zdroj->O_DIC,
|
|
] + $this->fakturaFacade->getDodavatelDefaults($firmaId));
|
|
|
|
$this->kopiePolozky = $this->fakturaFacade->getPolozky($id);
|
|
}
|
|
|
|
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;
|
|
$this->ensureZakaznikId = (int) $faktura->ZAKAZNIK;
|
|
}
|
|
$defaults['FORMA_UHRADY'] = (int) ($faktura->FORMA_UHRADY ?? 1);
|
|
|
|
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 renderNew(): void
|
|
{
|
|
$this->prepareEditTemplate();
|
|
}
|
|
|
|
public function renderCopy(): void
|
|
{
|
|
$this->prepareEditTemplate();
|
|
}
|
|
|
|
public function renderEdit(?int $id = null): void
|
|
{
|
|
$this->prepareEditTemplate();
|
|
}
|
|
|
|
private function prepareEditTemplate(): void
|
|
{
|
|
$this->template->isEdit = (bool) $this->id;
|
|
|
|
$polozky = $this->id
|
|
? $this->fakturaFacade->getPolozky($this->id)
|
|
: $this->kopiePolozky;
|
|
$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');
|
|
}
|
|
}
|
|
|
|
$jsonFlags = JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_THROW_ON_ERROR;
|
|
$this->template->katalogPolozekJson = json_encode(
|
|
$this->fakturaFacade->getKatalogPolozek(),
|
|
$jsonFlags
|
|
);
|
|
$this->template->zakazniciDetailJson = json_encode(
|
|
$this->zakazniciDetailProJs(),
|
|
$jsonFlags
|
|
);
|
|
$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');
|
|
$zakaznikId = $this->ensureZakaznikId ?? 0;
|
|
if ($zakaznikId) {
|
|
$uzJeVSeznamu = false;
|
|
foreach ($zakaznici as $z) {
|
|
if ((int) $z->ID === $zakaznikId) {
|
|
$uzJeVSeznamu = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!$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->addSelect('FORMA_UHRADY', 'Forma úhrady:', [
|
|
1 => 'převodem',
|
|
2 => 'hotově',
|
|
])->setDefaultValue(1);
|
|
|
|
$form->addText('DATUM_DUZP', 'Datum UZP:')
|
|
->setHtmlType('date');
|
|
|
|
// Detailní informace — dodavatel
|
|
$form->addText('D_PRAJM', 'Dodavatel:')->setMaxLength(511);
|
|
$form->addText('D_ULICE', 'Ulice:')->setMaxLength(50);
|
|
$form->addText('D_PSC', 'PSČ:')->setMaxLength(50);
|
|
$form->addText('D_MESTO', 'Město:')->setMaxLength(50);
|
|
$form->addText('D_IC', 'IČ:')->setMaxLength(8);
|
|
$form->addText('D_DIC', 'DIČ:')->setMaxLength(12);
|
|
$form->addText('D_TELEFON', 'Telefon:')->setMaxLength(20);
|
|
$form->addText('D_EMAIL', 'E-mail:')->setMaxLength(100);
|
|
$form->addText('D_BANKA', 'Bankovní účet:')->setMaxLength(100);
|
|
$form->addText('D_WEB', 'Web:')->setMaxLength(100);
|
|
|
|
// Detailní informace — odběratel
|
|
$form->addText('O_PRAJM', 'Odběratel:')->setMaxLength(511);
|
|
$form->addText('O_ULICE', 'Ulice:')->setMaxLength(50);
|
|
$form->addText('O_PSC', 'PSČ:')->setMaxLength(5);
|
|
$form->addText('O_MESTO', 'Město:')->setMaxLength(50);
|
|
$form->addText('O_IC', 'IČ:')->setMaxLength(8);
|
|
$form->addText('O_DIC', 'DIČ:')->setMaxLength(10);
|
|
|
|
$form->addTextArea('CINNOSTI', 'Činnosti / Popis plnění:');
|
|
|
|
$form->addSubmit('save', 'Uložit fakturu')
|
|
->setHtmlAttribute('class', 'btn btn-primary');
|
|
|
|
$form->onSuccess[] = [$this, 'fakturaFormSucceeded'];
|
|
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* @return array<string, array{nazev: string, ulice: ?string, psc: ?string, mesto: ?string, ic: ?string, dic: ?string}>
|
|
*/
|
|
private function zakazniciDetailProJs(): array
|
|
{
|
|
$map = [];
|
|
foreach ($this->zakaznikFacade->getFiltered('', 'aktivni') as $z) {
|
|
$map[(string) $z->ID] = [
|
|
'nazev' => trim(($z->PRIJMENI ?? '') . ' ' . ($z->JMENO ?? '')),
|
|
'ulice' => $z->ULICE,
|
|
'psc' => $z->PSC,
|
|
'mesto' => $z->MESTO,
|
|
'ic' => $z->IC,
|
|
'dic' => $z->DIC,
|
|
];
|
|
}
|
|
|
|
$zakaznikId = $this->ensureZakaznikId ?? 0;
|
|
if ($zakaznikId && !isset($map[(string) $zakaznikId])) {
|
|
$stavajici = $this->zakaznikFacade->getById($zakaznikId);
|
|
if ($stavajici) {
|
|
$map[(string) $zakaznikId] = [
|
|
'nazev' => trim(($stavajici->PRIJMENI ?? '') . ' ' . ($stavajici->JMENO ?? '')),
|
|
'ulice' => $stavajici->ULICE,
|
|
'psc' => $stavajici->PSC,
|
|
'mesto' => $stavajici->MESTO,
|
|
'ic' => $stavajici->IC,
|
|
'dic' => $stavajici->DIC,
|
|
];
|
|
}
|
|
}
|
|
|
|
return $map;
|
|
}
|
|
|
|
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');
|
|
}
|
|
} |