mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-10-01 19:09:45 +00:00
Compare commits
47 Commits
421-signat
...
285-cancel
Author | SHA1 | Date | |
---|---|---|---|
111f72d996 | |||
67c29728f3 | |||
0f62ddc3d6 | |||
db3833190e | |||
fbb4e8c784 | |||
a41414a460 | |||
a3c1aa4679 | |||
99b801fb8a | |||
4087911262 | |||
d6a50888e0 | |||
705f3b6f76 | |||
6f8b25f457 | |||
ffef8b70a3 | |||
43a3d5c902 | |||
197b17fa76 | |||
229d62e676 | |||
b51a7cfc57 | |||
5d40948a63 | |||
9c1df94796 | |||
24eb220e90 | |||
9a262a3f43 | |||
b421e0b0af | |||
20b82ddbfc | |||
a568d3c5a2 | |||
260a42c35a | |||
5b4f47bfaa | |||
60706ae75b | |||
b561b12213 | |||
f4369f0e3c | |||
afa755f5a5 | |||
cb2308f808 | |||
432650e081 | |||
4215a90b0e | |||
24daae6ee5 | |||
5ae26a46eb | |||
aec32b9bf8 | |||
5b59bef990 | |||
e70de780a7 | |||
a546ec1e6e | |||
a5417855f2 | |||
2234093971 | |||
be499bee07 | |||
55faeaec39 | |||
ac24df3f3c | |||
64dc458844 | |||
5f57b5eae3 | |||
95de2c863d |
@@ -1,6 +0,0 @@
|
|||||||
kind: Feature
|
|
||||||
body: Only allow delete of attachment on workflows that are not final
|
|
||||||
time: 2025-07-24T16:15:56.042884578+02:00
|
|
||||||
custom:
|
|
||||||
Issue: ""
|
|
||||||
SchemaChange: No schema change
|
|
@@ -1,6 +0,0 @@
|
|||||||
kind: Feature
|
|
||||||
body: Move up signature buttons on index workflow page for easier access
|
|
||||||
time: 2025-07-24T16:16:28.609598883+02:00
|
|
||||||
custom:
|
|
||||||
Issue: ""
|
|
||||||
SchemaChange: No schema change
|
|
@@ -1,6 +0,0 @@
|
|||||||
kind: Feature
|
|
||||||
body: Filter out document from attachment list if it is the same as the workflow document
|
|
||||||
time: 2025-07-24T17:20:13.118537573+02:00
|
|
||||||
custom:
|
|
||||||
Issue: ""
|
|
||||||
SchemaChange: No schema change
|
|
@@ -13,6 +13,7 @@ namespace Chill\CalendarBundle\Controller;
|
|||||||
|
|
||||||
use Chill\CalendarBundle\Entity\Calendar;
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
use Chill\CalendarBundle\Form\CalendarType;
|
use Chill\CalendarBundle\Form\CalendarType;
|
||||||
|
use Chill\CalendarBundle\Form\CancelType;
|
||||||
use Chill\CalendarBundle\RemoteCalendar\Connector\RemoteCalendarConnectorInterface;
|
use Chill\CalendarBundle\RemoteCalendar\Connector\RemoteCalendarConnectorInterface;
|
||||||
use Chill\CalendarBundle\Repository\CalendarACLAwareRepositoryInterface;
|
use Chill\CalendarBundle\Repository\CalendarACLAwareRepositoryInterface;
|
||||||
use Chill\CalendarBundle\Security\Voter\CalendarVoter;
|
use Chill\CalendarBundle\Security\Voter\CalendarVoter;
|
||||||
@@ -30,6 +31,7 @@ use Chill\PersonBundle\Repository\PersonRepository;
|
|||||||
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodVoter;
|
||||||
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
use Chill\PersonBundle\Security\Authorization\PersonVoter;
|
||||||
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
use Chill\ThirdPartyBundle\Entity\ThirdParty;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
use http\Exception\UnexpectedValueException;
|
use http\Exception\UnexpectedValueException;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
@@ -60,6 +62,7 @@ class CalendarController extends AbstractController
|
|||||||
private readonly UserRepositoryInterface $userRepository,
|
private readonly UserRepositoryInterface $userRepository,
|
||||||
private readonly TranslatorInterface $translator,
|
private readonly TranslatorInterface $translator,
|
||||||
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
|
private readonly \Doctrine\Persistence\ManagerRegistry $managerRegistry,
|
||||||
|
private readonly EntityManagerInterface $em,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,6 +114,55 @@ class CalendarController extends AbstractController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route(path: '/{_locale}/calendar/calendar/{id}/cancel', name: 'chill_calendar_calendar_cancel')]
|
||||||
|
public function cancelAction(Calendar $calendar, Request $request): Response
|
||||||
|
{
|
||||||
|
// Deal with sms being sent or not
|
||||||
|
// Communicate cancellation with the remote calendar.
|
||||||
|
|
||||||
|
$this->denyAccessUnlessGranted(CalendarVoter::EDIT, $calendar);
|
||||||
|
|
||||||
|
[$person, $accompanyingPeriod] = [$calendar->getPerson(), $calendar->getAccompanyingPeriod()];
|
||||||
|
|
||||||
|
$form = $this->createForm(CancelType::class, $calendar);
|
||||||
|
$form->add('submit', SubmitType::class);
|
||||||
|
|
||||||
|
if ($accompanyingPeriod instanceof AccompanyingPeriod) {
|
||||||
|
$view = '@ChillCalendar/Calendar/cancelCalendarByAccompanyingCourse.html.twig';
|
||||||
|
$redirectRoute = $this->generateUrl('chill_calendar_calendar_list_by_period', ['id' => $accompanyingPeriod->getId()]);
|
||||||
|
} elseif ($person instanceof Person) {
|
||||||
|
$view = '@ChillCalendar/Calendar/cancelCalendarByPerson.html.twig';
|
||||||
|
$redirectRoute = $this->generateUrl('chill_calendar_calendar_list_by_person', ['id' => $person->getId()]);
|
||||||
|
} else {
|
||||||
|
throw new \RuntimeException('nor person or accompanying period');
|
||||||
|
}
|
||||||
|
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
|
||||||
|
$this->logger->notice('A calendar event has been cancelled', [
|
||||||
|
'by_user' => $this->getUser()->getUsername(),
|
||||||
|
'calendar_id' => $calendar->getId(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$calendar->setStatus($calendar::STATUS_CANCELED);
|
||||||
|
$calendar->setSmsStatus($calendar::SMS_CANCEL_PENDING);
|
||||||
|
$this->em->flush();
|
||||||
|
|
||||||
|
$this->addFlash('success', $this->translator->trans('chill_calendar.calendar_canceled'));
|
||||||
|
|
||||||
|
return new RedirectResponse($redirectRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render($view, [
|
||||||
|
'calendar' => $calendar,
|
||||||
|
'form' => $form->createView(),
|
||||||
|
'accompanyingCourse' => $accompanyingPeriod,
|
||||||
|
'person' => $person,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edit a calendar item.
|
* Edit a calendar item.
|
||||||
*/
|
*/
|
||||||
|
@@ -35,7 +35,7 @@ class LoadCancelReason extends Fixture implements FixtureGroupInterface
|
|||||||
$arr = [
|
$arr = [
|
||||||
['name' => CancelReason::CANCELEDBY_USER],
|
['name' => CancelReason::CANCELEDBY_USER],
|
||||||
['name' => CancelReason::CANCELEDBY_PERSON],
|
['name' => CancelReason::CANCELEDBY_PERSON],
|
||||||
['name' => CancelReason::CANCELEDBY_DONOTCOUNT],
|
['name' => CancelReason::CANCELEDBY_OTHER],
|
||||||
];
|
];
|
||||||
|
|
||||||
foreach ($arr as $a) {
|
foreach ($arr as $a) {
|
||||||
|
@@ -18,14 +18,14 @@ use Doctrine\ORM\Mapping as ORM;
|
|||||||
#[ORM\Table(name: 'chill_calendar.cancel_reason')]
|
#[ORM\Table(name: 'chill_calendar.cancel_reason')]
|
||||||
class CancelReason
|
class CancelReason
|
||||||
{
|
{
|
||||||
final public const CANCELEDBY_DONOTCOUNT = 'CANCELEDBY_DONOTCOUNT';
|
final public const CANCELEDBY_OTHER = 'CANCELEDBY_OTHER';
|
||||||
|
|
||||||
final public const CANCELEDBY_PERSON = 'CANCELEDBY_PERSON';
|
final public const CANCELEDBY_PERSON = 'CANCELEDBY_PERSON';
|
||||||
|
|
||||||
final public const CANCELEDBY_USER = 'CANCELEDBY_USER';
|
final public const CANCELEDBY_USER = 'CANCELEDBY_USER';
|
||||||
|
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN)]
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN, options: ['default' => true])]
|
||||||
private ?bool $active = null;
|
private bool $active = true;
|
||||||
|
|
||||||
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 255)]
|
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::STRING, length: 255)]
|
||||||
private ?string $canceledBy = null;
|
private ?string $canceledBy = null;
|
||||||
|
@@ -15,7 +15,7 @@ use Chill\CalendarBundle\Entity\CancelReason;
|
|||||||
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
use Chill\MainBundle\Form\Type\TranslatableStringFormType;
|
||||||
use Symfony\Component\Form\AbstractType;
|
use Symfony\Component\Form\AbstractType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
|
||||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
use Symfony\Component\Form\FormBuilderInterface;
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
@@ -28,7 +28,14 @@ class CancelReasonType extends AbstractType
|
|||||||
->add('active', CheckboxType::class, [
|
->add('active', CheckboxType::class, [
|
||||||
'required' => false,
|
'required' => false,
|
||||||
])
|
])
|
||||||
->add('canceledBy', TextType::class);
|
->add('canceledBy', ChoiceType::class, [
|
||||||
|
'choices' => [
|
||||||
|
'chill_calendar.canceled_by.user' => CancelReason::CANCELEDBY_USER,
|
||||||
|
'chill_calendar.canceled_by.person' => CancelReason::CANCELEDBY_PERSON,
|
||||||
|
'chill_calendar.canceled_by.other' => CancelReason::CANCELEDBY_OTHER,
|
||||||
|
],
|
||||||
|
'required' => true,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function configureOptions(OptionsResolver $resolver)
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
42
src/Bundle/ChillCalendarBundle/Form/CancelType.php
Normal file
42
src/Bundle/ChillCalendarBundle/Form/CancelType.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chill is a software for social workers
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view
|
||||||
|
* the LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Chill\CalendarBundle\Form;
|
||||||
|
|
||||||
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
|
use Chill\CalendarBundle\Entity\CancelReason;
|
||||||
|
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class CancelType extends AbstractType
|
||||||
|
{
|
||||||
|
public function __construct(private readonly TranslatableStringHelperInterface $translatableStringHelper) {}
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$builder->add('cancelReason', EntityType::class, [
|
||||||
|
'class' => CancelReason::class,
|
||||||
|
'required' => true,
|
||||||
|
'choice_label' => fn (CancelReason $cancelReason) => $this->translatableStringHelper->localize($cancelReason->getName()),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'data_class' => Calendar::class,
|
||||||
|
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
@@ -21,6 +21,7 @@ namespace Chill\CalendarBundle\Messenger\Doctrine;
|
|||||||
use Chill\CalendarBundle\Entity\Calendar;
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
use Chill\CalendarBundle\Messenger\Message\CalendarMessage;
|
use Chill\CalendarBundle\Messenger\Message\CalendarMessage;
|
||||||
use Chill\CalendarBundle\Messenger\Message\CalendarRemovedMessage;
|
use Chill\CalendarBundle\Messenger\Message\CalendarRemovedMessage;
|
||||||
|
use Chill\MainBundle\Entity\User;
|
||||||
use Doctrine\ORM\Event\PostPersistEventArgs;
|
use Doctrine\ORM\Event\PostPersistEventArgs;
|
||||||
use Doctrine\ORM\Event\PostRemoveEventArgs;
|
use Doctrine\ORM\Event\PostRemoveEventArgs;
|
||||||
use Doctrine\ORM\Event\PostUpdateEventArgs;
|
use Doctrine\ORM\Event\PostUpdateEventArgs;
|
||||||
@@ -31,6 +32,17 @@ class CalendarEntityListener
|
|||||||
{
|
{
|
||||||
public function __construct(private readonly MessageBusInterface $messageBus, private readonly Security $security) {}
|
public function __construct(private readonly MessageBusInterface $messageBus, private readonly Security $security) {}
|
||||||
|
|
||||||
|
private function getAuthenticatedUser(): User
|
||||||
|
{
|
||||||
|
$user = $this->security->getUser();
|
||||||
|
|
||||||
|
if (!$user instanceof User) {
|
||||||
|
throw new \LogicException('Expected an instance of User.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $user;
|
||||||
|
}
|
||||||
|
|
||||||
public function postPersist(Calendar $calendar, PostPersistEventArgs $args): void
|
public function postPersist(Calendar $calendar, PostPersistEventArgs $args): void
|
||||||
{
|
{
|
||||||
if (!$calendar->preventEnqueueChanges) {
|
if (!$calendar->preventEnqueueChanges) {
|
||||||
@@ -38,7 +50,7 @@ class CalendarEntityListener
|
|||||||
new CalendarMessage(
|
new CalendarMessage(
|
||||||
$calendar,
|
$calendar,
|
||||||
CalendarMessage::CALENDAR_PERSIST,
|
CalendarMessage::CALENDAR_PERSIST,
|
||||||
$this->security->getUser()
|
$this->getAuthenticatedUser()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -50,7 +62,7 @@ class CalendarEntityListener
|
|||||||
$this->messageBus->dispatch(
|
$this->messageBus->dispatch(
|
||||||
new CalendarRemovedMessage(
|
new CalendarRemovedMessage(
|
||||||
$calendar,
|
$calendar,
|
||||||
$this->security->getUser()
|
$this->getAuthenticatedUser()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -58,12 +70,19 @@ class CalendarEntityListener
|
|||||||
|
|
||||||
public function postUpdate(Calendar $calendar, PostUpdateEventArgs $args): void
|
public function postUpdate(Calendar $calendar, PostUpdateEventArgs $args): void
|
||||||
{
|
{
|
||||||
if (!$calendar->preventEnqueueChanges) {
|
if ($calendar->getStatus() === $calendar::STATUS_CANCELED) {
|
||||||
|
$this->messageBus->dispatch(
|
||||||
|
new CalendarRemovedMessage(
|
||||||
|
$calendar,
|
||||||
|
$this->getAuthenticatedUser()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} elseif (!$calendar->preventEnqueueChanges) {
|
||||||
$this->messageBus->dispatch(
|
$this->messageBus->dispatch(
|
||||||
new CalendarMessage(
|
new CalendarMessage(
|
||||||
$calendar,
|
$calendar,
|
||||||
CalendarMessage::CALENDAR_UPDATE,
|
CalendarMessage::CALENDAR_UPDATE,
|
||||||
$this->security->getUser()
|
$this->getAuthenticatedUser()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -70,6 +70,8 @@ class CalendarRemovedMessage
|
|||||||
|
|
||||||
public function getRemoteId(): string
|
public function getRemoteId(): string
|
||||||
{
|
{
|
||||||
|
dump($this->remoteId);
|
||||||
|
|
||||||
return $this->remoteId;
|
return $this->remoteId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
Chill\CalendarBundle\Controller\:
|
Chill\CalendarBundle\Controller\:
|
||||||
autowire: true
|
autowire: true
|
||||||
|
autoconfigure: true
|
||||||
resource: '../../../Controller'
|
resource: '../../../Controller'
|
||||||
tags: ['controller.service_arguments']
|
tags: ['controller.service_arguments']
|
||||||
|
@@ -9,9 +9,20 @@
|
|||||||
<div class="item-row main">
|
<div class="item-row main">
|
||||||
<div class="item-col">
|
<div class="item-col">
|
||||||
<div class="wrap-header">
|
<div class="wrap-header">
|
||||||
|
<div class="wl-row">
|
||||||
|
{% if calendar.status == 'canceled' %}
|
||||||
|
<div class="badge rounded-pill bg-danger">
|
||||||
|
<span>{{ 'chill_calendar.canceled'|trans }}: </span>
|
||||||
|
<span>{{ calendar.cancelReason.name|localize_translatable_string }}</span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
<div class="wl-row">
|
<div class="wl-row">
|
||||||
<div class="wl-col title">
|
<div class="wl-col title">
|
||||||
<p class="date-label">
|
<p class="date-label">
|
||||||
|
{% if calendar.status == 'canceled' %}
|
||||||
|
<del>
|
||||||
|
{% endif %}
|
||||||
{% if context == 'person' and calendar.context == 'accompanying_period' %}
|
{% if context == 'person' and calendar.context == 'accompanying_period' %}
|
||||||
<a href="{{ chill_path_add_return_path('chill_person_accompanying_course_index', {'accompanying_period_id': calendar.accompanyingPeriod.id}) }}" style="text-decoration: none;">
|
<a href="{{ chill_path_add_return_path('chill_person_accompanying_course_index', {'accompanying_period_id': calendar.accompanyingPeriod.id}) }}" style="text-decoration: none;">
|
||||||
<span class="badge bg-primary">
|
<span class="badge bg-primary">
|
||||||
@@ -19,6 +30,9 @@
|
|||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if calendar.status == 'canceled' %}
|
||||||
|
<del>
|
||||||
|
{% endif %}
|
||||||
{% if calendar.endDate.diff(calendar.startDate).days >= 1 %}
|
{% if calendar.endDate.diff(calendar.startDate).days >= 1 %}
|
||||||
{{ calendar.startDate|format_datetime('short', 'short') }}
|
{{ calendar.startDate|format_datetime('short', 'short') }}
|
||||||
- {{ calendar.endDate|format_datetime('short', 'short') }}
|
- {{ calendar.endDate|format_datetime('short', 'short') }}
|
||||||
@@ -26,13 +40,15 @@
|
|||||||
{{ calendar.startDate|format_datetime('short', 'short') }}
|
{{ calendar.startDate|format_datetime('short', 'short') }}
|
||||||
- {{ calendar.endDate|format_datetime('none', 'short') }}
|
- {{ calendar.endDate|format_datetime('none', 'short') }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
{% if calendar.status == 'canceled' %}
|
||||||
|
</del>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="duration short-message">
|
<div class="duration short-message">
|
||||||
<i class="fa fa-fw fa-hourglass-end"></i>
|
<i class="fa fa-fw fa-hourglass-end"></i>
|
||||||
{{ calendar.duration|date('%H:%I') }}
|
{{ calendar.duration|date('%H:%I') }}
|
||||||
{% if false == calendar.sendSMS or null == calendar.sendSMS %}
|
{% if false == calendar.sendSMS or null == calendar.sendSMS %}
|
||||||
<!-- no sms will be send -->
|
<!-- no sms will be sent -->
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if calendar.smsStatus == 'sms_sent' %}
|
{% if calendar.smsStatus == 'sms_sent' %}
|
||||||
<span title="{{ 'SMS already sent'|trans }}" class="badge bg-info">
|
<span title="{{ 'SMS already sent'|trans }}" class="badge bg-info">
|
||||||
@@ -63,8 +79,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if calendar.comment.comment is not empty
|
{% if calendar.users|length > 0
|
||||||
or calendar.users|length > 0
|
|
||||||
or calendar.thirdParties|length > 0
|
or calendar.thirdParties|length > 0
|
||||||
or calendar.users|length > 0 %}
|
or calendar.users|length > 0 %}
|
||||||
<div class="item-row details separator">
|
<div class="item-row details separator">
|
||||||
@@ -103,12 +118,13 @@
|
|||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if calendar.documents is not empty %}
|
||||||
<div class="item-row separator column">
|
<div class="item-row separator column">
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
{{ include('@ChillCalendar/Calendar/_documents.twig.html') }}
|
{{ include('@ChillCalendar/Calendar/_documents.twig.html') }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if calendar.activity is not null %}
|
{% if calendar.activity is not null %}
|
||||||
<div class="item-row separator">
|
<div class="item-row separator">
|
||||||
@@ -151,7 +167,7 @@
|
|||||||
|
|
||||||
<div class="item-row separator">
|
<div class="item-row separator">
|
||||||
<ul class="record_actions">
|
<ul class="record_actions">
|
||||||
{% if is_granted('CHILL_CALENDAR_DOC_EDIT', calendar) %}
|
{% if is_granted('CHILL_CALENDAR_DOC_EDIT', calendar) and calendar.status is not constant('STATUS_CANCELED', calendar) %}
|
||||||
{% if templates|length == 0 %}
|
{% if templates|length == 0 %}
|
||||||
<li>
|
<li>
|
||||||
<a class="btn btn-create"
|
<a class="btn btn-create"
|
||||||
@@ -191,6 +207,7 @@
|
|||||||
or
|
or
|
||||||
(calendar.context == 'person' and is_granted('CHILL_ACTIVITY_CREATE', calendar.person))
|
(calendar.context == 'person' and is_granted('CHILL_ACTIVITY_CREATE', calendar.person))
|
||||||
)
|
)
|
||||||
|
and calendar.status is not constant('STATUS_CANCELED', calendar)
|
||||||
%}
|
%}
|
||||||
<li>
|
<li>
|
||||||
<a class="btn btn-create"
|
<a class="btn btn-create"
|
||||||
@@ -213,12 +230,18 @@
|
|||||||
class="btn btn-show "></a>
|
class="btn btn-show "></a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if is_granted('CHILL_CALENDAR_CALENDAR_EDIT', calendar) %}
|
|
||||||
|
{% if is_granted('CHILL_CALENDAR_CALENDAR_EDIT', calendar) and calendar.status is not constant('STATUS_CANCELED', calendar) %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_edit', { 'id': calendar.id }) }}"
|
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_edit', { 'id': calendar.id }) }}"
|
||||||
class="btn btn-update "></a>
|
class="btn btn-update "></a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_cancel', { 'id': calendar.id } ) }}"
|
||||||
|
class="btn btn-remove">{{ 'Cancel'|trans }}</a>
|
||||||
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if is_granted('CHILL_CALENDAR_CALENDAR_DELETE', calendar) %}
|
{% if is_granted('CHILL_CALENDAR_CALENDAR_DELETE', calendar) %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_delete', { 'id': calendar.id } ) }}"
|
<a href="{{ chill_path_add_return_path('chill_calendar_calendar_delete', { 'id': calendar.id } ) }}"
|
||||||
|
@@ -0,0 +1,29 @@
|
|||||||
|
{% extends "@ChillPerson/AccompanyingCourse/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = 'chill_calendar_calendar_list' %}
|
||||||
|
|
||||||
|
{% block title 'chill_calendar.cancel_calendar_item'|trans %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{{ form_start(form) }}
|
||||||
|
|
||||||
|
{{ form_row(form.cancelReason) }}
|
||||||
|
|
||||||
|
<ul class="record_actions sticky-form-buttons">
|
||||||
|
<li class="save">
|
||||||
|
<a
|
||||||
|
class="btn btn-cancel"
|
||||||
|
href="{{ chill_return_path_or('chill_calendar_calendar_list', { 'id': accompanyingCourse.id } )}}"
|
||||||
|
>
|
||||||
|
{{ 'Cancel'|trans|chill_return_path_label }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{{ form_widget(form.submit, { 'attr' : { 'class': 'btn btn-save' }, 'label': 'Save' } ) }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{ form_end(form) }}
|
||||||
|
|
||||||
|
{% endblock %}
|
@@ -0,0 +1,29 @@
|
|||||||
|
{% extends "@ChillPerson/Person/layout.html.twig" %}
|
||||||
|
|
||||||
|
{% set activeRouteKey = 'chill_calendar_calendar_list' %}
|
||||||
|
|
||||||
|
{% block title 'chill_calendar.cancel_calendar_item'|trans %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
{{ form_start(form) }}
|
||||||
|
|
||||||
|
{{ form_row(form.cancelReason) }}
|
||||||
|
|
||||||
|
<ul class="record_actions sticky-form-buttons">
|
||||||
|
<li class="save">
|
||||||
|
<a
|
||||||
|
class="btn btn-cancel"
|
||||||
|
href="{{ chill_return_path_or('chill_calendar_calendar_list', { 'id': person.id } )}}"
|
||||||
|
>
|
||||||
|
{{ 'Cancel'|trans|chill_return_path_label }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{{ form_widget(form.submit, { 'attr' : { 'class': 'btn btn-save' }, 'label': 'Save' } ) }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{{ form_end(form) }}
|
||||||
|
|
||||||
|
{% endblock %}
|
@@ -5,7 +5,7 @@
|
|||||||
{% block table_entities_thead_tr %}
|
{% block table_entities_thead_tr %}
|
||||||
<th>{{ 'Id'|trans }}</th>
|
<th>{{ 'Id'|trans }}</th>
|
||||||
<th>{{ 'Name'|trans }}</th>
|
<th>{{ 'Name'|trans }}</th>
|
||||||
<th>{{ 'canceledBy'|trans }}</th>
|
<th>{{ 'Canceled by'|trans }}</th>
|
||||||
<th>{{ 'active'|trans }}</th>
|
<th>{{ 'active'|trans }}</th>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@@ -19,6 +19,7 @@ declare(strict_types=1);
|
|||||||
namespace Chill\CalendarBundle\Service\ShortMessageNotification;
|
namespace Chill\CalendarBundle\Service\ShortMessageNotification;
|
||||||
|
|
||||||
use Chill\CalendarBundle\Entity\Calendar;
|
use Chill\CalendarBundle\Entity\Calendar;
|
||||||
|
use Chill\CalendarBundle\Entity\CancelReason;
|
||||||
use libphonenumber\PhoneNumberFormat;
|
use libphonenumber\PhoneNumberFormat;
|
||||||
use libphonenumber\PhoneNumberUtil;
|
use libphonenumber\PhoneNumberUtil;
|
||||||
use Symfony\Component\Notifier\Message\SmsMessage;
|
use Symfony\Component\Notifier\Message\SmsMessage;
|
||||||
@@ -57,7 +58,7 @@ class DefaultShortMessageForCalendarBuilder implements ShortMessageForCalendarBu
|
|||||||
$this->phoneUtil->format($person->getMobilenumber(), PhoneNumberFormat::E164),
|
$this->phoneUtil->format($person->getMobilenumber(), PhoneNumberFormat::E164),
|
||||||
$this->engine->render('@ChillCalendar/CalendarShortMessage/short_message.txt.twig', ['calendar' => $calendar]),
|
$this->engine->render('@ChillCalendar/CalendarShortMessage/short_message.txt.twig', ['calendar' => $calendar]),
|
||||||
);
|
);
|
||||||
} elseif (Calendar::SMS_CANCEL_PENDING === $calendar->getSmsStatus()) {
|
} elseif (Calendar::SMS_CANCEL_PENDING === $calendar->getSmsStatus() && (null === $calendar->getCancelReason() || CancelReason::CANCELEDBY_PERSON !== $calendar->getCancelReason()->getCanceledBy())) {
|
||||||
$toUsers[] = new SmsMessage(
|
$toUsers[] = new SmsMessage(
|
||||||
$this->phoneUtil->format($person->getMobilenumber(), PhoneNumberFormat::E164),
|
$this->phoneUtil->format($person->getMobilenumber(), PhoneNumberFormat::E164),
|
||||||
$this->engine->render('@ChillCalendar/CalendarShortMessage/short_message_canceled.txt.twig', ['calendar' => $calendar]),
|
$this->engine->render('@ChillCalendar/CalendarShortMessage/short_message_canceled.txt.twig', ['calendar' => $calendar]),
|
||||||
|
@@ -31,8 +31,7 @@ Will send SMS: Un SMS de rappel sera envoyé
|
|||||||
Will not send SMS: Aucun SMS de rappel ne sera envoyé
|
Will not send SMS: Aucun SMS de rappel ne sera envoyé
|
||||||
SMS already sent: Un SMS a été envoyé
|
SMS already sent: Un SMS a été envoyé
|
||||||
|
|
||||||
canceledBy: supprimé par
|
Canceled by: Annulé par
|
||||||
Canceled by: supprimé par
|
|
||||||
Calendar configuration: Gestion des rendez-vous
|
Calendar configuration: Gestion des rendez-vous
|
||||||
|
|
||||||
crud:
|
crud:
|
||||||
@@ -44,6 +43,14 @@ crud:
|
|||||||
title_edit: Modifier le motif d'annulation
|
title_edit: Modifier le motif d'annulation
|
||||||
|
|
||||||
chill_calendar:
|
chill_calendar:
|
||||||
|
canceled: Annulé
|
||||||
|
cancel_reason: Raison d'annulation
|
||||||
|
cancel_calendar_item: Annuler rendez-vous
|
||||||
|
calendar_canceled: Le rendez-vous a été annulé
|
||||||
|
canceled_by:
|
||||||
|
user: Utilisateur
|
||||||
|
person: Usager
|
||||||
|
other: Autre
|
||||||
Document: Document d'un rendez-vous
|
Document: Document d'un rendez-vous
|
||||||
form:
|
form:
|
||||||
The main user is mandatory. He will organize the appointment.: L'utilisateur principal est obligatoire. Il est l'organisateur de l'événement.
|
The main user is mandatory. He will organize the appointment.: L'utilisateur principal est obligatoire. Il est l'organisateur de l'événement.
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import {fetchResults, makeFetch} from "ChillMainAssets/lib/api/apiMethods";
|
import { fetchResults } from "ChillMainAssets/lib/api/apiMethods";
|
||||||
import { GenericDocForAccompanyingPeriod } from "ChillDocStoreAssets/types/generic_doc";
|
import { GenericDocForAccompanyingPeriod } from "ChillDocStoreAssets/types/generic_doc";
|
||||||
import {EntityWorkflow} from "ChillMainAssets/types";
|
|
||||||
|
|
||||||
export function fetch_generic_docs_by_accompanying_period(
|
export function fetch_generic_docs_by_accompanying_period(
|
||||||
periodId: number,
|
periodId: number,
|
||||||
@@ -9,17 +8,3 @@ export function fetch_generic_docs_by_accompanying_period(
|
|||||||
`/api/1.0/doc-store/generic-doc/by-period/${periodId}/index`,
|
`/api/1.0/doc-store/generic-doc/by-period/${periodId}/index`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const fetchWorkflow = async (
|
|
||||||
workflowId: number,
|
|
||||||
): Promise<EntityWorkflow> => {
|
|
||||||
try {
|
|
||||||
return await makeFetch<null, EntityWorkflow>(
|
|
||||||
"GET",
|
|
||||||
`/api/1.0/main/workflow/${workflowId}.json`,
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Failed to fetch workflow ${workflowId}:`, error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
@@ -25,7 +25,7 @@ export interface GenericDoc {
|
|||||||
type: "doc_store_generic_doc";
|
type: "doc_store_generic_doc";
|
||||||
uniqueKey: string;
|
uniqueKey: string;
|
||||||
key: string;
|
key: string;
|
||||||
identifiers: { id: number; };
|
identifiers: object;
|
||||||
context: "person" | "accompanying-period";
|
context: "person" | "accompanying-period";
|
||||||
doc_date: DateTime;
|
doc_date: DateTime;
|
||||||
metadata: GenericDocMetadata;
|
metadata: GenericDocMetadata;
|
||||||
|
@@ -11,7 +11,6 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Chill\MainBundle\Controller;
|
namespace Chill\MainBundle\Controller;
|
||||||
|
|
||||||
use Chill\MainBundle\CRUD\Controller\ApiController;
|
|
||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
|
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
|
||||||
use Chill\MainBundle\Pagination\PaginatorFactory;
|
use Chill\MainBundle\Pagination\PaginatorFactory;
|
||||||
@@ -28,7 +27,7 @@ use Symfony\Component\Security\Core\Exception\AccessDeniedException;
|
|||||||
use Symfony\Component\Security\Core\Security;
|
use Symfony\Component\Security\Core\Security;
|
||||||
use Symfony\Component\Serializer\SerializerInterface;
|
use Symfony\Component\Serializer\SerializerInterface;
|
||||||
|
|
||||||
class WorkflowApiController extends ApiController
|
class WorkflowApiController
|
||||||
{
|
{
|
||||||
public function __construct(private readonly EntityManagerInterface $entityManager, private readonly EntityWorkflowRepository $entityWorkflowRepository, private readonly PaginatorFactory $paginatorFactory, private readonly Security $security, private readonly SerializerInterface $serializer) {}
|
public function __construct(private readonly EntityManagerInterface $entityManager, private readonly EntityWorkflowRepository $entityWorkflowRepository, private readonly PaginatorFactory $paginatorFactory, private readonly Security $security, private readonly SerializerInterface $serializer) {}
|
||||||
|
|
||||||
|
@@ -44,7 +44,7 @@ final readonly class WorkflowSignatureStateChangeController
|
|||||||
$signature,
|
$signature,
|
||||||
$request,
|
$request,
|
||||||
EntityWorkflowStepSignatureVoter::CANCEL,
|
EntityWorkflowStepSignatureVoter::CANCEL,
|
||||||
function (EntityWorkflowStepSignature $signature): string { return $this->signatureStepStateChanger->markSignatureAsCanceled($signature); },
|
function (EntityWorkflowStepSignature $signature) {$this->signatureStepStateChanger->markSignatureAsCanceled($signature); },
|
||||||
'@ChillMain/WorkflowSignature/cancel.html.twig',
|
'@ChillMain/WorkflowSignature/cancel.html.twig',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -56,32 +56,11 @@ final readonly class WorkflowSignatureStateChangeController
|
|||||||
$signature,
|
$signature,
|
||||||
$request,
|
$request,
|
||||||
EntityWorkflowStepSignatureVoter::REJECT,
|
EntityWorkflowStepSignatureVoter::REJECT,
|
||||||
function (EntityWorkflowStepSignature $signature): string { return $this->signatureStepStateChanger->markSignatureAsRejected($signature); },
|
function (EntityWorkflowStepSignature $signature) {$this->signatureStepStateChanger->markSignatureAsRejected($signature); },
|
||||||
'@ChillMain/WorkflowSignature/reject.html.twig',
|
'@ChillMain/WorkflowSignature/reject.html.twig',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/{_locale}/main/workflow/signature/{id}/wait/{expectedStep}', name: 'chill_main_workflow_signature_wait', methods: ['GET'])]
|
|
||||||
public function waitForSignatureChange(EntityWorkflowStepSignature $signature, string $expectedStep, Request $request): Response
|
|
||||||
{
|
|
||||||
if ($signature->getStep()->getEntityWorkflow()->getStep() === $expectedStep) {
|
|
||||||
return new RedirectResponse(
|
|
||||||
$this->chillUrlGenerator->returnPathOr('chill_main_workflow_show', ['id' => $signature->getStep()->getEntityWorkflow()->getId()])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Response(
|
|
||||||
$this->twig->render('@ChillMain/WorkflowSignature/waiting.html.twig', ['signature' => $signature, 'expectedStep' => $expectedStep])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param callable(EntityWorkflowStepSignature): string $markSignature
|
|
||||||
*
|
|
||||||
* @throws \Twig\Error\LoaderError
|
|
||||||
* @throws \Twig\Error\RuntimeError
|
|
||||||
* @throws \Twig\Error\SyntaxError
|
|
||||||
*/
|
|
||||||
private function markSignatureAction(
|
private function markSignatureAction(
|
||||||
EntityWorkflowStepSignature $signature,
|
EntityWorkflowStepSignature $signature,
|
||||||
Request $request,
|
Request $request,
|
||||||
@@ -100,17 +79,12 @@ final readonly class WorkflowSignatureStateChangeController
|
|||||||
$form->handleRequest($request);
|
$form->handleRequest($request);
|
||||||
|
|
||||||
if ($form->isSubmitted() && $form->isValid()) {
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
$expectedStep = $this->entityManager->wrapInTransaction(function () use ($signature, $markSignature) {
|
$this->entityManager->wrapInTransaction(function () use ($signature, $markSignature) {
|
||||||
dump(__METHOD__);
|
$markSignature($signature);
|
||||||
|
|
||||||
return dump($markSignature($signature));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return new RedirectResponse(
|
return new RedirectResponse(
|
||||||
$this->chillUrlGenerator->forwardReturnPath(
|
$this->chillUrlGenerator->returnPathOr('chill_main_workflow_show', ['id' => $signature->getStep()->getEntityWorkflow()->getId()])
|
||||||
'chill_main_workflow_signature_wait',
|
|
||||||
['id' => $signature->getId(), 'expectedStep' => $expectedStep]
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -30,7 +30,6 @@ use Chill\MainBundle\Controller\UserGroupAdminController;
|
|||||||
use Chill\MainBundle\Controller\UserGroupApiController;
|
use Chill\MainBundle\Controller\UserGroupApiController;
|
||||||
use Chill\MainBundle\Controller\UserJobApiController;
|
use Chill\MainBundle\Controller\UserJobApiController;
|
||||||
use Chill\MainBundle\Controller\UserJobController;
|
use Chill\MainBundle\Controller\UserJobController;
|
||||||
use Chill\MainBundle\Controller\WorkflowApiController;
|
|
||||||
use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
|
use Chill\MainBundle\DependencyInjection\Widget\Factory\WidgetFactoryInterface;
|
||||||
use Chill\MainBundle\Doctrine\DQL\Age;
|
use Chill\MainBundle\Doctrine\DQL\Age;
|
||||||
use Chill\MainBundle\Doctrine\DQL\Extract;
|
use Chill\MainBundle\Doctrine\DQL\Extract;
|
||||||
@@ -67,7 +66,6 @@ use Chill\MainBundle\Entity\Regroupment;
|
|||||||
use Chill\MainBundle\Entity\User;
|
use Chill\MainBundle\Entity\User;
|
||||||
use Chill\MainBundle\Entity\UserGroup;
|
use Chill\MainBundle\Entity\UserGroup;
|
||||||
use Chill\MainBundle\Entity\UserJob;
|
use Chill\MainBundle\Entity\UserJob;
|
||||||
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
|
|
||||||
use Chill\MainBundle\Form\CenterType;
|
use Chill\MainBundle\Form\CenterType;
|
||||||
use Chill\MainBundle\Form\CivilityType;
|
use Chill\MainBundle\Form\CivilityType;
|
||||||
use Chill\MainBundle\Form\CountryType;
|
use Chill\MainBundle\Form\CountryType;
|
||||||
@@ -81,7 +79,6 @@ use Chill\MainBundle\Form\UserGroupType;
|
|||||||
use Chill\MainBundle\Form\UserJobType;
|
use Chill\MainBundle\Form\UserJobType;
|
||||||
use Chill\MainBundle\Form\UserType;
|
use Chill\MainBundle\Form\UserType;
|
||||||
use Chill\MainBundle\Security\Authorization\ChillExportVoter;
|
use Chill\MainBundle\Security\Authorization\ChillExportVoter;
|
||||||
use Chill\MainBundle\Security\Authorization\EntityWorkflowVoter;
|
|
||||||
use Misd\PhoneNumberBundle\Doctrine\DBAL\Types\PhoneNumberType;
|
use Misd\PhoneNumberBundle\Doctrine\DBAL\Types\PhoneNumberType;
|
||||||
use Ramsey\Uuid\Doctrine\UuidType;
|
use Ramsey\Uuid\Doctrine\UuidType;
|
||||||
use Symfony\Component\Config\FileLocator;
|
use Symfony\Component\Config\FileLocator;
|
||||||
@@ -943,21 +940,6 @@ class ChillMainExtension extends Extension implements
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
[
|
|
||||||
'class' => EntityWorkflow::class,
|
|
||||||
'name' => 'workflow',
|
|
||||||
'base_path' => '/api/1.0/main/workflow',
|
|
||||||
'base_role' => EntityWorkflowVoter::SEE,
|
|
||||||
'controller' => WorkflowApiController::class,
|
|
||||||
'actions' => [
|
|
||||||
'_entity' => [
|
|
||||||
'methods' => [
|
|
||||||
Request::METHOD_GET => true,
|
|
||||||
Request::METHOD_HEAD => true,
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import { GenericDoc } from "ChillDocStoreAssets/types/generic_doc";
|
import { GenericDoc } from "ChillDocStoreAssets/types/generic_doc";
|
||||||
import { StoredObject, StoredObjectStatus } from "ChillDocStoreAssets/types";
|
import { StoredObject, StoredObjectStatus } from "ChillDocStoreAssets/types";
|
||||||
import {Person} from "../../../ChillPersonBundle/Resources/public/types";
|
|
||||||
|
|
||||||
export interface DateTime {
|
export interface DateTime {
|
||||||
datetime: string;
|
datetime: string;
|
||||||
@@ -203,55 +202,6 @@ export interface WorkflowAttachment {
|
|||||||
genericDoc: null | GenericDoc;
|
genericDoc: null | GenericDoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Workflow {
|
|
||||||
name: string;
|
|
||||||
text: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EntityWorkflowStep {
|
|
||||||
type: "entity_workflow_step";
|
|
||||||
id: number;
|
|
||||||
comment: string;
|
|
||||||
currentStep: StepDefinition;
|
|
||||||
isFinal: boolean;
|
|
||||||
isFreezed: boolean;
|
|
||||||
isFinalized: boolean;
|
|
||||||
transitionPrevious: Transition | null;
|
|
||||||
transitionAfter: Transition | null;
|
|
||||||
previousId: number | null;
|
|
||||||
nextId: number | null;
|
|
||||||
transitionPreviousBy: User | null;
|
|
||||||
transitionPreviousAt: DateTime | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Transition {
|
|
||||||
name: string;
|
|
||||||
text: string;
|
|
||||||
isForward: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StepDefinition {
|
|
||||||
name: string;
|
|
||||||
text: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface EntityWorkflow {
|
|
||||||
type: "entity_workflow";
|
|
||||||
id: number;
|
|
||||||
relatedEntityClass: string;
|
|
||||||
relatedEntityId: number;
|
|
||||||
workflow: Workflow;
|
|
||||||
currentStep: EntityWorkflowStep;
|
|
||||||
steps: EntityWorkflowStep[];
|
|
||||||
datas: WorkflowData;
|
|
||||||
title: string;
|
|
||||||
isOnHoldAtCurrentStep: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WorkflowData {
|
|
||||||
persons: Person[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ExportGeneration {
|
export interface ExportGeneration {
|
||||||
id: string;
|
id: string;
|
||||||
type: "export_generation";
|
type: "export_generation";
|
||||||
|
@@ -1,11 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {computed, onMounted, ref, useTemplateRef} from "vue";
|
import { computed, useTemplateRef } from "vue";
|
||||||
import type {EntityWorkflow, WorkflowAttachment} from "ChillMainAssets/types";
|
import type { WorkflowAttachment } from "ChillMainAssets/types";
|
||||||
import PickGenericDocModal from "ChillMainAssets/vuejs/WorkflowAttachment/Component/PickGenericDocModal.vue";
|
import PickGenericDocModal from "ChillMainAssets/vuejs/WorkflowAttachment/Component/PickGenericDocModal.vue";
|
||||||
import { GenericDocForAccompanyingPeriod } from "ChillDocStoreAssets/types/generic_doc";
|
import { GenericDocForAccompanyingPeriod } from "ChillDocStoreAssets/types/generic_doc";
|
||||||
import AttachmentList from "ChillMainAssets/vuejs/WorkflowAttachment/Component/AttachmentList.vue";
|
import AttachmentList from "ChillMainAssets/vuejs/WorkflowAttachment/Component/AttachmentList.vue";
|
||||||
import { GenericDoc } from "ChillDocStoreAssets/types";
|
import { GenericDoc } from "ChillDocStoreAssets/types";
|
||||||
import {fetch_generic_docs_by_accompanying_period, fetchWorkflow} from "ChillDocStoreAssets/js/generic-doc-api";
|
|
||||||
|
|
||||||
interface AppConfig {
|
interface AppConfig {
|
||||||
workflowId: number;
|
workflowId: number;
|
||||||
@@ -35,13 +34,6 @@ const attachedGenericDoc = computed<GenericDocForAccompanyingPeriod[]>(
|
|||||||
) as GenericDocForAccompanyingPeriod[],
|
) as GenericDocForAccompanyingPeriod[],
|
||||||
);
|
);
|
||||||
|
|
||||||
const workflow = ref<EntityWorkflow | null>(null);
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
workflow.value = await fetchWorkflow(Number(props.workflowId));
|
|
||||||
console.log('workflow', workflow.value);
|
|
||||||
});
|
|
||||||
|
|
||||||
const openModal = function () {
|
const openModal = function () {
|
||||||
pickDocModal.value?.openModal();
|
pickDocModal.value?.openModal();
|
||||||
};
|
};
|
||||||
@@ -61,14 +53,12 @@ const onRemoveAttachment = (payload: { attachment: WorkflowAttachment }) => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<pick-generic-doc-modal
|
<pick-generic-doc-modal
|
||||||
:workflow="workflow"
|
|
||||||
:accompanying-period-id="props.accompanyingPeriodId"
|
:accompanying-period-id="props.accompanyingPeriodId"
|
||||||
:to-remove="attachedGenericDoc"
|
:to-remove="attachedGenericDoc"
|
||||||
ref="pickDocModal"
|
ref="pickDocModal"
|
||||||
@pickGenericDoc="onPickGenericDoc"
|
@pickGenericDoc="onPickGenericDoc"
|
||||||
></pick-generic-doc-modal>
|
></pick-generic-doc-modal>
|
||||||
<attachment-list
|
<attachment-list
|
||||||
:workflow="workflow"
|
|
||||||
:attachments="props.attachments"
|
:attachments="props.attachments"
|
||||||
@removeAttachment="onRemoveAttachment"
|
@removeAttachment="onRemoveAttachment"
|
||||||
></attachment-list>
|
></attachment-list>
|
||||||
|
@@ -1,11 +1,10 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {EntityWorkflow, WorkflowAttachment} from "ChillMainAssets/types";
|
import { WorkflowAttachment } from "ChillMainAssets/types";
|
||||||
import GenericDocItemBox from "ChillMainAssets/vuejs/WorkflowAttachment/Component/GenericDocItemBox.vue";
|
import GenericDocItemBox from "ChillMainAssets/vuejs/WorkflowAttachment/Component/GenericDocItemBox.vue";
|
||||||
import DocumentActionButtonsGroup from "ChillDocStoreAssets/vuejs/DocumentActionButtonsGroup.vue";
|
import DocumentActionButtonsGroup from "ChillDocStoreAssets/vuejs/DocumentActionButtonsGroup.vue";
|
||||||
|
|
||||||
interface AttachmentListProps {
|
interface AttachmentListProps {
|
||||||
attachments: WorkflowAttachment[];
|
attachments: WorkflowAttachment[];
|
||||||
workflow: EntityWorkflow | null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
@@ -37,7 +36,7 @@ const props = defineProps<AttachmentListProps>();
|
|||||||
:stored-object="a.genericDoc.storedObject"
|
:stored-object="a.genericDoc.storedObject"
|
||||||
></document-action-buttons-group>
|
></document-action-buttons-group>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="!workflow?.currentStep.isFinal">
|
<li>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-delete"
|
class="btn btn-delete"
|
||||||
|
@@ -1,12 +1,13 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {GenericDoc, GenericDocForAccompanyingPeriod,} from "ChillDocStoreAssets/types/generic_doc";
|
import {
|
||||||
|
GenericDoc,
|
||||||
|
GenericDocForAccompanyingPeriod,
|
||||||
|
} from "ChillDocStoreAssets/types/generic_doc";
|
||||||
import PickGenericDocItem from "ChillMainAssets/vuejs/WorkflowAttachment/Component/PickGenericDocItem.vue";
|
import PickGenericDocItem from "ChillMainAssets/vuejs/WorkflowAttachment/Component/PickGenericDocItem.vue";
|
||||||
import {fetch_generic_docs_by_accompanying_period} from "ChillDocStoreAssets/js/generic-doc-api";
|
import { fetch_generic_docs_by_accompanying_period } from "ChillDocStoreAssets/js/generic-doc-api";
|
||||||
import {computed, onMounted, ref} from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
import {EntityWorkflow} from "ChillMainAssets/types";
|
|
||||||
|
|
||||||
interface PickGenericDocProps {
|
interface PickGenericDocProps {
|
||||||
workflow: EntityWorkflow | null;
|
|
||||||
accompanyingPeriodId: number;
|
accompanyingPeriodId: number;
|
||||||
pickedList: GenericDocForAccompanyingPeriod[];
|
pickedList: GenericDocForAccompanyingPeriod[];
|
||||||
toRemove: GenericDocForAccompanyingPeriod[];
|
toRemove: GenericDocForAccompanyingPeriod[];
|
||||||
@@ -35,19 +36,9 @@ const isPicked = (genericDoc: GenericDocForAccompanyingPeriod): boolean =>
|
|||||||
) !== -1;
|
) !== -1;
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
const fetchedGenericDocs = await fetch_generic_docs_by_accompanying_period(
|
genericDocs.value = await fetch_generic_docs_by_accompanying_period(
|
||||||
props.accompanyingPeriodId,
|
props.accompanyingPeriodId,
|
||||||
);
|
);
|
||||||
const documentClasses = [
|
|
||||||
"Chill\\DocStoreBundle\\Entity\\AccompanyingCourseDocument",
|
|
||||||
"Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluationDocument",
|
|
||||||
"Chill\\DocStoreBundle\\Entity\\PersonDocument"
|
|
||||||
];
|
|
||||||
|
|
||||||
genericDocs.value = fetchedGenericDocs.filter(doc =>
|
|
||||||
!documentClasses.includes(props.workflow?.relatedEntityClass || '') ||
|
|
||||||
props.workflow?.relatedEntityId !== doc.identifiers.id
|
|
||||||
);
|
|
||||||
loaded.value = true;
|
loaded.value = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -3,10 +3,8 @@ import Modal from "ChillMainAssets/vuejs/_components/Modal.vue";
|
|||||||
import { computed, ref, useTemplateRef } from "vue";
|
import { computed, ref, useTemplateRef } from "vue";
|
||||||
import PickGenericDoc from "ChillMainAssets/vuejs/WorkflowAttachment/Component/PickGenericDoc.vue";
|
import PickGenericDoc from "ChillMainAssets/vuejs/WorkflowAttachment/Component/PickGenericDoc.vue";
|
||||||
import { GenericDocForAccompanyingPeriod } from "ChillDocStoreAssets/types/generic_doc";
|
import { GenericDocForAccompanyingPeriod } from "ChillDocStoreAssets/types/generic_doc";
|
||||||
import {EntityWorkflow} from "ChillMainAssets/types";
|
|
||||||
|
|
||||||
interface PickGenericDocModalProps {
|
interface PickGenericDocModalProps {
|
||||||
workflow: EntityWorkflow | null;
|
|
||||||
accompanyingPeriodId: number;
|
accompanyingPeriodId: number;
|
||||||
toRemove: GenericDocForAccompanyingPeriod[];
|
toRemove: GenericDocForAccompanyingPeriod[];
|
||||||
}
|
}
|
||||||
@@ -82,7 +80,6 @@ defineExpose({ openModal, closeModal });
|
|||||||
</template>
|
</template>
|
||||||
<template v-slot:body>
|
<template v-slot:body>
|
||||||
<pick-generic-doc
|
<pick-generic-doc
|
||||||
:workflow="props.workflow"
|
|
||||||
:accompanying-period-id="props.accompanyingPeriodId"
|
:accompanying-period-id="props.accompanyingPeriodId"
|
||||||
:to-remove="props.toRemove"
|
:to-remove="props.toRemove"
|
||||||
:picked-list="pickeds"
|
:picked-list="pickeds"
|
||||||
|
@@ -58,14 +58,12 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{% if signatures|length > 0 %}
|
|
||||||
<section class="step my-4">{% include '@ChillMain/Workflow/_signature.html.twig' %}</section>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<section class="step my-4">{% include '@ChillMain/Workflow/_attachment.html.twig' %}</section>
|
<section class="step my-4">{% include '@ChillMain/Workflow/_attachment.html.twig' %}</section>
|
||||||
|
|
||||||
<section class="step my-4">{% include '@ChillMain/Workflow/_follow.html.twig' %}</section>
|
<section class="step my-4">{% include '@ChillMain/Workflow/_follow.html.twig' %}</section>
|
||||||
{% if entity_workflow.currentStep.sends|length > 0 %}
|
{% if signatures|length > 0 %}
|
||||||
|
<section class="step my-4">{% include '@ChillMain/Workflow/_signature.html.twig' %}</section>
|
||||||
|
{% elseif entity_workflow.currentStep.sends|length > 0 %}
|
||||||
<section class="step my-4">
|
<section class="step my-4">
|
||||||
<h2>{{ 'workflow.external_views.title'|trans({'numberOfSends': entity_workflow.currentStep.sends|length }) }}</h2>
|
<h2>{{ 'workflow.external_views.title'|trans({'numberOfSends': entity_workflow.currentStep.sends|length }) }}</h2>
|
||||||
{% include '@ChillMain/Workflow/_send_views_list.html.twig' with {'sends': entity_workflow.currentStep.sends} %}
|
{% include '@ChillMain/Workflow/_send_views_list.html.twig' with {'sends': entity_workflow.currentStep.sends} %}
|
||||||
|
@@ -1,10 +0,0 @@
|
|||||||
{% extends '@ChillMain/layout.html.twig' %}
|
|
||||||
|
|
||||||
{% block title %}{{ 'workflow.signature.waiting_for'|trans }}{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<h1>{{ block('title') }}</h1>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@@ -22,7 +22,6 @@ use Psr\Log\LoggerInterface;
|
|||||||
use Symfony\Component\Clock\ClockInterface;
|
use Symfony\Component\Clock\ClockInterface;
|
||||||
use Symfony\Component\Messenger\MessageBusInterface;
|
use Symfony\Component\Messenger\MessageBusInterface;
|
||||||
use Symfony\Component\Workflow\Registry;
|
use Symfony\Component\Workflow\Registry;
|
||||||
use Symfony\Component\Workflow\Transition;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles state changes for signature steps within a workflow.
|
* Handles state changes for signature steps within a workflow.
|
||||||
@@ -51,10 +50,8 @@ class SignatureStepStateChanger
|
|||||||
*
|
*
|
||||||
* @param EntityWorkflowStepSignature $signature the signature entity to be marked as signed
|
* @param EntityWorkflowStepSignature $signature the signature entity to be marked as signed
|
||||||
* @param int|null $atIndex optional index position for the signature within the zone
|
* @param int|null $atIndex optional index position for the signature within the zone
|
||||||
*
|
|
||||||
* @return string The expected new workflow's step, after transition is applyied
|
|
||||||
*/
|
*/
|
||||||
public function markSignatureAsSigned(EntityWorkflowStepSignature $signature, ?int $atIndex): string
|
public function markSignatureAsSigned(EntityWorkflowStepSignature $signature, ?int $atIndex): void
|
||||||
{
|
{
|
||||||
$this->entityManager->refresh($signature, LockMode::PESSIMISTIC_WRITE);
|
$this->entityManager->refresh($signature, LockMode::PESSIMISTIC_WRITE);
|
||||||
|
|
||||||
@@ -63,14 +60,7 @@ class SignatureStepStateChanger
|
|||||||
->setZoneSignatureIndex($atIndex)
|
->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->logger->info(self::LOG_PREFIX.'Mark signature entity as signed', ['signatureId' => $signature->getId(), 'index' => (string) $atIndex]);
|
||||||
['transition' => $transition, 'futureUser' => $futureUser] = $this->decideTransition($signature);
|
|
||||||
|
|
||||||
$this->messageBus->dispatch(new PostSignatureStateChangeMessage((int) $signature->getId()));
|
$this->messageBus->dispatch(new PostSignatureStateChangeMessage((int) $signature->getId()));
|
||||||
if (null === $transition) {
|
|
||||||
return $signature->getStep()->getEntityWorkflow()->getStep();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $transition->getTos()[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,10 +71,8 @@ class SignatureStepStateChanger
|
|||||||
*
|
*
|
||||||
* This method updates the signature state to 'canceled' and logs the action.
|
* This method updates the signature state to 'canceled' and logs the action.
|
||||||
* It also dispatches a message to notify about the state change.
|
* It also dispatches a message to notify about the state change.
|
||||||
*
|
|
||||||
* @return string The expected new workflow's step, after transition is applyied
|
|
||||||
*/
|
*/
|
||||||
public function markSignatureAsCanceled(EntityWorkflowStepSignature $signature): string
|
public function markSignatureAsCanceled(EntityWorkflowStepSignature $signature): void
|
||||||
{
|
{
|
||||||
$this->entityManager->refresh($signature, LockMode::PESSIMISTIC_WRITE);
|
$this->entityManager->refresh($signature, LockMode::PESSIMISTIC_WRITE);
|
||||||
|
|
||||||
@@ -92,15 +80,7 @@ class SignatureStepStateChanger
|
|||||||
->setState(EntityWorkflowSignatureStateEnum::CANCELED)
|
->setState(EntityWorkflowSignatureStateEnum::CANCELED)
|
||||||
->setStateDate($this->clock->now());
|
->setStateDate($this->clock->now());
|
||||||
$this->logger->info(self::LOG_PREFIX.'Mark signature entity as canceled', ['signatureId' => $signature->getId()]);
|
$this->logger->info(self::LOG_PREFIX.'Mark signature entity as canceled', ['signatureId' => $signature->getId()]);
|
||||||
|
|
||||||
['transition' => $transition, 'futureUser' => $futureUser] = $this->decideTransition($signature);
|
|
||||||
|
|
||||||
$this->messageBus->dispatch(new PostSignatureStateChangeMessage((int) $signature->getId()));
|
$this->messageBus->dispatch(new PostSignatureStateChangeMessage((int) $signature->getId()));
|
||||||
if (null === $transition) {
|
|
||||||
return $signature->getStep()->getEntityWorkflow()->getStep();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $transition->getTos()[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -113,10 +93,8 @@ class SignatureStepStateChanger
|
|||||||
* a state change has occurred.
|
* a state change has occurred.
|
||||||
*
|
*
|
||||||
* @param EntityWorkflowStepSignature $signature the signature entity to be marked as rejected
|
* @param EntityWorkflowStepSignature $signature the signature entity to be marked as rejected
|
||||||
*
|
|
||||||
* @return string The expected new workflow's step, after transition is applyied
|
|
||||||
*/
|
*/
|
||||||
public function markSignatureAsRejected(EntityWorkflowStepSignature $signature): string
|
public function markSignatureAsRejected(EntityWorkflowStepSignature $signature): void
|
||||||
{
|
{
|
||||||
$this->entityManager->refresh($signature, LockMode::PESSIMISTIC_WRITE);
|
$this->entityManager->refresh($signature, LockMode::PESSIMISTIC_WRITE);
|
||||||
|
|
||||||
@@ -124,16 +102,7 @@ class SignatureStepStateChanger
|
|||||||
->setState(EntityWorkflowSignatureStateEnum::REJECTED)
|
->setState(EntityWorkflowSignatureStateEnum::REJECTED)
|
||||||
->setStateDate($this->clock->now());
|
->setStateDate($this->clock->now());
|
||||||
$this->logger->info(self::LOG_PREFIX.'Mark signature entity as rejected', ['signatureId' => $signature->getId()]);
|
$this->logger->info(self::LOG_PREFIX.'Mark signature entity as rejected', ['signatureId' => $signature->getId()]);
|
||||||
|
|
||||||
['transition' => $transition, 'futureUser' => $futureUser] = $this->decideTransition($signature);
|
|
||||||
|
|
||||||
$this->messageBus->dispatch(new PostSignatureStateChangeMessage((int) $signature->getId()));
|
$this->messageBus->dispatch(new PostSignatureStateChangeMessage((int) $signature->getId()));
|
||||||
|
|
||||||
if (null === $transition) {
|
|
||||||
return $signature->getStep()->getEntityWorkflow()->getStep();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $transition->getTos()[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -148,35 +117,10 @@ class SignatureStepStateChanger
|
|||||||
{
|
{
|
||||||
$this->entityManager->refresh($signature, LockMode::PESSIMISTIC_READ);
|
$this->entityManager->refresh($signature, LockMode::PESSIMISTIC_READ);
|
||||||
|
|
||||||
['transition' => $transition, 'futureUser' => $futureUser] = $this->decideTransition($signature);
|
|
||||||
|
|
||||||
if (null === $transition) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$entityWorkflow = $signature->getStep()->getEntityWorkflow();
|
|
||||||
$workflow = $this->registry->get($entityWorkflow, $entityWorkflow->getWorkflowName());
|
|
||||||
$transitionDto = new WorkflowTransitionContextDTO($entityWorkflow);
|
|
||||||
$transitionDto->futureDestUsers[] = $futureUser;
|
|
||||||
|
|
||||||
$workflow->apply($entityWorkflow, $transition->getName(), [
|
|
||||||
'context' => $transitionDto,
|
|
||||||
'transitionAt' => $this->clock->now(),
|
|
||||||
'transition' => $transition->getName(),
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->logger->info(self::LOG_PREFIX.'Transition automatically applied', ['signatureId' => $signature->getId()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array{transition: Transition|null, futureUser: User|null}
|
|
||||||
*/
|
|
||||||
private function decideTransition(EntityWorkflowStepSignature $signature): array
|
|
||||||
{
|
|
||||||
if (!EntityWorkflowStepSignature::isAllSignatureNotPendingForStep($signature->getStep())) {
|
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()]);
|
$this->logger->info(self::LOG_PREFIX.'This is not the last signature, skipping transition to another place', ['signatureId' => $signature->getId()]);
|
||||||
|
|
||||||
return ['transition' => null, 'futureUser' => null];
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger->debug(self::LOG_PREFIX.'Continuing the process to find a transition', ['signatureId' => $signature->getId()]);
|
$this->logger->debug(self::LOG_PREFIX.'Continuing the process to find a transition', ['signatureId' => $signature->getId()]);
|
||||||
@@ -200,7 +144,7 @@ class SignatureStepStateChanger
|
|||||||
if (null === $transition) {
|
if (null === $transition) {
|
||||||
$this->logger->info(self::LOG_PREFIX.'The transition is not configured, will not apply a transition', ['signatureId' => $signature->getId()]);
|
$this->logger->info(self::LOG_PREFIX.'The transition is not configured, will not apply a transition', ['signatureId' => $signature->getId()]);
|
||||||
|
|
||||||
return ['transition' => null, 'futureUser' => null];
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ('person' === $signature->getSignerKind()) {
|
if ('person' === $signature->getSignerKind()) {
|
||||||
@@ -212,16 +156,19 @@ class SignatureStepStateChanger
|
|||||||
if (null === $futureUser) {
|
if (null === $futureUser) {
|
||||||
$this->logger->info(self::LOG_PREFIX.'No previous user, will not apply a transition', ['signatureId' => $signature->getId()]);
|
$this->logger->info(self::LOG_PREFIX.'No previous user, will not apply a transition', ['signatureId' => $signature->getId()]);
|
||||||
|
|
||||||
return ['transition' => null, 'futureUser' => null];
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($workflow->getDefinition()->getTransitions() as $transitionObj) {
|
$transitionDto = new WorkflowTransitionContextDTO($entityWorkflow);
|
||||||
if ($transitionObj->getName() === $transition) {
|
$transitionDto->futureDestUsers[] = $futureUser;
|
||||||
return ['transition' => $transitionObj, 'futureUser' => $futureUser];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new \RuntimeException('Transition not found');
|
$workflow->apply($entityWorkflow, $transition, [
|
||||||
|
'context' => $transitionDto,
|
||||||
|
'transitionAt' => $this->clock->now(),
|
||||||
|
'transition' => $transition,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->logger->info(self::LOG_PREFIX.'Transition automatically applied', ['signatureId' => $signature->getId()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getPreviousSender(EntityWorkflowStep $entityWorkflowStep): ?User
|
private function getPreviousSender(EntityWorkflowStep $entityWorkflowStep): ?User
|
||||||
|
@@ -965,31 +965,6 @@ paths:
|
|||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/components/schemas/UserJob"
|
$ref: "#/components/schemas/UserJob"
|
||||||
/1.0/main/workflow/{id}.json:
|
|
||||||
get:
|
|
||||||
tags:
|
|
||||||
- workflow
|
|
||||||
summary: Return a workflow
|
|
||||||
parameters:
|
|
||||||
- name: id
|
|
||||||
in: path
|
|
||||||
required: true
|
|
||||||
description: The workflow id
|
|
||||||
schema:
|
|
||||||
type: integer
|
|
||||||
format: integer
|
|
||||||
minimum: 1
|
|
||||||
responses:
|
|
||||||
200:
|
|
||||||
description: "ok"
|
|
||||||
content:
|
|
||||||
application/json:
|
|
||||||
schema:
|
|
||||||
$ref: "#/components/schemas/Workflow"
|
|
||||||
404:
|
|
||||||
description: "not found"
|
|
||||||
401:
|
|
||||||
description: "Unauthorized"
|
|
||||||
/1.0/main/workflow/my:
|
/1.0/main/workflow/my:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
|
@@ -666,7 +666,6 @@ workflow:
|
|||||||
cancel_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_signature_of: Rejet de la signature de %signer%
|
||||||
reject_are_you_sure: Êtes-vous sûr de vouloir rejeter la signature de %signer%
|
reject_are_you_sure: Êtes-vous sûr de vouloir rejeter la signature de %signer%
|
||||||
waiting_for: En attente de modification de l'état de la signature
|
|
||||||
|
|
||||||
attachments:
|
attachments:
|
||||||
title: Pièces jointes
|
title: Pièces jointes
|
||||||
|
Reference in New Issue
Block a user