<?php
namespace App\Controller;
use App\Entity\Invoice;
use App\Entity\InvoiceStatus;
use App\Form\ClientFilterType;
use App\Form\InvoiceType;
use App\Generator\InvoicePdfGenerator;
use App\Generator\PdfGenerator;
use App\Helper\UserHelper;
use App\Repository\InvoiceRepository;
use App\Security\Voter\InvoiceVoter;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Process\Process;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Workflow\Workflow;
use Symfony\Component\Workflow\WorkflowInterface;
#[Route('/invoice')]
class InvoiceController extends AbstractController
{
#[Route('/', name: 'app_invoice_index', methods: ['GET'])]
public function index(Request $request, InvoiceRepository $invoiceRepository, WorkflowInterface $invoiceStateMachine): Response
{
$form = $this->createForm(ClientFilterType::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$invoices = $invoiceRepository->findByFilter(
$data['client'],
$data['dateFrom'],
$data['dateTo'],
$data['datePaidFrom'],
$data['datePaidTo'],
$data['status'],
);
} else {
$invoices = $invoiceRepository->findAll();
}
$paidInvoices = array_filter($invoices, fn(Invoice $invoice) => $invoice->getStatus() === 'paid');
$byMonths = [];
for ($i = 1; $i <= 12; $i++) {
$monthName = date('F', mktime(0, 0, 0, $i, 1, 2000));
$byMonths[$monthName] = ['ht' => 0,'vat' => 0,];
}
$toPayVat = $toPayUrssaf = 0;
foreach ($paidInvoices as $invoice) {
if ($invoice->getPaymentDate() === null) continue;
$byMonths[$invoice->getPaymentDate()->format('F')]['ht'] += $invoice->getTotalHT();
$byMonths[$invoice->getPaymentDate()->format('F')]['vat'] += $invoice->getTotalVAT();
$toPayVat += $invoice->isVatPaid() ? 0 : $invoice->getTotalVAT();
$toPayUrssaf += $invoice->isUrssafPaid() ? 0 : 0.235 * $invoice->getTotalHT();
}
return $this->render('invoice/index.html.twig', [
'invoices' => $invoices,
'form_filter' => $form->createView(),
'total_ht_all' => array_sum(array_map(fn(Invoice $invoice) => $invoice->getTotalHT(), $invoices)),
'total_ttc_all' => array_sum(array_map(fn(Invoice $invoice) => $invoice->getTotalTTC(), $invoices)),
'total_tva_all' => array_sum(array_map(fn(Invoice $invoice) => $invoice->getTotalVAT(), $invoices)),
'total_ht_paid' => array_sum(array_map(fn(Invoice $invoice) => $invoice->getTotalHT(), $paidInvoices)),
'total_ttc_paid' => array_sum(array_map(fn(Invoice $invoice) => $invoice->getTotalTTC(), $paidInvoices)),
'total_tva_paid' => array_sum(array_map(fn(Invoice $invoice) => $invoice->getTotalVAT(), $paidInvoices)),
'total_quantity' => array_sum(array_map(fn(Invoice $invoice) => $invoice->getQuantity(), $invoices)),
'paid_months' => $byMonths,
'to_pay_vat' => $toPayVat,
'to_pay_urssaf' => $toPayUrssaf,
]);
}
#[Route('/new', name: 'app_invoice_new', methods: ['GET', 'POST'])]
public function new(Request $request, InvoiceRepository $invoiceRepository, TokenStorageInterface $tokenStorage): Response
{
$invoice = new Invoice();
$invoice->setAuthor($tokenStorage->getToken()->getUser());
$form = $this->createForm(InvoiceType::class, $invoice);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$invoiceRepository->save($invoice, true);
return $this->redirectToRoute('app_invoice_index', [], Response::HTTP_SEE_OTHER);
}
return $this->renderForm('invoice/new.html.twig', [
'invoice' => $invoice,
'form' => $form,
]);
}
#[Route('/{id}', name: 'app_invoice_show', methods: ['GET'])]
public function show(Invoice $invoice): Response
{
return $this->render('invoice/show.html.twig', [
'invoice' => $invoice,
]);
}
#[Route('/{id}/edit', name: 'app_invoice_edit', methods: ['GET', 'POST'])]
public function edit(Request $request, Invoice $invoice, InvoiceRepository $invoiceRepository): Response
{
$form = $this->createForm(InvoiceType::class, $invoice);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$invoiceRepository->save($invoice, true);
return $this->redirectToRoute('app_invoice_index', [], Response::HTTP_SEE_OTHER);
}
return $this->renderForm('invoice/edit.html.twig', [
'invoice' => $invoice,
'form' => $form,
]);
}
#[Route('/{id}/delete', name: 'app_invoice_delete')]
public function delete(Invoice $invoice, InvoiceRepository $invoiceRepository): Response
{
$this->denyAccessUnlessGranted(InvoiceVoter::DELETE, $invoice);
$invoiceRepository->remove($invoice, true);
return $this->redirectToRoute('app_invoice_index', [], Response::HTTP_SEE_OTHER);
}
#[Route('/{id}/preview/pdf', name: 'invoice_preview_pdf')]
public function previewPdf(InvoicePdfGenerator $pdfGenerator, Invoice $invoice): Response
{
$pdfGenerator->generate($invoice, true);
$response = new BinaryFileResponse($invoice->getGeneratedPath());
$response->setContentDisposition(
ResponseHeaderBag::DISPOSITION_INLINE,
($invoice->getReference() ?: uniqid()) . '.pdf'
);
return $response;
}
#[Route('/{id}/preview/html', name: 'invoice_preview_html')]
public function previewHtml(Invoice $invoice, UserHelper $userHelper): Response
{
return $this->render('invoice_tailwind.html.twig', [
'invoice' => $invoice,
'information' => $userHelper->getOrCreatePersonalInformation(),
]);
}
#[Route('/{id}/generate', name: 'invoice_pdf_generate')]
public function generate(Invoice $invoice, InvoicePdfGenerator $invoicePdfGenerator): Response
{
$invoicePdfGenerator->generate($invoice, true);
return new Response(null, 204);
}
#[Route('/{id}/apply/{transition}', name: 'app_invoice_apply_transition', methods: ['GET'])]
public function applyTransition(
Request $request,
WorkflowInterface $invoiceStateMachine,
Invoice $invoice,
string $transition,
InvoiceRepository $invoiceRepository): Response
{
$invoiceStateMachine->apply($invoice, $transition);
if ($invoice->getStatus() === InvoiceStatus::Paid->value && !$invoice->getPaymentDate()) {
$invoice->setPaymentDate(new \DateTime());
}
$invoiceRepository->save($invoice, true);
return $this->redirect($request->headers->get('referer'));
}
}