Add reject functionality for workflow signatures

Implemented the ability to reject workflow signatures by adding necessary templates, routes, and authorization checks. Updated the `WorkflowSignatureCancelController` to handle rejection and modified existing templates and translations to support the new feature.
This commit is contained in:
Julien Fastré 2024-09-25 11:31:27 +02:00
parent 83121c2a83
commit cfce531754
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
7 changed files with 86 additions and 17 deletions

View File

@ -40,7 +40,36 @@ final readonly class WorkflowSignatureCancelController
#[Route('/{_locale}/main/workflow/signature/{id}/cancel', name: 'chill_main_workflow_signature_cancel')]
public function cancelSignature(EntityWorkflowStepSignature $signature, Request $request): Response
{
if (!$this->security->isGranted(EntityWorkflowStepSignatureVoter::CANCEL, $signature)) {
return $this->markSignatureAction(
$signature,
$request,
EntityWorkflowStepSignatureVoter::CANCEL,
function (EntityWorkflowStepSignature $signature) {$this->signatureStepStateChanger->markSignatureAsCanceled($signature); },
'@ChillMain/WorkflowSignature/cancel.html.twig',
);
}
#[Route('/{_locale}/main/workflow/signature/{id}/reject', name: 'chill_main_workflow_signature_reject')]
public function rejectSignature(EntityWorkflowStepSignature $signature, Request $request): Response
{
return $this->markSignatureAction(
$signature,
$request,
EntityWorkflowStepSignatureVoter::REJECT,
function (EntityWorkflowStepSignature $signature) {$this->signatureStepStateChanger->markSignatureAsRejected($signature); },
'@ChillMain/WorkflowSignature/reject.html.twig',
);
}
private function markSignatureAction(
EntityWorkflowStepSignature $signature,
Request $request,
string $permissionAttribute,
callable $markSignature,
string $template,
): Response {
if (!$this->security->isGranted($permissionAttribute, $signature)) {
throw new AccessDeniedHttpException('not allowed to cancel this signature');
}
@ -50,7 +79,7 @@ final readonly class WorkflowSignatureCancelController
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->signatureStepStateChanger->markSignatureAsCanceled($signature);
$markSignature($signature);
$this->entityManager->flush();
return new RedirectResponse(
@ -61,7 +90,7 @@ final readonly class WorkflowSignatureCancelController
return
new Response(
$this->twig->render(
'@ChillMain/WorkflowSignature/cancel.html.twig',
$template,
['form' => $form->createView(), 'signature' => $signature]
)
);

View File

@ -29,6 +29,11 @@
{% else %}
{% if (is_granted('CHILL_MAIN_ENTITY_WORKFLOW_SIGNATURE_CANCEL', s) or is_granted('CHILL_MAIN_ENTITY_WORKFLOW_SIGNATURE_SIGN', s)) %}
<ul class="record_actions slim">
{% if is_granted('CHILL_MAIN_ENTITY_WORKFLOW_SIGNATURE_REJECT', s) %}
<li>
<a class="btn btn-remove" href="{{ chill_path_add_return_path('chill_main_workflow_signature_reject', { 'id': s.id}) }}">{{ 'workflow.signature_zone.button_reject'|trans }}</a>
</li>
{% endif %}
{% if is_granted('CHILL_MAIN_ENTITY_WORKFLOW_SIGNATURE_CANCEL', s) %}
<li>
<a class="btn btn-misc" href="{{ chill_path_add_return_path('chill_main_workflow_signature_cancel', { 'id': s.id}) }}">{{ 'workflow.signature_zone.button_cancel'|trans }}</a>

View File

@ -5,7 +5,7 @@
{% block content %}
<h1>{{ block('title') }}</h1>
<p>{{ 'workflow.signature.are_you_sure'|trans({'%signer%': signature.signer|chill_entity_render_string}) }}</p>
<p>{{ 'workflow.signature.cancel_are_you_sure'|trans({'%signer%': signature.signer|chill_entity_render_string}) }}</p>
{{ form_start(form) }}
<ul class="record_actions sticky-form-buttons">

View File

@ -0,0 +1,20 @@
{% extends '@ChillMain/layout.html.twig' %}
{% block title %}{{ 'workflow.signature.reject_signature_of'|trans({ '%signer%': signature.signer|chill_entity_render_string }) }}{% endblock %}
{% block content %}
<h1>{{ block('title') }}</h1>
<p>{{ 'workflow.signature.reject_are_you_sure'|trans({'%signer%': signature.signer|chill_entity_render_string}) }}</p>
{{ form_start(form) }}
<ul class="record_actions sticky-form-buttons">
<li class="cancel">
<a class="btn btn-cancel" href="{{ chill_return_path_or('chill_main_workflow_show', {'id': signature.step.entityWorkflow.id}) }}">{{ 'Cancel'|trans }}</a>
</li>
<li>
{{ form_widget(form.confirm, {'attr': {'class': 'btn btn-misc'}}) }}
</li>
</ul>
{{ form_end(form) }}
{% endblock %}

View File

@ -22,10 +22,12 @@ final class EntityWorkflowStepSignatureVoter extends Voter
public const CANCEL = 'CHILL_MAIN_ENTITY_WORKFLOW_SIGNATURE_CANCEL';
public const REJECT = 'CHILL_MAIN_ENTITY_WORKFLOW_SIGNATURE_REJECT';
protected function supports(string $attribute, $subject)
{
return $subject instanceof EntityWorkflowStepSignature
&& in_array($attribute, [self::SIGN, self::CANCEL], true);
&& in_array($attribute, [self::SIGN, self::CANCEL, self::REJECT], true);
}
protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token)

View File

@ -34,11 +34,29 @@ class SignatureStepStateChanger
$signature
->setState(EntityWorkflowSignatureStateEnum::SIGNED)
->setZoneSignatureIndex($atIndex)
->setStateDate($this->clock->now())
;
->setStateDate($this->clock->now());
$this->logger->info(self::LOG_PREFIX.'Mark signature entity as signed', ['signatureId' => $signature->getId(), 'index' => (string) $atIndex]);
$this->onPostMark($signature);
}
public function markSignatureAsCanceled(EntityWorkflowStepSignature $signature): void
{
$signature
->setState(EntityWorkflowSignatureStateEnum::CANCELED)
->setStateDate($this->clock->now());
$this->logger->info(self::LOG_PREFIX.'Mark signature entity as canceled', ['signatureId' => $signature->getId()]);
}
public function markSignatureAsRejected(EntityWorkflowStepSignature $signature): void
{
$signature
->setState(EntityWorkflowSignatureStateEnum::REJECTED)
->setStateDate($this->clock->now());
$this->logger->info(self::LOG_PREFIX.'Mark signature entity as rejected', ['signatureId' => $signature->getId()]);
}
private function onPostMark(EntityWorkflowStepSignature $signature): void
{
if (!EntityWorkflowStepSignature::isAllSignatureNotPendingForStep($signature->getStep())) {
$this->logger->info(self::LOG_PREFIX.'This is not the last signature, skipping transition to another place', ['signatureId' => $signature->getId()]);
@ -89,13 +107,6 @@ class SignatureStepStateChanger
$this->logger->info(self::LOG_PREFIX.'Transition automatically applied', ['signatureId' => $signature->getId()]);
}
public function markSignatureAsCanceled(EntityWorkflowStepSignature $signature): void
{
$signature
->setState(EntityWorkflowSignatureStateEnum::CANCELED)
->setStateDate($this->clock->now());
}
private function getPreviousSender(EntityWorkflowStep $entityWorkflowStep): ?User
{
$stepsChained = $entityWorkflowStep->getEntityWorkflow()->getStepsChained();

View File

@ -539,6 +539,7 @@ workflow:
title: Signatures électroniques
button_sign: Signer
button_cancel: Annuler
button_reject: Rejeter
metadata:
sign_by: 'Signature pour %name%'
docType: Type de document
@ -553,8 +554,9 @@ workflow:
signature:
cancel_signature_of: Annulation de la signature de %signer%
are_you_sure: Êtes-vous sûr de vouloir annuler la signature de %signer%
cancel_are_you_sure: Êtes-vous sûr de vouloir annuler la signature de %signer%
reject_signature_of: Rejet de la signature de %signer%
reject_are_you_sure: Êtes-vous sûr de vouloir rejeter la signature de %signer%
Subscribe final: Recevoir une notification à l'étape finale
Subscribe all steps: Recevoir une notification à chaque étape