diff --git a/src/Controller/ExportController.php b/src/Controller/ExportController.php index 685d6000..0ce11099 100644 --- a/src/Controller/ExportController.php +++ b/src/Controller/ExportController.php @@ -144,6 +144,7 @@ class ExportController extends AbstractController /** * @param ExportQuery $query * @return ExportItemInterface[] + * @throws TooManyItemsExportException */ protected function getEntries(ExportQuery $query): array { diff --git a/src/Entity/Invoice.php b/src/Entity/Invoice.php index 6b9cfedc..6da5637c 100644 --- a/src/Entity/Invoice.php +++ b/src/Entity/Invoice.php @@ -37,6 +37,7 @@ class Invoice { public const STATUS_PENDING = 'pending'; public const STATUS_PAID = 'paid'; + public const STATUS_CANCELED = 'canceled'; public const STATUS_NEW = 'new'; /** @@ -306,6 +307,16 @@ class Invoice return $this; } + public function isCanceled(): bool + { + return $this->status === self::STATUS_CANCELED; + } + + public function setIsCanceled(): void + { + $this->status = self::STATUS_CANCELED; + } + public function getDueDays(): int { return $this->dueDays; diff --git a/src/EventSubscriber/Actions/InvoiceSubscriber.php b/src/EventSubscriber/Actions/InvoiceSubscriber.php index c574f9c9..10cb991e 100644 --- a/src/EventSubscriber/Actions/InvoiceSubscriber.php +++ b/src/EventSubscriber/Actions/InvoiceSubscriber.php @@ -30,12 +30,18 @@ class InvoiceSubscriber extends AbstractActionsSubscriber return; } - if ($invoice->isNew() || $invoice->isPaid()) { + if (!$invoice->isPending()) { $event->addAction('invoice.pending', ['url' => $this->path('admin_invoice_status', ['id' => $invoice->getId(), 'status' => 'pending'])]); - } elseif ($invoice->isPending()) { + } else { $event->addAction('invoice.paid', ['url' => $this->path('admin_invoice_status', ['id' => $invoice->getId(), 'status' => 'paid']), 'class' => 'modal-ajax-form']); } + if (!$invoice->isCanceled()) { + $event->addAction('invoice.cancel', ['url' => $this->path('admin_invoice_status', ['id' => $invoice->getId(), 'status' => 'canceled'])]); + } + + $event->addDivider(); + $event->addAction('download', ['url' => $this->path('admin_invoice_download', ['id' => $invoice->getId()]), 'target' => '_blank']); $event->addDelete($this->path('admin_invoice_delete', ['id' => $invoice->getId(), 'token' => $payload['token']]), false); } diff --git a/src/Invoice/ServiceInvoice.php b/src/Invoice/ServiceInvoice.php index d0f42d5b..8155a8a1 100644 --- a/src/Invoice/ServiceInvoice.php +++ b/src/Invoice/ServiceInvoice.php @@ -239,10 +239,6 @@ final class ServiceInvoice public function changeInvoiceStatus(Invoice $invoice, string $status) { - if (!\in_array($status, [Invoice::STATUS_NEW, Invoice::STATUS_PENDING, Invoice::STATUS_PAID])) { - throw new \InvalidArgumentException('Unknown invoice status'); - } - switch ($status) { case Invoice::STATUS_NEW: $invoice->setIsNew(); @@ -255,6 +251,13 @@ final class ServiceInvoice case Invoice::STATUS_PAID: $invoice->setIsPaid(); break; + + case Invoice::STATUS_CANCELED: + $invoice->setIsCanceled(); + break; + + default: + throw new \InvalidArgumentException('Unknown invoice status'); } $this->invoiceRepository->saveInvoice($invoice); diff --git a/templates/invoice/listing.html.twig b/templates/invoice/listing.html.twig index d13a4363..b6583eda 100644 --- a/templates/invoice/listing.html.twig +++ b/templates/invoice/listing.html.twig @@ -36,7 +36,7 @@ {% else %} {{ tables.datatable_header(tableName, columns, query, {}) }} {% for entry in entries %} - + {{ entry.createdAt|date_short }} {{ widgets.user_avatar(entry.user) }} {{ widgets.username(entry.user) }} {{ widgets.label_customer(entry.customer) }} diff --git a/templates/invoice/macros.html.twig b/templates/invoice/macros.html.twig index 79b029d3..6518d966 100644 --- a/templates/invoice/macros.html.twig +++ b/templates/invoice/macros.html.twig @@ -12,12 +12,16 @@ {{ widgets.label('status.pending'|trans, 'warning') }} {% elseif invoice.paid %} {{ widgets.label('status.paid'|trans, 'success') }} + {% elseif invoice.canceled %} + {{ widgets.label('status.canceled'|trans, 'gray') }} {% endif %} {% endmacro %} {% macro invoice_due_date(invoice) %} {% import "macros/widgets.html.twig" as widgets %} - {% if invoice.overdue and not invoice.paid %} + {% if invoice.canceled %} + {{ widgets.label('status.canceled'|trans, 'gray') }} + {% elseif invoice.overdue and not invoice.paid %} {{ widgets.label(invoice.dueDate|date_short, 'danger') }} {% else %} {{ widgets.label(invoice.dueDate|date_short, 'primary') }} diff --git a/translations/actions.de.xlf b/translations/actions.de.xlf index 71fa0285..386cdbf2 100644 --- a/translations/actions.de.xlf +++ b/translations/actions.de.xlf @@ -94,6 +94,10 @@ invoice.paid Rechnung bezahlt + + invoice.cancel + Rechnung stornieren + filter Daten filtern diff --git a/translations/actions.en.xlf b/translations/actions.en.xlf index ebd55b96..6ad1e50d 100644 --- a/translations/actions.en.xlf +++ b/translations/actions.en.xlf @@ -94,6 +94,10 @@ invoice.paid Invoice paid + + invoice.cancel + Cancel invoice + filter Filter data diff --git a/translations/messages.de.xlf b/translations/messages.de.xlf index baf0cdf4..17a9b6af 100644 --- a/translations/messages.de.xlf +++ b/translations/messages.de.xlf @@ -1083,6 +1083,10 @@ status.paid Bezahlt + + status.canceled + Storniert + preview.skipped_rows Überspringe Vorschau von %rows% weiteren Zeilen … diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 4f5ea917..49b4a082 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -1083,6 +1083,10 @@ status.paid Paid + + status.canceled + Canceled + preview.skipped_rows Skipped preview of %rows% more rows …