From 194cd4e59ddb8fde001ebb18c26f51275744d258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Fri, 13 Oct 2023 17:20:13 +0200 Subject: [PATCH] Feat: Implement disposition document handling for admins --- config/packages/workflow.yaml | 6 + .../Admin/Document/CheckController.php | 107 ++++++++++++++++++ .../Admin/Document/DeleteController.php | 31 ----- src/Entity/Upload.php | 3 +- src/Event/DocumentRejectedEvent.php | 31 +++++ src/Form/DocumentCheckType.php | 53 +++++++++ src/Menu/TeamerMenuBuilder.php | 7 ++ src/Model/DocumentCheckDto.php | 46 ++++++++ src/Twig/AppRuntime.php | 2 +- templates/admin/document/check.html.twig | 13 +++ templates/admin/document/index.html.twig | 18 ++- translations/messages.de.yaml | 4 +- 12 files changed, 282 insertions(+), 39 deletions(-) create mode 100644 src/Controller/Admin/Document/CheckController.php delete mode 100644 src/Controller/Admin/Document/DeleteController.php create mode 100644 src/Event/DocumentRejectedEvent.php create mode 100644 src/Form/DocumentCheckType.php create mode 100644 src/Model/DocumentCheckDto.php create mode 100644 templates/admin/document/check.html.twig diff --git a/config/packages/workflow.yaml b/config/packages/workflow.yaml index bacf49d..f89b573 100644 --- a/config/packages/workflow.yaml +++ b/config/packages/workflow.yaml @@ -22,12 +22,18 @@ framework: confirm_contract: from: checking_contract to: confirmed + reject_contract: + from: checking_contract + to: new upload_invoice: from: confirmed to: checking_invoice confirm_invoice: from: checking_invoice to: paid + reject_invoice: + from: checking_invoice + to: confirmed complete: from: confirmed to: completed diff --git a/src/Controller/Admin/Document/CheckController.php b/src/Controller/Admin/Document/CheckController.php new file mode 100644 index 0000000..264eb3b --- /dev/null +++ b/src/Controller/Admin/Document/CheckController.php @@ -0,0 +1,107 @@ +generateUrl('app_admin_document_check', ['uuid' => $document->getUuid()]); + $form = $this->createForm( + DocumentCheckType::class, + $formData, + [ + 'action' => $formAction, + 'ajax_submit' => true, + 'document_type' => $document->getType(), + ] + ); + + $form->handleRequest($request); + + if ($form->isSubmitted() && $form->isValid()) { + switch ($formData->getStatus()) { + case Upload::STATUS_CHECKED: + $this->confirmDocument($document, 'confirm_contract', Upload::STATUS_CHECKED); + break; + case Upload::STATUS_PAID: + $this->confirmDocument($document, 'confirm_invoice', Upload::STATUS_PAID); + break; + case Upload::STATUS_REJECTED: + $this->rejectDocument($document); + $this->eventDispatcher->dispatch(new DocumentRejectedEvent($formData), DocumentRejectedEvent::NAME); + } + + $returnUrl = $this->generateUrl('app_admin_document_index'); + $response->setCloseAndRedirect($returnUrl); + } else { + $response->setContent($this->renderView('admin/document/check.html.twig', [ + 'document' => $document, + 'form' => $form, + ])); + } + + return $this->json($response); + } + + private function rejectDocument(Upload $document): void + { + $transition = Upload::TYPE_CONTRACT === $document->getType() ? 'reject_contract' : 'reject_invoice'; + $this->workflow->apply($document->getDisposition(), $transition); + $document->setStatus(Upload::STATUS_REJECTED); + $this->entityManager->flush(); + + $this->addFlash('success', 'Das Dokument wurde abgelehnt'); + $this->logger->info('Reject document', [ + 'document' => $document->getOriginalFilename(), + ]); + + } + + private function confirmDocument(Upload $document, string $transition, string $status): void + { + if (true === $this->workflow->can($document->getDisposition(), $transition)) { + $document->setStatus($status); + $this->workflow->apply($document->getDisposition(), $transition); + $this->entityManager->flush(); + $this->addFlash('success', 'Das Dokument wurde bestätigt'); + $this->logger->info('Confirm document', [ + 'document' => $document->getOriginalFilename(), + ]); + } else { + $blockers = $this->workflow->buildTransitionBlockerList($document->getDisposition(), $transition); + foreach ($blockers as $blocker) { + $this->addFlash('error', $blocker->getMessage()); + } + } + } +} diff --git a/src/Controller/Admin/Document/DeleteController.php b/src/Controller/Admin/Document/DeleteController.php deleted file mode 100644 index d12b05a..0000000 --- a/src/Controller/Admin/Document/DeleteController.php +++ /dev/null @@ -1,31 +0,0 @@ -entityManager->remove($document); - $this->entityManager->flush(); - - return $this->render(''); - } -} diff --git a/src/Entity/Upload.php b/src/Entity/Upload.php index c5814b7..f531601 100644 --- a/src/Entity/Upload.php +++ b/src/Entity/Upload.php @@ -22,10 +22,9 @@ class Upload implements BlameableEntityInterface, TimestampableEntityInterface public const TYPE_DOCUMENT = 'document'; public const STATUS_NEW = 'new'; - public const CHECKING = 'checking'; public const STATUS_CHECKED = 'checked'; public const STATUS_PAID = 'paid'; - public const STATUS_ERROR = 'error'; + public const STATUS_REJECTED = 'rejected'; #[ORM\Id] #[ORM\GeneratedValue] diff --git a/src/Event/DocumentRejectedEvent.php b/src/Event/DocumentRejectedEvent.php new file mode 100644 index 0000000..b079bde --- /dev/null +++ b/src/Event/DocumentRejectedEvent.php @@ -0,0 +1,31 @@ +document = $documentCheckDto->getUpload(); + $this->comment = $documentCheckDto->getComment(); + } + + public function getDocument(): Upload + { + return $this->document; + } + + public function getComment(): ?string + { + return $this->comment; + } +} \ No newline at end of file diff --git a/src/Form/DocumentCheckType.php b/src/Form/DocumentCheckType.php new file mode 100644 index 0000000..4ab305e --- /dev/null +++ b/src/Form/DocumentCheckType.php @@ -0,0 +1,53 @@ +add('status', ChoiceType::class, [ + 'label' => 'neuer Status', + 'choices' => $options['status_choices'][$options['document_type']], + ]) + ->add('comment', TextareaType::class, [ + 'label' => 'Kommentar/Begründung', + 'required' => false, + 'attr' => [ + 'rows' => 3, + ], + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver + ->setDefaults([ + 'data_class' => DocumentCheckDto::class, + 'status_choices' => [ + Upload::TYPE_CONTRACT => [ + 'bestätigt' => Upload::STATUS_CHECKED, + 'abgelehnt' => Upload::STATUS_REJECTED, + ], + Upload::TYPE_INVOICE => [ + 'bezahlt' => Upload::STATUS_PAID, + 'abgelehnt' => Upload::STATUS_REJECTED, + ], + ], + ]) + ->setRequired(['document_type']) + ->setAllowedTypes('document_type', 'string') + ->setAllowedValues('document_type', [Upload::TYPE_INVOICE, Upload::TYPE_CONTRACT]) + ; + } +} \ No newline at end of file diff --git a/src/Menu/TeamerMenuBuilder.php b/src/Menu/TeamerMenuBuilder.php index 7282cc3..3db2ecd 100644 --- a/src/Menu/TeamerMenuBuilder.php +++ b/src/Menu/TeamerMenuBuilder.php @@ -49,6 +49,13 @@ class TeamerMenuBuilder extends AbstractMenuBuilder [ 'route' => 'app_teamer_bookmark_index', 'title' => 'Merkliste', + 'children' => [ + [ + 'route' => 'app_teamer_assignment', + 'title' => 'Einsatzdetails', + 'routeParameters' => $this->getDefaultRouteParameters('uuid'), + ] + ], ], [ 'route' => 'app_teamer_application_index', diff --git a/src/Model/DocumentCheckDto.php b/src/Model/DocumentCheckDto.php new file mode 100644 index 0000000..1db3fe7 --- /dev/null +++ b/src/Model/DocumentCheckDto.php @@ -0,0 +1,46 @@ +upload = $upload; + } + + public function getUpload(): Upload + { + return $this->upload; + } + + public function getStatus(): string + { + return $this->status; + } + + public function setStatus(string $status): static + { + $this->status = $status; + + return $this; + } + + public function getComment(): ?string + { + return $this->comment; + } + + public function setComment(?string $comment): static + { + $this->comment = $comment; + + return $this; + } +} \ No newline at end of file diff --git a/src/Twig/AppRuntime.php b/src/Twig/AppRuntime.php index 17aa4fc..c2bc698 100644 --- a/src/Twig/AppRuntime.php +++ b/src/Twig/AppRuntime.php @@ -103,7 +103,7 @@ class AppRuntime implements RuntimeExtensionInterface $class = 'upload-status-badge '; $class .= match($status) { Upload::STATUS_NEW => 'upload-status-badge--new', - Upload::STATUS_ERROR => 'upload-status-badge--error', + Upload::STATUS_REJECTED => 'upload-status-badge--error', Upload::STATUS_PAID => 'upload-status-badge--paid', Upload::STATUS_CHECKED => 'upload-status-badge--checked', default => 'upload-status-badge--default', diff --git a/templates/admin/document/check.html.twig b/templates/admin/document/check.html.twig new file mode 100644 index 0000000..e7bd9e0 --- /dev/null +++ b/templates/admin/document/check.html.twig @@ -0,0 +1,13 @@ +{{ form_start(form) }} +

