diff --git a/src/Controller/Administrative/Disposition/DocumentUploadController.php b/src/Controller/Administrative/Disposition/DocumentUploadController.php index c7dc8f3..702cc8c 100644 --- a/src/Controller/Administrative/Disposition/DocumentUploadController.php +++ b/src/Controller/Administrative/Disposition/DocumentUploadController.php @@ -31,22 +31,33 @@ class DocumentUploadController extends AbstractController } #[Route( - path: '/administrative/disposition/document-upload/{uuid}', + path: '/administrative/disposition/document-upload/{uuid}/{type}', name: 'app_administrative_disposition_document_upload' )] - #[IsGranted('CONTRACT_SUPPLEMENTARY', subject: 'disposition')] - public function index(Disposition $disposition, Request $request): Response + #[IsGranted('ADMIN_DOCUMENT_UPLOAD', subject: 'disposition')] + public function index(Disposition $disposition, string $type, Request $request): Response { + if (false === in_array($type, [Upload::TYPE_CONTRACT, Upload::TYPE_INVOICE], true)) { + throw $this->createNotFoundException('Unsupported document type'); + } + $teamer = $disposition->getTeamer(); - $modalTitle = sprintf('Honorarvertrag für %s hochladen', $teamer); + $modalTitle = Upload::TYPE_CONTRACT === $type + ? sprintf('Honorarvertrag für %s hochladen', $teamer) + : sprintf('Honorarnote für %s hochladen', $teamer); $form = $this->createFormBuilder()->getForm(); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $this->processUpload($disposition); + $this->processUpload($disposition, $type); - $this->addFlash('success', 'Der Honorarvertrag wurde hochgeladen'); + $this->addFlash( + 'success', + Upload::TYPE_CONTRACT === $type + ? 'Der Honorarvertrag wurde hochgeladen' + : 'Die Honorarnote wurde hochgeladen' + ); return new HxRedirectResponse($this->generateUrl('app_administrative_assignment_detail', [ 'uuid' => $disposition->getAssignment()->getUuid(), @@ -56,13 +67,16 @@ class DocumentUploadController extends AbstractController return $this->render('administrative/disposition/modal_document_upload.html.twig', [ 'disposition' => $disposition, 'modalTitle' => $modalTitle, + 'endpointUpload' => Upload::TYPE_CONTRACT === $type + ? '_uploader_upload_contract' + : '_uploader_upload_invoice', 'form' => $form->createView(), ]); } - private function processUpload(Disposition $disposition): void + private function processUpload(Disposition $disposition, string $type): void { - if (null !== $existingUpload = $disposition->getDocumentByType(Upload::TYPE_CONTRACT)) { + if (null !== $existingUpload = $disposition->getDocumentByType($type)) { $this->entityManager->remove($existingUpload); } @@ -76,23 +90,28 @@ class DocumentUploadController extends AbstractController $upload = Upload::fromUploadDto( $uploadSession->getUploads()->first(), $teamer->getUser(), - Upload::TYPE_CONTRACT + $type ); - $upload - ->setStatus(Upload::STATUS_CHECKED) - ->setApprovedAt(new \DateTimeImmutable()) - ->setApprovedBy($user->getInitials()) - ; + if (Upload::TYPE_CONTRACT === $type) { + $upload + ->setStatus(Upload::STATUS_CHECKED) + ->setApprovedAt(new \DateTimeImmutable()) + ->setApprovedBy($user->getInitials()) + ; - $disposition - ->addDocument($upload) - ->setStatus(Disposition::STATUS_CONFIRMED) - ; + $disposition->setStatus(Disposition::STATUS_CONFIRMED); + } else { + $upload->setStatus(Upload::STATUS_NEW); + + $disposition->setStatus(Disposition::STATUS_CHECKING_INVOICE); + } + + $disposition->addDocument($upload); $this->entityManager->flush(); - $this->uploadHandler->moveUploadSessionFilesFromOrphanage(Upload::TYPE_CONTRACT, $uploadSession); + $this->uploadHandler->moveUploadSessionFilesFromOrphanage($type, $uploadSession); $this->uploadHandler->destroyUploadSession(); if (true === $this->featureManager->isActive('sanitize_uploads')) { @@ -100,14 +119,16 @@ class DocumentUploadController extends AbstractController } $this->eventDispatcher->dispatch(new DocumentUploadedEvent($upload), DocumentUploadedEvent::NAME); - $this->eventDispatcher->dispatch(new DocumentConfirmedEvent($upload), DocumentConfirmedEvent::NAME); + if (Upload::TYPE_CONTRACT === $type) { + $this->eventDispatcher->dispatch(new DocumentConfirmedEvent($upload), DocumentConfirmedEvent::NAME); + } - $this->logger->info('Document upload for teamer', [ + $this->logger->info('Administrative document upload for teamer', [ 'teamer_id' => $teamer->getId(), 'teamer_name' => $teamer->getFullName(), 'disposition_id' => $disposition->getId(), 'document_id' => $upload->getId(), - 'upload_type' => Upload::TYPE_CONTRACT, + 'upload_type' => $type, ]); } } diff --git a/src/Security/Voter/DispositionVoter.php b/src/Security/Voter/DispositionVoter.php index 0182bfc..d076dce 100644 --- a/src/Security/Voter/DispositionVoter.php +++ b/src/Security/Voter/DispositionVoter.php @@ -16,6 +16,7 @@ class DispositionVoter extends Voter public const DELETE = 'DELETE'; public const CONTRACT = 'CONTRACT'; public const CONTRACT_SUPPLEMENTARY = 'CONTRACT_SUPPLEMENTARY'; + public const ADMIN_DOCUMENT_UPLOAD = 'ADMIN_DOCUMENT_UPLOAD'; public const INVOICE = 'INVOICE'; public const FEEDBACK = 'FEEDBACK'; public const CALL_OFF = 'CALL_OFF'; @@ -36,6 +37,7 @@ class DispositionVoter extends Voter static::DELETE, static::CONTRACT, static::CONTRACT_SUPPLEMENTARY, + static::ADMIN_DOCUMENT_UPLOAD, static::INVOICE, static::FEEDBACK, static::CALL_OFF, @@ -54,6 +56,7 @@ class DispositionVoter extends Voter static::FEEDBACK => $this->security->isGranted('ROLE_ADMINISTRATIVE') || $this->assertHouseManagerAccess($token, $disposition), static::CONTRACT_SUPPLEMENTARY => $this->assertContractUploadAllowed($disposition), + static::ADMIN_DOCUMENT_UPLOAD => $this->assertAdminDocumentUploadAllowed($disposition), static::CALL_OFF => $this->security->isGranted('ROLE_ADMINISTRATIVE') && Disposition::STATUS_CALLED_OFF !== $disposition->getStatus(), default => false, @@ -110,4 +113,14 @@ class DispositionVoter extends Voter return null === $existingContract || Upload::STATUS_REJECTED === $existingContract->getStatus(); } + + private function assertAdminDocumentUploadAllowed(Disposition $disposition): bool + { + if (false === $this->security->isGranted('ROLE_ADMINISTRATIVE') + && false === $this->security->isGranted('ROLE_ADMIN')) { + return false; + } + + return Disposition::STATUS_CALLED_OFF !== $disposition->getStatus(); + } } diff --git a/templates/administrative/assignment/detail.html.twig b/templates/administrative/assignment/detail.html.twig index e98c835..18230c5 100644 --- a/templates/administrative/assignment/detail.html.twig +++ b/templates/administrative/assignment/detail.html.twig @@ -176,54 +176,67 @@ {{ disposition.remarks|default('-')|nl2br }} {% endif %} -