<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\ORM\EntityManagerInterface;
use Knp\Snappy\Pdf;
use Knp\Bundle\SnappyBundle\Snappy\Response\PdfResponse;
use Symfony\Component\HttpFoundation\JsonResponse;
use Doctrine\Common\Collections\ArrayCollection;
use App\Service\Booking\BookingService;
use App\Entity\Invoice;
use App\Entity\Booking;
use App\Entity\Item;
use App\Entity\Payment;
use App\Entity\Hotel;
use App\Entity\Guest;
use App\Entity\Season;
use App\Form\InvoiceType;
class BillingController extends AbstractController
{
private $invoice_repository;
public function __construct(
private EntityManagerInterface $entityManager,
private BookingService $booking_service,
private Pdf $knp_snappy_pdf,
) {
$this->invoice_repository = $entityManager->getRepository(Invoice::class);
}
public function listInvoice(): Response
{
$list_invoice = $this->invoice_repository->findAll();
$list_season = $this->entityManager->getRepository(Season::class)->findBy([],['year' => 'ASC', 'number' => 'ASC']);
$id_array = [];
foreach($list_season as $season){
$id_array[$season->getNumber().' '.$season->getYear()] = $season->getNumber().' Trimestre '.$season->getYear().' ('.$season->getName().')';
}
return $this->render('setting/billing/list_invoice.html.twig', [
'list_invoice' => $list_invoice,
'id_array' => json_encode($id_array),
]);
}
public function addInvoice(Request $request, $id): Response
{
$invoice = $id != 0 ? $this->manageBooking($id) : $this->manageNewInvoice();
$list_invoice = $this->invoice_repository->findByYear((new \DateTime())->format('Y'));
$invoice->setNumber(count($list_invoice) + 1);
$form = $this->createForm(InvoiceType::class, $invoice);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if ($id != 0){
$booking = $this->entityManager->find(Booking::class, $id);
$booking->setBilled(true);
$this->entityManager->persist($booking);
}
$this->invoice_repository->add($invoice, true);
$this->addFlash('success', 'Vous avez créé la facture avec succès!');
return $this->redirectToRoute('admin_setting_billing_preview_invoice', [
'id' => $invoice->getId(),
]);
}
return $this->render('setting/billing/add_invoice.html.twig', [
'form' => $form->createView(),
'invoice' => $invoice,
]);
}
public function previewInvoice(Invoice $invoice): Response
{
$previous_invoice = $this->invoice_repository->findOneBy(['year' => $invoice->getYear(), 'number' => $invoice->getNumber()-1]);
if(!$previous_invoice){
$previous = 0;
}else{
$previous = $previous_invoice->getId();
}
$next_invoice = $this->invoice_repository->findOneBy(['year' => $invoice->getYear(), 'number' => $invoice->getNumber()+1]);
if(!$next_invoice){
$next = 0;
}else{
$next = $next_invoice->getId();
}
return $this->render('setting/billing/preview_invoice.html.twig', [
'invoice' => $invoice,
'next' => $next,
'previous' => $previous,
]);
}
public function donwloadPdf(Invoice $invoice): PdfResponse
{
$html = $this->renderView('setting/billing/preview_invoice.html.twig', [
'invoice' => $invoice,
]);
return new PdfResponse(
$this->knp_snappy_pdf->getOutputFromHtml($html),
$invoice->getDate()->format('Y-m-d').'-'.$invoice->getGuest()->getCompany().'-'.$invoice->getNumber().'.pdf'
);
}
public function editInvoice(Request $request, Invoice $invoice): Response
{
$form = $this->createForm(InvoiceType::class, $invoice);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->invoice_repository->add($invoice, true);
$this->addFlash('success', 'Vous avez modifié la facture avec succès!');
return $this->redirectToRoute('admin_setting_billing_preview_invoice', [
'id' => $invoice->getId(),
]);
}
return $this->render('setting/billing/edit_invoice.html.twig', [
'form' => $form->createView(),
'invoice' => $invoice,
]);
}
public function copyInvoice(Request $request, Invoice $invoice): Response
{
$clonedInvoice = $this->cloneInvoice($invoice);
$this->addFlash('success', 'Vous avez copié la facture avec succès!');
return $this->redirectToRoute('admin_setting_billing_preview_invoice', [
'id' => $clonedInvoice->getId(),
]);
}
public function deleteInvoice(Invoice $invoice): Response
{
$next_invoice = $this->invoice_repository->findOneByNumberAndYear($invoice->getNumber()+1, $invoice->getYear());
if($next_invoice){
$this->addFlash('danger', 'La facture ne peut pas être supprimée!');
}else{
$this->invoice_repository->remove($invoice, true);
$this->addFlash('success', 'La facture a été supprimé avec succès avec succès!');
}
return $this->redirectToRoute('admin_setting_billing_list_invoice');
}
public function deleteMultiInvoices(Request $request): Response
{
$array_id = $request->get('data');
if(!is_array($array_id)){
$this->addFlash('warning', "Vous n'avez pas sélectionné de factures.");
return new Response('ko');
}
foreach($array_id as $id){
$invoice = $this->invoice_repository->find($id);
$next_invoice = $this->invoice_repository->findOneByNumberAndYear($invoice->getNumber()+1, $invoice->getYear());
if($next_invoice){
$this->addFlash('danger', "Les factures n'ont pas pu être supprimées.");
return new Response('ko');
}else{
$this->invoice_repository->remove($invoice, true);
}
}
$this->addFlash('success', 'Les factures ont pu être supprimées.');
return new Response('ok');
}
public function printMultiInvoices($ids): Response
{
$array_invoice_id = json_decode($ids);
$list_invoice=[];
foreach($array_invoice_id as $id){
$invoice = $this->invoice_repository->find($id);
$list_invoice[] = $invoice;
}
return $this->render('setting/billing/print_invoice.html.twig', [
'list_invoice' => $list_invoice,
]);
}
public function seasonal($number, $year): Response
{
$season = $this->entityManager->getRepository(Season::class)->findOneBy(['number' => $number, 'year' => $year, 'billed' => 0]);
if(!$season){
$this->addFlash('warning', 'Vous avez déjà facturé cette saison.');
return $this->redirectToRoute('admin_setting_billing_list_invoice');
}
$list_invoice = $this->invoice_repository->findByYear((new \DateTime())->format('Y'));
$invoice_number = count($list_invoice) + 1;
$hotels = $this->entityManager->getRepository(Hotel::class)->findall();
foreach($hotels as $hotel){
$price = 0;
$bookings = $this->entityManager->getRepository(Booking::class)->findBySeasonAndHotel($season->getId(), $hotel->getId());
foreach($bookings as $booking){
$price += $booking->getAmount()->getPrice();
}
if($price == 0){
continue 1;
}
$invoice = new Invoice;
$invoice->setNumber($invoice_number);
$invoice->setGuest($this->getHotelGuest($hotel));
$item = new Item();
$item->manageHotelItem($season, $price);
$invoice->addItem($item);
$subtotal = $item->getSubtotal();
$invoice->setSubtotal($subtotal);
$invoice->setTax(round($subtotal * (6 / 100), 2));
$invoice->setTotal($subtotal + (round($subtotal * (6 / 100), 2)));
$invoice->setStatus('paid');
$this->invoice_repository->add($invoice, true);
$invoice_number++;
}
$season->setBilled(true);
$this->entityManager->persist($season);
$this->entityManager->flush();
$this->addFlash('success', 'Les factures saisonnières ont correctement été créées.');
return $this->redirectToRoute('admin_setting_billing_list_invoice');
}
private function manageBooking($id)
{
/** @var Booking $booking */
$booking = $this->entityManager->find(Booking::class, $id);
$invoice = new Invoice;
$invoice->setGuest($booking->getGuest());
$imported_booking = $this->booking_service->getBookingFromBeds24($booking->getHotel()->getBeds24Setting()->getPropKey(), $booking->getBookId());
$subtotal = $paid = 0;
foreach($imported_booking['invoice'] as $imported_item){
if($imported_item['qty'] < 0){
$payment = new Payment;
$payment->manageImportedItem($imported_item);
$invoice->addPayment($payment);
$paid = $paid + $payment->getPrice();
}elseif ($imported_booking['price'] > 0){
$item = new Item();
$item->manageImportedItem($imported_item, true);
$subtotal = $subtotal + $item->getSubtotal();
$invoice->addItem($item);
}
}
$invoice->setSubtotal($subtotal);
$invoice->setTax(round($subtotal * (6 / 100), 2));
$invoice->setTotal($subtotal + (round($subtotal * (6 / 100), 2)));
if($invoice->getTotal() == $paid){
$invoice->setStatus('paid');
}
return $invoice;
}
private function manageNewInvoice(){
$invoice = new Invoice;
$item = new Item;
$invoice->addItem($item);
$payment = new Payment();
$invoice->addPayment($payment);
return $invoice;
}
private function gethotelGuest(Hotel $hotel): Guest
{
$guest = $this->entityManager->getRepository(Guest::class)->findByFirstnameAndName('Vente', $hotel->getName());
if(!$guest){
$location = clone $hotel->getLocation();
$guest = new Guest();
$guest->manageHotel($hotel);
$guest->setLocation($location);
}
return $guest;
}
private function cloneInvoice(Invoice $invoice): Invoice
{
// Cloner l'objet Invoice
$clonedInvoice = clone $invoice;
$list_invoice = $this->invoice_repository->findByYear((new \DateTime())->format('Y'));
$clonedInvoice->setNumber(count($list_invoice) + 1);
// Si nécessaire, vous pouvez ajuster d'autres propriétés comme la date, le numéro de facture, etc.
$clonedInvoice->setDate(new \DateTime());
$clonedInvoice->setStatus('unpaid');
// Cloner les items et les réassocier à la nouvelle facture
foreach ($invoice->getItems() as $item) {
$clonedItem = clone $item;
$clonedItem->setInvoice($clonedInvoice);
$clonedInvoice->addItem($clonedItem);
}
foreach ($invoice->getPayments() as $payment) {
$clonedInvoice->removePayment($payment);
}
// Persist et flush l'entité clonée
$this->invoice_repository->add($clonedInvoice, true);
return $clonedInvoice;
}
}