+ {{ ('label.document.type.' ~ document.type)|trans }} {{ document.disposition.teamer }} vom {{ document.createdAt|date('d.m.Y') }} +

+
+ {{ form_row(form.status) }} + {{ form_row(form.comment) }} +
+ +{{ form_rest(form) }} +{{ form_end(form) }} diff --git a/templates/admin/document/index.html.twig b/templates/admin/document/index.html.twig index f249be9..322b7ef 100644 --- a/templates/admin/document/index.html.twig +++ b/templates/admin/document/index.html.twig @@ -60,9 +60,21 @@ {{ upload.status|upload_status_badge }} - {% include '_partials/_dropdown.html.twig' with { 'links': [ - { 'url': path('app_common_download', { 'uuid': upload.uuid }), 'label': 'Download', 'target': '_blank' }, - ] } %} +
+ + + {{ icon('download') }} + +
{% else %} diff --git a/translations/messages.de.yaml b/translations/messages.de.yaml index 05f200a..0ad6b2a 100644 --- a/translations/messages.de.yaml +++ b/translations/messages.de.yaml @@ -19,8 +19,8 @@ label: new: neu checking: in Bearbeitung checked: geprüft - payed: bezahlt - error: Fehler + paid: bezahlt + rejected: abgelehnt message: confirm_contract: