Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,6 @@ config/local.neon
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.idea/

bin/objednavky
bin/objednavky
45 changes: 45 additions & 0 deletions app/Form/InvoiceForm/InvoiceForm.latte
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{import ../../Presenters/templates/@commonBlocks.latte}

{varType ?Netvor\Invoice\Model\Entities\Invoice $invoice}

{if $invoice === null} {* We have no invoice yet, then create one. *}
<h2>Nová faktura</h2>
<div n:snippet="invoiceForm">
<form n:name="invoiceForm" class="ajax">
{include formErrors form => $form}
<div class="row g-3 mb-3">
<div class="col-auto">
<label n:name="amount" class="form-label">Částka</label>
<input n:name="amount" class="form-control">
{include inputErrors input => $form[amount]}
</div>
<div class="col-auto">
<label n:name="issueDate" class="form-label">Datum vystavení</label>
<input n:name="issueDate" class="form-control">
{include inputErrors input => $form[issueDate]}
</div>
<div class="col-auto">
<label n:name="dueDate" class="form-label">Datum splatnosti</label>
<input n:name="dueDate" class="form-control">
{include inputErrors input => $form[dueDate]}
</div>
</div>
<button n:name="submit" class="btn btn-primary">Přidat novou fakturu</button>
</form>
</div>
{else} {* We have invoice, add payment if wanted. *}
<h2>Přidat platbu k faktuře {$invoice->getId()}</h2>
<div n:snippet="paymentForm">
<form n:name="paymentForm" class="ajax">
{include formErrors form => $form}
<div class="row g-3 mb-3">
<div class="col-auto">
<label n:name="amount" class="form-label">Částka</label>
<input n:name="amount" class="form-control">
{include inputErrors input => $form[amount]}
</div>
</div>
<button n:name="submit" class="btn btn-primary">Přidat platbu</button>
</form>
</div>
{/if}
183 changes: 183 additions & 0 deletions app/Form/InvoiceForm/InvoiceForm.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
<?php

declare(strict_types=1);

namespace Netvor\Invoice\Form\InvoiceForm;

use DateTimeImmutable;
use Money\Money;
use Nette\Application\AbortException;
use Nette\Application\UI\Control;
use Nette\Application\UI\Form;
use Nette\Application\UI\Template;
use Nette\Forms\Controls\TextInput;
use Nette\Utils\Validators;
use Netvor\Invoice\Model\Entities\Client;
use Netvor\Invoice\Model\Entities\Invoice;
use Netvor\Invoice\Model\Entities\Payment;
use Netvor\Invoice\Model\InvoiceService;
use stdClass;

