<?php
namespace App\Controller;
use App\Entity\Dto\CsvImportDto;
use App\Entity\Invoice;
use App\Entity\InvoicePayment;
use App\Entity\Order;
use App\Entity\Person;
use App\Entity\WaitItem;
use App\Form\CsvImportType;
use App\Form\InvoiceOnlyType;
use App\Form\InvoiceType;
use App\Repository\InvoiceItemAttendeesRepository;
use App\Repository\InvoicePaymentRepository;
use App\Repository\InvoiceReminderRepository;
use App\Repository\InvoiceRepository;
use App\Repository\PersonRepository;
use App\Service\ConfigurationService;
use App\Service\CsvImportService;
use App\Service\EmailHistoryService;
use App\Service\Exception\ServiceException;
use App\Service\InvoiceService;
use App\Service\MailerService;
use App\Service\PaymentService;
use App\Service\PdfService;
use App\Service\SepaXmlService;
use App\Service\UiService;
use Doctrine\Common\Collections\ArrayCollection;
use App\User\Controller\AbstractClientableController;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/invoice")
*
* @IsGranted("ROLE_MANAGER")
*/
class InvoiceController extends AbstractClientableController
{
public const LISTING_LIMIT = 20;
private function generateUniqueFileName()
{
return md5(uniqid());
}
/**
* @Route("/", name="invoice_index", methods="GET|POST")
*/
public function index(
Request $request,
InvoiceRepository $invoiceRepo,
CsvImportService $importService,
UiService $uiService,
RequestStack $requestStack,
PaymentService $paymentService,
): Response {
$order = $uiService->getSortOrder('invoice-index-listing');
// Check for unset invoice status
$this->checkForUnsetInvoiceStatus($invoiceRepo, $paymentService);
$filterInvoices = $request->get('action');
if ($filterInvoices) {
$requestStack->getSession()->set('filter', $filterInvoices);
} else {
$requestStack->getSession()->set('filter', null);
}
$invoice = $invoiceRepo->getByClientPaged(
$this->getCurrentClient(),
self::LISTING_LIMIT,
$order['orderDirection'] ?? 'desc',
$order['orderBy'] ?? 'id',
1,
($filterInvoices) ? $filterInvoices : null
);
$csvImportDto = new CsvImportDto();
$form = $this->createForm(CsvImportType::class, $csvImportDto);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$fileName =
md5(uniqid()).'.'.$csvImportDto->file->guessExtension();
try {
$csvImportDto->file->move(
$this->getParameter('import_directory'),
$fileName
);
$fullFileName = $this->getParameter('import_directory').'/'.$fileName;
} catch (FileException $e) {
$this->addFlash(
'error',
'Beim Datei-Upload ist ein Fehler aufgetreten. Bitte versuchen Sie es später noch einmal.'
);
return $this->redirectToRoute('invoice_index');
}
$result = $importService->updateInvoiceStatus(
$fullFileName,
$this->getCurrentClient()
);
if (is_array($result)) {
$message = 'Beim Rechnungsimport ';
if (count($result) > 1) {
$message .=
'sind '.count($result).' Fehler aufgetreten.';
} else {
$message .= 'ist ein Fehler aufgetreten.';
}
$this->addFlash('error', $message);
foreach ($result as $key => $error) {
$this->addFlash('error', $key + 1 .'. '.$error);
}
} elseif (false !== $result) {
$this->addFlash('notice', $result.' Rechnungen importiert.');
return $this->redirectToRoute('invoice_index');
}
}
return $this->render('invoice/index.html.twig', [
'uiService' => $uiService,
'invoices' => $invoice->getIterator(),
'total' => $invoice->count(),
'pages' => ceil($invoice->count() / self::LISTING_LIMIT),
'page' => 1,
'form' => $form->createView(),
'filterAction' => $requestStack->getSession()->get('filter'),
'env' => $_ENV,
'now' => new \DateTime(),
]);
}
/**
* @Route("/{page}/{orderby}/{order}", name="invoice_index_listing", methods="GET", requirements={"page"="\d+","order"="asc|desc"})
*/
public function indexListing(
InvoiceRepository $invoiceRepo,
UiService $uiService,
$page,
$orderby,
$order,
RequestStack $requestStack,
): Response {
$uiService->storeSortOrder('invoice-index-listing', $orderby, $order);
$invoice = $invoiceRepo->getByClientPaged(
$this->getCurrentClient(),
self::LISTING_LIMIT,
$order,
$orderby,
$page,
$requestStack->getSession()->get('filter')
);
return $this->render('invoice/_index_listing.html.twig', [
'invoices' => $invoice->getIterator(),
'total' => $invoice->count(),
'pages' => ceil($invoice->count() / self::LISTING_LIMIT),
'page' => $page,
'filterAction' => $requestStack->getSession()->get('filter'),
'env' => $_ENV,
'now' => new \DateTime(),
]);
}
/**
* @Route("/{id}/close", name="invoice_close", methods="GET", requirements={"id"="\d+"})
*/
public function close(
Request $request,
Invoice $invoice,
PdfService $pdfService,
MailerService $mailer,
EmailHistoryService $emailHistoryService,
): Response {
// Security: Check client ownership via Voter
$this->denyAccessUnlessGranted('view', $invoice);
$pdf = $pdfService->getInvoicePdf($this->getCurrentClient(), $invoice);
$sentMessage = $mailer->sendInvoiceEmail(
$invoice,
'Rechnung-'.$invoice->getNumber().'.pdf',
$pdf->Output('S', 'Rechnung-'.$invoice->getNumber().'.pdf')
);
$outputfile = $this->generateUniqueFileName().'.pdf';
$outputpath = $this->getParameter('attachment_directory').'/'.$outputfile;
$pdf->Output('F', $outputpath);
$emailHistoryService->saveProtocolEntryFromInvoiceMessage(
$invoice,
$sentMessage['sender'],
$sentMessage['subject'],
$sentMessage['message'],
$outputfile,
'Rechnung-'.$invoice->getNumber().'.pdf'
);
if (Invoice::STATUS_CLOSED != $invoice->getStatus()) {
if ($invoice->isPaymentDebit()) {
$invoice->setStatus(Invoice::STATUS_DEBIT_PENDING);
} else {
$invoice->setStatus(Invoice::STATUS_CLOSED);
}
}
$em = $this->getDoctrine()->getManager();
// Update the order status
$newOrderState = $invoice->getOrder()->setStatus(Order::STATUS_DONE);
$em->persist($newOrderState);
$em->flush();
$this->addFlash('notice', 'Rechnung versendet');
return $this->redirect($request->get('return'));
}
/**
* @Route("/{id}/lock", name="invoice_lock", methods="GET", requirements={"id"="\d+"})
*/
public function lock(
Request $request,
Invoice $invoice,
PdfService $pdfService,
): Response {
// Security: Check client ownership via Voter
$this->denyAccessUnlessGranted('view', $invoice);
$pdf = $pdfService->getInvoicePdf($this->getCurrentClient(), $invoice);
$outputfile = $this->generateUniqueFileName().'.pdf';
$outputpath = $this->getParameter('attachment_directory').'/'.$outputfile;
$pdf->Output('F', $outputpath);
if (Invoice::STATUS_CLOSED != $invoice->getStatus()) {
if ($invoice->isPaymentDebit()) {
$invoice->setStatus(Invoice::STATUS_DEBIT_PENDING);
} else {
$invoice->setStatus(Invoice::STATUS_CLOSED);
}
}
$em = $this->getDoctrine()->getManager();
// Update the order status
$newOrderState = $invoice->getOrder()->setStatus(Order::STATUS_DONE);
$em->persist($newOrderState);
$em->flush();
$this->addFlash('notice', 'Rechnung abgeschlossen');
return $this->redirect($request->get('return'));
}
/**
* @Route("/new/{return}", name="invoice_new", methods="GET|POST")
*/
public function new(
Request $request,
$return = '',
PersonRepository $personRepo,
ConfigurationService $configService,
): Response {
$customer = null;
if ($return) {
$customer = $personRepo->find($return);
}
$invoice = new Invoice();
$form = $this->createForm(InvoiceType::class, $invoice, [
'client' => $this->getCurrentClient(),
'taxes' => $configService->getTaxConfigbyClient(
$this->getCurrentClient()
),
'customer' => $customer,
]);
$form->handleRequest($request);
// check if creation is possible
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$allItemsBookable = true;
$occurrences = [];
foreach ($invoice->getOrder()->getOrderItems() as $orderItem) {
if ($orderItem->getCourseOccurrence()) {
$occurrence = $orderItem->getCourseOccurrence();
if (
!$occurrence->isBookable($orderItem->getQuantity())
&& $occurrence->getReservationAllowed()
) {
$waitItem = WaitItem::fromOrderItem($orderItem);
foreach ($orderItem->getParticipants() as $participant) {
$orderItem->removeParticipant($participant);
}
$invoice->getOrder()->addWaitItem($waitItem);
$invoice->getOrder()->removeOrderItem($orderItem);
$em->persist($waitItem);
$this->addFlash(
'error',
'Im Kurs "'.
$occurrence->getTitle().
'" sind nicht mehr genug Plätz verfügbar. Die Buchung wurde stattdessen zur Warteliste hinzugefügt.'
);
} elseif (
!$occurrence->isBookable($orderItem->getQuantity())
&& !$occurrence->getReservationAllowed()
) {
$allItemsBookable = false;
$this->addFlash(
'error',
'Im Kurs "'.
$occurrence->getTitle().
'" sind nicht mehr genug Plätz verfügbar.'
);
} else {
$occurrence->bookSlots($orderItem->getQuantity());
$occurrences[] = $occurrence;
}
}
}
if ($allItemsBookable) {
if (
count($invoice->getOrderItems()) > 0
|| count($invoice->getOrder()->getWaitItems()) > 0
) {
$invoice->setNumber(
$configService->getNewInvoiceNumberByClient(
$this->getCurrentClient()
)
);
$invoice->setSignedBy($this->getCurrentUser());
$order = $invoice->getOrder();
$order->setClient($this->getCurrentClient());
$order->setCustomer($customer);
$order->setCustomerData($customer);
$order->setDate(new \DateTime());
$order->setNumber(
$configService->getNewOrderNumberByClient(
$this->getCurrentClient()
)
);
$em->persist($order);
$em->persist($invoice);
$em->flush();
foreach ($occurrences as $occurrence) {
$occurrence->flushBooking();
}
}
$em->flush();
if ($return) {
return $this->redirectToRoute('customer_invoices', [
'id' => $return,
]);
} else {
return $this->redirectToRoute('invoice_index');
}
}
}
return $this->render('invoice/new.html.twig', [
'invoice' => $invoice,
'form' => $form->createView(),
'customer' => $customer,
]);
}
/**
* @Route("/{id}", name="invoice_show", methods="GET|POST", requirements={"id"="\d+"})
*/
public function show(
Request $request,
Invoice $invoice,
InvoicePaymentRepository $invoicePaymentRepo,
InvoiceRepository $repo,
ConfigurationService $configService,
InvoiceService $invoiceService,
PersonRepository $personRepo,
): Response {
$invoiceRecipient = null;
if ($request->query->has('invoice')) {
// Entries from the invoice table
$invoiceRecipient = $repo->findOneBy([
'invoiceAdressPerson' => $personRepo,
'id' => $request->get('invoice'),
]);
}
$payments = $invoicePaymentRepo->getByInvoicePaged($invoice, static::LISTING_LIMIT);
$invoiceRecipientMembers = null;
$adressChanged = false;
// Need the original recipient ID before update
$lastInvoiceRecipient = $invoice->getInvoiceAdressPerson();
// var_dump($invoice);
if (is_null($invoice->getInvoiceAdressPerson())) {
if (!is_null($invoice->getInvoiceAdressPerson())) {
$currentRecipient = $invoice->getInvoiceAdressPerson();
$invoiceRecipientMembers = $personRepo->getInvoiceReciepientMembers($currentRecipient);
/*
* If there are no Members, so we have to look, if the current Invoice Recipient
* is an family member. Then we can get the original client and his recipient members.
*/
if (empty($invoiceRecipientMembers)) {
// Get FamilyMembers By Client
$invoiceRecipientMembers = $personRepo->getInvoiceReciepientsByParent(
$currentRecipient->getFamilyMemberOf()
);
// Client of the Family Member
$currentRecipient = $currentRecipient->getFamilyMemberOf();
}
// Create values for the SelectBox (Frontend invoice/edit)
$invoiceRecipient = $this->createInvoiceRecipientValues(
$invoiceRecipientMembers,
$currentRecipient,
$invoice->getInvoiceAdressPerson()
);
} else {
// If there is no InvoiceAdressPerson, we have to take the Person from the Order Table.
$currentRecipient = $invoice->getOrder()->getCustomer();
$invoiceRecipientMembers = $personRepo->getInvoiceReciepientMembers(
$currentRecipient
);
// Create values for the SelectBox (Frontend invoice/edit)
$invoiceRecipient = $this->createInvoiceRecipientValues(
$invoiceRecipientMembers,
$currentRecipient,
$invoice->getInvoiceAdressPerson(),
true
);
}
if (
$invoice->getInvoiceAdressPerson()
// && $invoice->getInvoiceAdressPerson()->getIsInvoiceRecipient()
) {
$adressChanged = $invoiceService->checkIfAdressHasChanged($invoice, true);
}
// else {
// $adressChanged = $invoiceService->checkIfAdressHasChanged($invoice, true);
// }
}
if ($request->get('flashMessage')) {
$this->addFlash('notice', 'Rechnungsadresse wurde erfolgreich aktualisiert.');
}
$cancellations = $repo->findCancellationByInvoice($invoice);
if ($invoice->isDraft()) {
$currentRecipient = $invoice->getInvoiceAdressPerson();
$invoiceRecipientMembers = $personRepo->getInvoiceReciepientMembers($currentRecipient);
$invoiceRecipient = $this->createInvoiceRecipientValues(
$invoiceRecipientMembers,
$currentRecipient,
$invoice->getInvoiceAdressPerson()
);
// var_dump($invoiceRecipient);
$form = $this->createForm(InvoiceOnlyType::class, $invoice, [
'client' => $this->getCurrentClient(),
'taxes' => $configService->getTaxConfigbyClient(
$this->getCurrentClient()
),
'invoiceRecipient' => $invoiceRecipient,
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->flush();
$this->addFlash('notice', 'Rechnung gespeichert.');
}
return $this->render('invoice/edit.html.twig', [
'invoice' => $invoice,
'cancellations' => $cancellations,
'payments' => $payments->getIterator(),
'total' => $payments->count(),
'pages' => ceil($payments->count() / self::LISTING_LIMIT),
'page' => 1,
'form' => $form->createView(),
'adressChanged' => $adressChanged,
]);
} else {
return $this->render('invoice/show.html.twig', [
'invoice' => $invoice,
'cancellations' => $cancellations,
'payments' => $payments->getIterator(),
'total' => $payments->count(),
'pages' => ceil($payments->count() / self::LISTING_LIMIT),
'page' => 1,
]);
}
}
/**
* @Route("/{id}/updateAdress", name="invoice_update_adress", methods="GET|POST", requirements={"id"="\d+"})
*/
public function updateAdress(
Request $request,
Invoice $invoice,
InvoiceService $invoiceService,
PersonRepository $personRepo,
): RedirectResponse {
$em = $this->getDoctrine()->getManager();
if ($request->get('person')) {
$person = $personRepo->find($request->get('personId'));
$updatedInvoice = $invoiceService->updateInvoiceAdress($invoice, $person);
$em->persist($updatedInvoice);
$em->flush();
}
// else {
// $updatedInvoice = $invoiceService->updateInvoiceAdress($invoice, $null);
// }
return $this->redirectToRoute('invoice_show', [
'id' => $invoice->getId(),
'flashMessage' => true,
]);
}
/**
* @Route("/{id}", name="invoice_delete", methods="DELETE", requirements={"id"="\d+"})
*/
public function delete(Request $request, Invoice $invoice, InvoiceItemAttendeesRepository $invoiceItemAttendeesRepo): Response
{
// Security: Check client ownership via Voter
$this->denyAccessUnlessGranted('view', $invoice);
if ($this->isCsrfTokenValid('delete'.$invoice->getId(), $request->request->get('_token')) && $invoice->isDraft()) {
$em = $this->getDoctrine()->getManager();
// Prüfe, ob andere Rechnungen (z.B. Stornierungen) auf diese Rechnung verweisen
$childInvoices = $em->getRepository(Invoice::class)->findBy(['parent' => $invoice]);
if (count($childInvoices) > 0) {
$this->addFlash('error', sprintf(
'Die Rechnung kann nicht gelöscht werden, weil %d Stornierungsrechnung(en) darauf verweisen. Löschen Sie zuerst die Stornierungen.',
count($childInvoices)
));
return $this->redirectToRoute('invoice_index');
}
// Erst alle InvoiceItemAttendees löschen, dann Items, dann Invoice
foreach ($invoice->getItems() as $item) {
$attendees = $invoiceItemAttendeesRepo->findBy(['invoice_item' => $item]);
foreach ($attendees as $attendee) {
$em->remove($attendee);
}
// Item wird explizit entfernt
$em->remove($item);
}
// Jetzt kann die Invoice gelöscht werden
$em->remove($invoice);
$em->flush();
$this->addFlash('notice', 'Rechnung gelöscht');
}
return $this->redirectToRoute('invoice_index');
}
/**
* @Route("/{id}/cancel", name="invoice_cancel", methods="POST", requirements={"id"="\d+"})
*/
public function cancel(
Request $request,
Invoice $invoice,
ConfigurationService $configService,
InvoiceItemAttendeesRepository $invoiceItemAttendeesRepo,
): Response {
// Security: Check client ownership via Voter
$this->denyAccessUnlessGranted('view', $invoice);
if ($this->isCsrfTokenValid('cancel'.$invoice->getId(), $request->request->get('_token')) && !$invoice->isDraft()) {
$em = $this->getDoctrine()->getManager();
$coppiedInvoice = $invoice->cloneForCancellation();
$cancellation = $coppiedInvoice['invoice'];
$cancellation->setInvoiceDate(new \DateTime());
$cancellation->setNumber(
$configService->getNewInvoiceNumberByClient(
$this->getCurrentClient()
)
);
$cancellation->setCancellation(true);
$cancellation->setParent($invoice);
$cancellation->setSignedBy($this->getCurrentUser());
$cancellation->setStatus(Invoice::STATUS_CLOSED);
$invoice->setCancelled(true);
foreach ($coppiedInvoice['attendees'] as $attendee) {
$em->persist($attendee);
}
$em->persist($cancellation);
$em->flush();
$this->addFlash('notice', 'Rechnung storniert');
}
if ($this->isCsrfTokenValid('cancel'.$invoice->getId(), $request->request->get('_token')) && $invoice->isDraft()) {
$em = $this->getDoctrine()->getManager();
$attendees = [];
foreach ($invoice->getItems() as $item) {
$attendees = $invoiceItemAttendeesRepo->findBy(['invoice_item' => $item]);
}
if ($attendees) {
foreach ($attendees as $attendee) {
$em->remove($attendee);
}
}
$em->remove($invoice);
$em->flush();
$this->addFlash('notice', 'Rechnung gelöscht');
}
return $this->redirectToRoute('invoice_show', [
'id' => $invoice->getId(),
]);
}
/**
* @Route("/{id}/cancel_fromorder/{order}", name="invoice_cancel_fromorder", methods="POST", requirements={"id"="\d+"})
*/
public function cancel_fromorder(
Request $request,
Invoice $invoice,
Order $order,
InvoiceItemAttendeesRepository $invoiceItemAttendeesRepo,
ConfigurationService $configService,
): Response {
// Security: Check client ownership via Voter
$this->denyAccessUnlessGranted('view', $invoice);
if ($this->isCsrfTokenValid('cancel'.$invoice->getId(), $request->request->get('_token')) && !$invoice->isDraft()) {
$em = $this->getDoctrine()->getManager();
$coppiedInvoice = $invoice->cloneForCancellation();
$cancellation = $coppiedInvoice['invoice'];
$cancellation->setInvoiceDate(new \DateTime());
$cancellation->setNumber(
$configService->getNewInvoiceNumberByClient(
$this->getCurrentClient()
)
);
$cancellation->setCancellation(true);
$cancellation->setParent($invoice);
$cancellation->setSignedBy($this->getCurrentUser());
$cancellation->setStatus(Invoice::STATUS_CLOSED);
$invoice->setCancelled(true);
foreach ($coppiedInvoice['attendees'] as $attendee) {
$em->persist($attendee);
}
$em->persist($cancellation);
$em->flush();
$this->addFlash('notice', 'Rechnung storniert');
}
if ($this->isCsrfTokenValid('cancel'.$invoice->getId(), $request->request->get('_token')) && $invoice->isDraft()) {
$em = $this->getDoctrine()->getManager();
$attendees = [];
foreach ($invoice->getItems() as $item) {
$attendees = $invoiceItemAttendeesRepo->findBy(['invoice_item' => $item]);
}
if ($attendees) {
foreach ($attendees as $attendee) {
$em->remove($attendee);
}
}
$em->remove($invoice);
$em->flush();
$this->addFlash('notice', 'Rechnung gelöscht');
}
return $this->redirectToRoute('order_show', [
'id' => $order->getId(),
]);
}
/**
* @Route("/{id}/pdf", name="invoice_pdf", methods="GET", requirements={"id"="\d+"})
*/
public function pdf(
Request $request,
Invoice $invoice,
ConfigurationService $configService,
PdfService $pdfService,
InvoiceItemAttendeesRepository $invoiceItemAttendeesRepository,
) {
// dd($invoice->getItems()[0]->getId());
// dd(count($invoice->getItems()));
// Security: Check client ownership via Voter
$this->denyAccessUnlessGranted('view', $invoice);
$pdf = $pdfService->getInvoicePdf($this->getCurrentClient(), $invoice);
$pdf->Output('D', 'Rechnung-'.$invoice->getNumber().'.pdf');
exit;
}
/**
* @Route("/{id}/cancellation-pdf", name="invoice_cancellation-pdf", methods="GET", requirements={"id"="\d+"})
*/
public function cancellationPdf(
Request $request,
Invoice $invoice,
ConfigurationService $configService,
PdfService $pdfService,
) {
// Security: Check client ownership via Voter
$this->denyAccessUnlessGranted('view', $invoice);
$pdf = $pdfService->getCancellationPdf(
$this->getCurrentClient(),
$invoice
);
$pdf->Output('D', 'Gutschrift-'.$invoice->getNumber().'.pdf');
exit;
}
/**
* @Route("/{id}/sepa-xml", name="invoice_sepa-xml", methods="GET", requirements={"id"="\d+"})
*/
public function sepaXml(
Request $request,
Invoice $invoice,
ConfigurationService $configService,
SepaXmlService $sepaXmlService,
) {
// Security: Check client ownership via Voter
$this->denyAccessUnlessGranted('view', $invoice);
$em = $this->getDoctrine()->getManager();
$invoice->setStatus(Invoice::STATUS_CLOSED);
if (
!$invoice
->getOrder()
->getCustomer()
->getDebitActive()
) {
$invoice
->getOrder()
->getCustomer()
->setDebitActive(true);
$invoice->setIsNewSepaMandate(true);
}
$config = $configService->getSepaXmlConfigByClient(
$this->getCurrentClient()
);
try {
$xml = $sepaXmlService->getSepaXmlSingle(
$this->getCurrentClient(),
$config,
$invoice
);
} catch (ServiceException $e) {
$this->addFlash('error', $e->getMessage());
return $this->redirectToRoute('invoice_index');
}
$em->flush();
$response = new Response($xml);
$response->headers->set('Content-Type', 'text/xml');
$response->headers->set('Content-disposition', 'attachment; filename="SEPA-'.date('Ymd-His').'.xml"');
return $response;
}
/**
* @Route("/new-sepa-xml", name="invoice_new-sepa-xml", methods="GET")
*/
public function newInvoicesSepaXml(
Request $request,
ConfigurationService $configService,
SepaXmlService $sepaXmlService,
InvoiceRepository $invoiceRepo,
) {
$invoices = $invoiceRepo->getByClientAndStatuses(
$this->getCurrentClient(),
[Invoice::STATUS_DRAFT, Invoice::STATUS_DEBIT_PENDING],
Invoice::PAYMENT_DEBIT
);
$invoicesToExport = new ArrayCollection();
foreach ($invoices as $invoice) {
if (!$invoicesToExport->contains($invoice)) {
$invoice->setStatus(Invoice::STATUS_CLOSED);
if (!empty($_ENV['SEPAEXPORT_PAYED'])) {
$invoice->setExportStatus(Invoice::EXPORTED);
}
$invoicesToExport->add($invoice);
if (
$invoice->getOrder()->getCustomer()
&& !$invoice
->getOrder()
->getCustomer()
->getDebitActive()
) {
$invoice
->getOrder()
->getCustomer()
->setDebitActive(true);
$invoice->setIsNewSepaMandate(true);
}
}
}
try {
if (count($invoicesToExport) > 0) {
$config = $configService->getSepaXmlConfigByClient($this->getCurrentClient());
$xml = $sepaXmlService->getSepaXmlMultiple($this->getCurrentClient(), $config, $invoicesToExport);
$em = $this->getDoctrine()->getManager();
$em->flush();
$response = new Response($xml);
$response->headers->set('Content-Type', 'text/xml');
$response->headers->set('Content-disposition', 'attachment; filename="SEPA-'.date('Ymd-His').'.xml"');
return $response;
}
} catch (ServiceException $e) {
$this->addFlash('error', $e->getMessage());
return $this->redirectToRoute('invoice_index');
}
$this->addFlash('error', 'Es wurden keine exportierbaren Rechnungen gefunden.');
return $this->redirectToRoute('invoice_index');
}
/**
* @Route("/{id}/payments/{page}/{orderby}/{order}", name="invoice_payments_listing", methods="GET", requirements={"id"="\d+"})
*/
public function paymentsListing(
Request $request,
Invoice $invoice,
$page = 1,
$orderby = 'payedDate',
$order = 'ASC',
InvoicePaymentRepository $repo,
) {
// Security: Check client ownership via Voter
$this->denyAccessUnlessGranted('view', $invoice);
$payments = $repo->getByInvoicePaged(
$invoice,
self::LISTING_LIMIT,
$order,
$orderby,
$page
);
return $this->render('invoice/tabs/_payments_listing.html.twig', [
'payments' => $payments->getIterator(),
'total' => $payments->count(),
'pages' => ceil($payments->count() / self::LISTING_LIMIT),
'page' => $page,
]);
}
/**
* @Route("/{id}/reminders/{page}/{orderby}/{order}", name="invoice_reminders_listing", methods="GET", requirements={"id"="\d+"})
*/
public function remindersListing(
Request $request,
Invoice $invoice,
$page = 1,
$orderby = 'remindDate',
$order = 'ASC',
InvoiceReminderRepository $repo,
) {
// Security: Check client ownership via Voter
$this->denyAccessUnlessGranted('view', $invoice);
$reminders = $repo->getByInvoicePaged(
$invoice,
self::LISTING_LIMIT,
$order,
$orderby,
$page
);
return $this->render('invoice/tabs/_reminders_listing.html.twig', [
'reminders' => $reminders->getIterator(),
'total' => $reminders->count(),
'pages' => ceil($reminders->count() / self::LISTING_LIMIT),
'page' => $page,
]);
}
private function getInvoiceRecipientId(Person $person)
{
if ($person->getIsInvoiceRecipient()) {
return [
'id' => $person->getId(),
'type' => 'personRecipient',
];
}
return [
'id' => $person->getId(),
'type' => 'clientRecipient',
];
}
private function createInvoiceRecipientValues($invoiceRecipientMembers, $currentRecipient, $invoicePerson = null, $onlyClient = false)
{
$res = [];
$invoicePersonId = null;
if ($invoicePerson) {
$res[] = $invoicePerson;
$invoicePersonId = $invoicePerson->getId();
}
if ($onlyClient) {
$res[] = $currentRecipient;
} else {
if (
$currentRecipient
&& $currentRecipient->getId() != $invoicePersonId
) {
$res[] = $currentRecipient;
}
}
foreach ($invoiceRecipientMembers as $person) {
if ($person->getId() != $invoicePersonId) {
$res[] = $person;
}
}
return $res;
}
/**
* @Route("/{id}/getPersonAdress", name="get_person_adress", methods="GET|POST")
*/
public function getClientAdress(Request $request, Person $person, InvoiceRepository $invoiceRepo)
{
/**
* Ajax Call
* Returns the person informations back to the invoice/edit by onChange the persons.
*/
$invoiceRecipient = null;
if ($request->query->has('invoice')) {
// Entries from the invoice table
$invoiceRecipient = $invoiceRepo->findOneBy([
'invoiceAdressPerson' => $person,
'id' => $request->get('invoice'),
]);
}
if ($invoiceRecipient) {
return $this->json([
'person' => [
'id' => $person->getId(),
'company' => $invoiceRecipient->getCompany(),
'name' => $invoiceRecipient->getInvoiceFullname(),
'street' => $invoiceRecipient->getInvoiceFullStreet(),
'place' => $invoiceRecipient->getInvoicePostalcodeCity(),
'isInvoiceRecipient' => $person->getIsInvoiceRecipient(),
],
], Response::HTTP_OK);
}
// Entries from the person table
return $this->json([
'person' => [
'id' => $person->getId(),
'company' => $person->getCompany(),
'name' => $person->getFullname(),
'street' => $person->getFullStreet(),
'place' => $person->getPostalcodeCity(),
'isInvoiceRecipient' => $person->getIsInvoiceRecipient(),
],
], Response::HTTP_OK);
}
private function checkForUnsetInvoiceStatus(
InvoiceRepository $invoiceRepo,
PaymentService $paymentService,
) {
$allInvoicesWithoutState = $invoiceRepo->findBy(['paymentStatus' => null]);
if (!empty($allInvoicesWithoutState)) {
foreach ($allInvoicesWithoutState as $invoice) {
$sumOfPayments = $paymentService->getPayments($invoice);
$state = $paymentService->interpretPayments($sumOfPayments, $invoice);
$invoice->setPaymentStatus($state);
$em = $this->getDoctrine()->getManager();
$em->persist($invoice);
}
$em->flush();
}
}
/**
* @Route("/{id}/payInvoice", name="pay_invoice", methods="GET|POST")
*/
public function payTheBill(Invoice $invoice, PaymentService $paymentService)
{
$openSum = (float) $paymentService->payAmount($invoice);
$invoicePayment = new InvoicePayment();
$invoicePayment->setInvoice($invoice);
$invoicePayment->setPayedDate(new \DateTime());
$invoicePayment->setSum($openSum);
$invoice->setPaymentStatus(Invoice::FULLY_PAID);
$em = $this->getDoctrine()->getManager();
$em->persist($invoicePayment);
$em->persist($invoice);
$em->flush();
return $this->json([
'success' => 'Die Rechnung wurde als bezahlt markiert.',
'invoice' => true,
]);
}
}