add subtotal and payment date to invoices (#2450)
This commit is contained in:
@@ -17,6 +17,7 @@ use App\Export\Spreadsheet\AnnotatedObjectExporter;
|
||||
use App\Export\Spreadsheet\Writer\BinaryFileResponseWriter;
|
||||
use App\Export\Spreadsheet\Writer\XlsxWriter;
|
||||
use App\Form\InvoiceDocumentUploadForm;
|
||||
use App\Form\InvoicePaymentDateForm;
|
||||
use App\Form\InvoiceTemplateForm;
|
||||
use App\Form\Toolbar\InvoiceArchiveForm;
|
||||
use App\Form\Toolbar\InvoiceToolbarForm;
|
||||
@@ -228,10 +229,22 @@ final class InvoiceController extends AbstractController
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route(path="/change-status/{id}/{status}", name="admin_invoice_status", methods={"GET"})
|
||||
* @Route(path="/change-status/{id}/{status}", name="admin_invoice_status", methods={"GET", "POST"})
|
||||
*/
|
||||
public function changeStatusAction(Invoice $invoice, string $status): Response
|
||||
public function changeStatusAction(Invoice $invoice, string $status, Request $request): Response
|
||||
{
|
||||
if ($status === Invoice::STATUS_PAID) {
|
||||
$form = $this->createPaymentDateForm($invoice, $request);
|
||||
$form->handleRequest($request);
|
||||
|
||||
if (!$form->isSubmitted() || !$form->isValid()) {
|
||||
return $this->render('invoice/payment_date_edit.html.twig', [
|
||||
'invoice' => $invoice,
|
||||
'form' => $form->createView()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$this->service->changeInvoiceStatus($invoice, $status);
|
||||
$this->flashSuccess('action.update.success');
|
||||
@@ -512,4 +525,17 @@ final class InvoiceController extends AbstractController
|
||||
'method' => 'POST'
|
||||
]);
|
||||
}
|
||||
|
||||
private function createPaymentDateForm(Invoice $invoice, Request $request): FormInterface
|
||||
{
|
||||
if (null === $invoice->getPaymentDate()) {
|
||||
$invoice->setPaymentDate($this->getDateTimeFactory()->createDateTime());
|
||||
}
|
||||
|
||||
return $this->createForm(InvoicePaymentDateForm::class, $invoice, [
|
||||
'action' => $request->getUri(),
|
||||
'method' => 'POST',
|
||||
'timezone' => $this->getDateTimeFactory()->getTimezone()->getName(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,11 @@ use Symfony\Component\Validator\Constraints as Assert;
|
||||
* @UniqueEntity("invoiceNumber")
|
||||
* @UniqueEntity("invoiceFilename")
|
||||
*
|
||||
* @Exporter\Order({"id", "createdAt", "invoiceNumber", "status", "customer", "total", "tax", "currency", "vat", "dueDays", "dueDate", "user", "invoiceFilename"})
|
||||
* @Exporter\Order({"id", "createdAt", "invoiceNumber", "status", "customer", "subtotal", "total", "tax", "currency", "vat", "dueDays", "dueDate", "paymentDate", "user", "invoiceFilename"})
|
||||
* @Exporter\Expose("customer", label="label.customer", exp="object.getCustomer() === null ? null : object.getCustomer().getName()")
|
||||
* @Exporter\Expose("dueDate", label="invoice.due_days", type="datetime", exp="object.getDueDate() === null ? null : object.getDueDate()")
|
||||
* @Exporter\Expose("user", label="label.username", type="string", exp="object.getUser() === null ? null : object.getUser().getDisplayName()")
|
||||
* @Exporter\Expose("paymentDate", label="invoice.payment_date", type="date", exp="object.getPaymentDate() === null ? null : object.getPaymentDate()")
|
||||
*/
|
||||
class Invoice
|
||||
{
|
||||
@@ -172,6 +173,13 @@ class Invoice
|
||||
*/
|
||||
private $localized = false;
|
||||
|
||||
/**
|
||||
* @var \DateTime
|
||||
*
|
||||
* @ORM\Column(name="payment_date", type="date", nullable=true)
|
||||
*/
|
||||
private $paymentDate;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
@@ -265,6 +273,7 @@ class Invoice
|
||||
|
||||
public function setIsNew(): Invoice
|
||||
{
|
||||
$this->setPaymentDate(null);
|
||||
$this->status = self::STATUS_NEW;
|
||||
|
||||
return $this;
|
||||
@@ -277,6 +286,7 @@ class Invoice
|
||||
|
||||
public function setIsPending(): Invoice
|
||||
{
|
||||
$this->setPaymentDate(null);
|
||||
$this->status = self::STATUS_PENDING;
|
||||
|
||||
return $this;
|
||||
@@ -318,4 +328,25 @@ class Invoice
|
||||
{
|
||||
return $this->invoiceFilename;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Exporter\Expose(label="invoice.subtotal", type="float", name="subtotal")
|
||||
* @return float|null
|
||||
*/
|
||||
public function getSubtotal(): ?float
|
||||
{
|
||||
return $this->total - $this->tax;
|
||||
}
|
||||
|
||||
public function getPaymentDate(): ?\DateTime
|
||||
{
|
||||
return $this->paymentDate;
|
||||
}
|
||||
|
||||
public function setPaymentDate(?\DateTime $paymentDate): Invoice
|
||||
{
|
||||
$this->paymentDate = $paymentDate;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,10 +30,10 @@ class InvoiceSubscriber extends AbstractActionsSubscriber
|
||||
return;
|
||||
}
|
||||
|
||||
if ($invoice->isNew()) {
|
||||
if ($invoice->isNew() || $invoice->isPaid()) {
|
||||
$event->addAction('invoice.pending', ['url' => $this->path('admin_invoice_status', ['id' => $invoice->getId(), 'status' => 'pending'])]);
|
||||
} elseif ($invoice->isPending()) {
|
||||
$event->addAction('invoice.paid', ['url' => $this->path('admin_invoice_status', ['id' => $invoice->getId(), 'status' => 'paid'])]);
|
||||
$event->addAction('invoice.paid', ['url' => $this->path('admin_invoice_status', ['id' => $invoice->getId(), 'status' => 'paid']), 'class' => 'modal-ajax-form']);
|
||||
}
|
||||
|
||||
$event->addAction('download', ['url' => $this->path('admin_invoice_download', ['id' => $invoice->getId()]), 'target' => '_blank']);
|
||||
|
||||
50
src/Form/InvoicePaymentDateForm.php
Normal file
50
src/Form/InvoicePaymentDateForm.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace App\Form;
|
||||
|
||||
use App\Entity\Invoice;
|
||||
use App\Form\Type\DatePickerType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class InvoicePaymentDateForm extends AbstractType
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$dateTimeOptions = [
|
||||
'model_timezone' => $options['timezone'],
|
||||
'view_timezone' => $options['timezone'],
|
||||
];
|
||||
|
||||
$builder
|
||||
->add('paymentDate', DatePickerType::class, array_merge($dateTimeOptions, [
|
||||
'label' => 'invoice.payment_date',
|
||||
'required' => true,
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function configureOptions(OptionsResolver $resolver)
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => Invoice::class,
|
||||
'timezone' => date_default_timezone_get(),
|
||||
'attr' => [
|
||||
'data-form-event' => 'kimai.invoiceUpdate'
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
40
src/Migrations/Version20210320162820.php
Normal file
40
src/Migrations/Version20210320162820.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the Kimai time-tracking app.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Update invoice with payment date
|
||||
*
|
||||
* @version 1.14
|
||||
*/
|
||||
final class Version20210320162820 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return 'Update invoice with payment date';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
$invoices = $schema->getTable('kimai2_invoices');
|
||||
$invoices->addColumn('payment_date', 'date', ['default' => null, 'notnull' => false]);
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
$invoices = $schema->getTable('kimai2_invoices');
|
||||
$invoices->dropColumn('payment_date');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user