Feat: Implement invoice pdf download for teamer
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
@@ -109,3 +109,7 @@ services:
|
|||||||
App\Service\Pdf\ContractRenderer:
|
App\Service\Pdf\ContractRenderer:
|
||||||
arguments:
|
arguments:
|
||||||
$options: { 'project_dir': '%kernel.project_dir%' }
|
$options: { 'project_dir': '%kernel.project_dir%' }
|
||||||
|
|
||||||
|
App\Service\Pdf\InvoiceRenderer:
|
||||||
|
arguments:
|
||||||
|
$options: { 'project_dir': '%kernel.project_dir%' }
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Controller\Teamer\Disposition;
|
||||||
|
|
||||||
|
use App\Entity\Disposition;
|
||||||
|
use App\Service\Pdf\InvoiceRenderer;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\HeaderUtils;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||||
|
|
||||||
|
class InvoicePdfController extends AbstractController
|
||||||
|
{
|
||||||
|
public function __construct(private readonly InvoiceRenderer $renderer)
|
||||||
|
{}
|
||||||
|
|
||||||
|
#[Route('/teamer/disposition/invoice/{uuid}', name: 'app_teamer_disposition_invoicepdf')]
|
||||||
|
#[IsGranted('INVOICE', subject: 'disposition')]
|
||||||
|
public function index(Disposition $disposition): Response
|
||||||
|
{
|
||||||
|
$pdf = $this->renderer->render($disposition);
|
||||||
|
|
||||||
|
$teamer = $disposition->getTeamer();
|
||||||
|
|
||||||
|
$filename = sprintf('Honorarnote_%s_%s.pdf', $teamer, $disposition->getAssignment()->getDestination());
|
||||||
|
$disposition = HeaderUtils::makeDisposition(HeaderUtils::DISPOSITION_ATTACHMENT, $filename, md5($filename));
|
||||||
|
|
||||||
|
$response = new Response($pdf->Output('S'));
|
||||||
|
$response->setPrivate();
|
||||||
|
$response->headers->set('Content-type', 'application/pdf');
|
||||||
|
$response->headers->set('Content-Disposition', $disposition);
|
||||||
|
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ class DispositionVoter extends Voter
|
|||||||
public const EDIT = 'EDIT';
|
public const EDIT = 'EDIT';
|
||||||
public const DELETE = 'DELETE';
|
public const DELETE = 'DELETE';
|
||||||
public const CONTRACT = 'CONTRACT';
|
public const CONTRACT = 'CONTRACT';
|
||||||
|
public const INVOICE = 'INVOICE';
|
||||||
|
|
||||||
protected function supports(string $attribute, mixed $subject): bool
|
protected function supports(string $attribute, mixed $subject): bool
|
||||||
{
|
{
|
||||||
@@ -20,7 +21,7 @@ class DispositionVoter extends Voter
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return in_array($attribute, [static::VIEW, static::EDIT, static::DELETE, static::CONTRACT]);
|
return in_array($attribute, [static::VIEW, static::EDIT, static::DELETE, static::CONTRACT, static::INVOICE]);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
|
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
|
||||||
@@ -31,15 +32,21 @@ class DispositionVoter extends Voter
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Teamers may only view or edit their own dispositions
|
// Teamers may only view or edit their own dispositions
|
||||||
if (in_array('ROLE_TEAMER', $token->getRoleNames()) && in_array($attribute, [static::VIEW, static::EDIT, static::CONTRACT])) {
|
if (in_array('ROLE_TEAMER', $token->getRoleNames())) {
|
||||||
/** @var User $user */
|
/** @var User $user */
|
||||||
$user = $token->getUser();
|
$user = $token->getUser();
|
||||||
$teamer = $user->getTeamer();
|
$teamer = $user->getTeamer();
|
||||||
/** @var Disposition $disposition */
|
/** @var Disposition $disposition */
|
||||||
$disposition = $subject;
|
$disposition = $subject;
|
||||||
|
|
||||||
|
switch ($attribute) {
|
||||||
|
case static::VIEW:
|
||||||
|
case static::EDIT:
|
||||||
|
case static::CONTRACT:
|
||||||
|
case static::INVOICE:
|
||||||
return $teamer === $disposition->getTeamer();
|
return $teamer === $disposition->getTeamer();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,8 +68,8 @@
|
|||||||
Hier findest du deine Honorarnote
|
Hier findest du deine Honorarnote
|
||||||
</h3>
|
</h3>
|
||||||
<div class="pb-4">
|
<div class="pb-4">
|
||||||
<a href="{{ path('app_teamer_disposition_contractpdf', { 'uuid': disposition.uuid }) }}" target="_blank" class="inline-block">
|
<a href="{{ path('app_teamer_disposition_invoicepdf', { 'uuid': disposition.uuid }) }}" target="_blank" class="inline-block">
|
||||||
<img src="{{ asset('build/images/contract_thumb.jpg') }}" alt="Honorarvertrag" class="block w-32 h-auto shadow-md">
|
<img src="{{ asset('build/images/invoice_thumb.jpg') }}" alt="Honorarnote" class="block w-32 h-auto shadow-md">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<p class="pb-4">
|
<p class="pb-4">
|
||||||
|
|||||||
Reference in New Issue
Block a user