/**
* @property-read Template $template
*/
class InvoiceForm extends Control
{
public function __construct(
private Client $client,
private ?Invoice $invoice,
private InvoiceService $invoiceService,
) {
}


public function render(): void
{
$this->template->setFile(__DIR__ . '/InvoiceForm.latte');
$this->template->invoice = $this->invoice;
$this->template->render();
}


public function createComponentPaymentForm(): Form
{
$form = new Form;
$form->addProtection('Vaše relace vypršela. Vraťte se na domovskou stránku a zkuste to znovu.');

$form->addText('amount')
->setRequired('Zadejte prosím částku.');

$form->addHidden('invoiceId', $this->invoice?->getId() ?? null)
->setRequired();
$form->addSubmit('submit');

$form->onValidate[] = [$this, 'paymentFormValidate'];
$form->onSuccess[] = [$this, 'paymentFormSuccess'];
$form->onError[] = function (): void {
if ($this->getPresenter()->isAjax() === true) {
$this->redrawControl('paymentForm');
return;
}

$this->redirect('this');
};

return $form;
}


public function paymentFormValidate(Form $form, stdClass $data): void
{
if (Validators::isNumeric($data->amount) === false) {
/** @var TextInput $amountInput */
$amountInput = $form['amount'];
$amountInput->addError('Částka musí být validní číslo.');
}
}


public function paymentFormSuccess(Form $form, stdClass $data): void
{
$this->invoice = $this->invoiceService->get((int) $data->invoiceId);

if ($this->invoice === null) {
$form->addError('Faktura ke které se snažíte přidat platbu neexistuje.');
return;
}

$amount = Money::CZK((int) ((float) $data->amount * 100)); // TODO: currency
$unpaidAmount = $this->invoice->getUnpaidAmount();

if ((int) $amount->getAmount() > $unpaidAmount) {
/** @var TextInput $amountInput */
$amountInput = $form['amount'];
$amountInput->addError(sprintf('Částka nemůže převyšovat %dKč.', $unpaidAmount / 100));
return;
}

$this->invoiceService->addPayment(new Payment($this->invoice, $amount));
$this->invoice = null;
}


protected function createComponentInvoiceForm(): Form
{
// TODO: translate
$form = new Form;
$form->addProtection('Vaše relace vypršela. Vraťte se na domovskou stránku a zkuste to znovu.');

$form->addText('amount')
->setRequired('Zadejte prosím částku.');

$form->addText('issueDate')
->setHtmlType('date')
->setRequired('Zvolte prosím datum vytavení')
->setDefaultValue(date('Y-m-d'));

$form->addText('dueDate')
->setHtmlType('date')
->setRequired('Zvolte prosím datum splatnosti')
->setDefaultValue(date('Y-m-d'));

$form->addSubmit('submit');

$form->onSuccess[] = [$this, 'invoiceFormSuccess'];
$form->onValidate[] = [$this, 'invoiceFormValidate'];
$form->onError[] = function (): void {
if ($this->getPresenter()->isAjax() === true) {
$this->redrawControl('invoiceForm');
return;
}

$this->redirect('this');
};

return $form;
}


public function invoiceFormValidate(Form $form, stdClass $data): void
{
// TODO: translate
if (Validators::isNumeric($data->amount) === false) {
/** @var TextInput $amountInput */
$amountInput = $form['amount'];
$amountInput->addError('Částka musí být validní číslo.');
}
}


/**
* @throws AbortException
*/
public function invoiceFormSuccess(Form $form, stdClass $data): void
{
$issueDate = DateTimeImmutable::createFromFormat('Y-m-d', $data->issueDate);

if ($issueDate === false) {
/** @var TextInput $issueDateInput */
$issueDateInput = $form['issueDate'];
$issueDateInput->addError('Zadejte prosím platné datum.');
return;
}

$dueDate = DateTimeImmutable::createFromFormat('Y-m-d', $data->issueDate);

if ($dueDate === false) {
/** @var TextInput $dueDateInput */
$dueDateInput = $form['dueDate'];
$dueDateInput->addError('Zadejte prosím platné datum.');
return;
}

$amount = Money::CZK((int) ((float) $data->amount * 100)); // TODO: currency
$this->invoiceService->create($this->client, $amount, $issueDate, $dueDate);

if ($this->getPresenter()->isAjax() === false) {
$this->redirect('this');
}

$form->reset();
$this->redrawControl('invoiceForm');
}
}
13 changes: 13 additions & 0 deletions app/Form/InvoiceForm/InvoiceFormFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Netvor\Invoice\Form\InvoiceForm;

use Netvor\Invoice\Model\Entities\Client;
use Netvor\Invoice\Model\Entities\Invoice;

interface InvoiceFormFactory
{
public function create(Client $client, ?Invoice $invoice = null): InvoiceForm;
}
4 changes: 2 additions & 2 deletions app/Mails/templates/invoice.latte
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@
{block title}Nová faktura{/block}

{block content}
<p>Částka: {$invoice->amount|number:2, ',', ' '}&nbsp;Kč</p>
<p>Datum vystavení: {$invoice->issueDate|date:'j. n. Y'}</p>
<p>Částka: {$invoice->getAmount()->getAmount() / 100|number:2, ',', ' '}&nbsp;Kč</p>
<p>Datum vystavení: {$invoice->getIssueDate()|date:'j. n. Y'}</p>
22 changes: 22 additions & 0 deletions app/Model/ARESRegistrySubjectFinder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace Netvor\Invoice\Model;

use Netvor\Invoice\Model\DTO\Subject;

/**
* Best would be to have this class in custom composer package, to make it reusable
*/
class ARESRegistrySubjectFinder implements IRegistrySubjectFinder
{
public function getByIdentificationNumber(string $identificationNumber): ?Subject
{
// TODO: implement
// just to show, that there needs to be interface first, then implementation
// which returns DTO instead of array or smthing

return new Subject;
}
}
10 changes: 10 additions & 0 deletions app/Model/DTO/Subject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

declare(strict_types=1);

namespace Netvor\Invoice\Model\DTO;

class Subject
{
// not implemented, just to show the way
}
Loading