-
+
{{ title }}
{{ 'workflow.public_link.main_document'|trans }}
@@ -39,5 +39,21 @@
+ {% for attachment in attachments %}
+
+
+
+
{{ attachment.proxyStoredObject.title }}
+
{{ 'workflow.public_link.attachment'|trans }}
+
+
+
+ {{ attachment.proxyStoredObject|chill_document_download_only_button(storedObject.title(), false) }}
+
+
+
+
+
+ {% endfor %}
{% endblock %}
diff --git a/src/Bundle/ChillDocStoreBundle/Security/Authorization/StoredObjectVoter.php b/src/Bundle/ChillDocStoreBundle/Security/Authorization/StoredObjectVoter.php
index da5e4118b..f23db17c3 100644
--- a/src/Bundle/ChillDocStoreBundle/Security/Authorization/StoredObjectVoter.php
+++ b/src/Bundle/ChillDocStoreBundle/Security/Authorization/StoredObjectVoter.php
@@ -12,6 +12,8 @@ declare(strict_types=1);
namespace Chill\DocStoreBundle\Security\Authorization;
use Chill\DocStoreBundle\Entity\StoredObject;
+use Chill\MainBundle\Entity\User;
+use Chill\MainBundle\Repository\Workflow\EntityWorkflowAttachmentRepository;
use Psr\Log\LoggerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
@@ -26,7 +28,12 @@ class StoredObjectVoter extends Voter
{
public const LOG_PREFIX = '[stored object voter] ';
- public function __construct(private readonly Security $security, private readonly iterable $storedObjectVoters, private readonly LoggerInterface $logger) {}
+ public function __construct(
+ private readonly Security $security,
+ private readonly iterable $storedObjectVoters,
+ private readonly LoggerInterface $logger,
+ private readonly EntityWorkflowAttachmentRepository $entityWorkflowAttachmentRepository,
+ ) {}
protected function supports($attribute, $subject): bool
{
@@ -39,6 +46,16 @@ class StoredObjectVoter extends Voter
/** @var StoredObject $subject */
$attributeAsEnum = StoredObjectRoleEnum::from($attribute);
+ // check if the stored object is attached to any workflow
+ $user = $token->getUser();
+ if ($user instanceof User && StoredObjectRoleEnum::SEE === $attributeAsEnum) {
+ foreach ($this->entityWorkflowAttachmentRepository->findByStoredObject($subject) as $workflowAttachment) {
+ if ($workflowAttachment->getEntityWorkflow()->isUserInvolved($user)) {
+ return true;
+ }
+ }
+ }
+
// Loop through context-specific voters
foreach ($this->storedObjectVoters as $storedObjectVoter) {
if ($storedObjectVoter->supports($attributeAsEnum, $subject)) {
diff --git a/src/Bundle/ChillDocStoreBundle/Serializer/Normalizer/GenericDocNormalizer.php b/src/Bundle/ChillDocStoreBundle/Serializer/Normalizer/GenericDocNormalizer.php
new file mode 100644
index 000000000..f3aa33243
--- /dev/null
+++ b/src/Bundle/ChillDocStoreBundle/Serializer/Normalizer/GenericDocNormalizer.php
@@ -0,0 +1,67 @@
+manager->fetchStoredObject($object);
+ } catch (AssociatedStoredObjectNotFound) {
+ $storedObject = null;
+ }
+
+ $data = [
+ 'type' => 'doc_store_generic_doc',
+ 'key' => $object->key,
+ 'uniqueKey' => $object->key.implode('', array_keys($object->identifiers)).implode('', array_values($object->identifiers)),
+ 'identifiers' => $object->identifiers,
+ 'context' => $object->getContext(),
+ 'doc_date' => $this->normalizer->normalize($object->docDate, $format, $context),
+ 'metadata' => [],
+ 'storedObject' => $this->normalizer->normalize($storedObject, $format, $context),
+ ];
+
+ if ($this->manager->isGenericDocNormalizable($object, $format, $context)) {
+ $data['metadata'] = $this->manager->normalizeGenericDoc($object, $format, $context);
+ }
+
+ return $data;
+ }
+
+ public function supportsNormalization($data, ?string $format = null): bool
+ {
+ return 'json' === $format && $data instanceof GenericDocDTO;
+ }
+}
diff --git a/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/ManagerTest.php b/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/ManagerTest.php
index eed078aa3..0839019ae 100644
--- a/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/ManagerTest.php
+++ b/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/ManagerTest.php
@@ -11,10 +11,13 @@ declare(strict_types=1);
namespace Chill\DocStoreBundle\Tests\GenericDoc;
+use Chill\DocStoreBundle\Entity\StoredObject;
+use Chill\DocStoreBundle\GenericDoc\Exception\NotNormalizableGenericDocException;
use Chill\DocStoreBundle\GenericDoc\FetchQuery;
use Chill\DocStoreBundle\GenericDoc\FetchQueryInterface;
use Chill\DocStoreBundle\GenericDoc\GenericDocDTO;
use Chill\DocStoreBundle\GenericDoc\GenericDocForPersonProviderInterface;
+use Chill\DocStoreBundle\GenericDoc\GenericDocNormalizerInterface;
use Chill\DocStoreBundle\GenericDoc\Manager;
use Chill\DocStoreBundle\GenericDoc\GenericDocForAccompanyingPeriodProviderInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
@@ -58,6 +61,7 @@ class ManagerTest extends KernelTestCase
$manager = new Manager(
[new SimpleGenericDocAccompanyingPeriodProvider()],
[new SimpleGenericDocPersonProvider()],
+ [],
$this->connection,
);
@@ -79,6 +83,7 @@ class ManagerTest extends KernelTestCase
$manager = new Manager(
[new SimpleGenericDocAccompanyingPeriodProvider()],
[new SimpleGenericDocPersonProvider()],
+ [],
$this->connection,
);
@@ -100,6 +105,7 @@ class ManagerTest extends KernelTestCase
$manager = new Manager(
[new SimpleGenericDocAccompanyingPeriodProvider()],
[new SimpleGenericDocPersonProvider()],
+ [],
$this->connection,
);
@@ -121,6 +127,7 @@ class ManagerTest extends KernelTestCase
$manager = new Manager(
[new SimpleGenericDocAccompanyingPeriodProvider()],
[new SimpleGenericDocPersonProvider()],
+ [],
$this->connection,
);
@@ -142,6 +149,7 @@ class ManagerTest extends KernelTestCase
$manager = new Manager(
[new SimpleGenericDocAccompanyingPeriodProvider()],
[new SimpleGenericDocPersonProvider()],
+ [],
$this->connection,
);
@@ -163,6 +171,7 @@ class ManagerTest extends KernelTestCase
$manager = new Manager(
[new SimpleGenericDocAccompanyingPeriodProvider()],
[new SimpleGenericDocPersonProvider()],
+ [],
$this->connection,
);
@@ -170,10 +179,77 @@ class ManagerTest extends KernelTestCase
self::assertEquals(['accompanying_course_document_dummy'], $places);
}
+
+ public function testIsGenericDocNormalizable(): void
+ {
+ $genericDoc = new GenericDocDTO('test', ['id' => 1], new \DateTimeImmutable(), new AccompanyingPeriod());
+
+ $manager = new Manager([], [], [$this->buildNormalizer(true)], $this->connection);
+ self::assertTrue($manager->isGenericDocNormalizable($genericDoc, 'json'));
+
+ $manager = new Manager([], [], [$this->buildNormalizer(false)], $this->connection);
+ self::assertFalse($manager->isGenericDocNormalizable($genericDoc, 'json'));
+ }
+
+ public function testNormalizeGenericDocMetadata(): void
+ {
+ $genericDoc = new GenericDocDTO('test', ['id' => 1], new \DateTimeImmutable(), new AccompanyingPeriod());
+
+ $manager = new Manager([], [], [$this->buildNormalizer(false), $this->buildNormalizer(true)], $this->connection);
+ self::assertEquals(['title' => 'Some title'], $manager->normalizeGenericDoc($genericDoc, 'json'));
+ }
+
+ public function testNormalizeGenericDocMetadataNoNormalizer(): void
+ {
+ $genericDoc = new GenericDocDTO('test', ['id' => 1], new \DateTimeImmutable(), new AccompanyingPeriod());
+
+ $manager = new Manager([], [], [$this->buildNormalizer(false)], $this->connection);
+
+ $this->expectException(NotNormalizableGenericDocException::class);
+
+ self::assertEquals(['title' => 'Some title'], $manager->normalizeGenericDoc($genericDoc, 'json'));
+ }
+
+ public function buildNormalizer(bool $supports): GenericDocNormalizerInterface
+ {
+ return new class ($supports) implements GenericDocNormalizerInterface {
+ public function __construct(private readonly bool $supports) {}
+
+ public function supportsNormalization(GenericDocDTO $genericDocDTO, string $format, array $context = []): bool
+ {
+ return $this->supports;
+ }
+
+ public function normalize(GenericDocDTO $genericDocDTO, string $format, array $context = []): array
+ {
+ return ['title' => 'Some title'];
+ }
+ };
+ }
}
final readonly class SimpleGenericDocAccompanyingPeriodProvider implements GenericDocForAccompanyingPeriodProviderInterface
{
+ public function fetchAssociatedStoredObject(GenericDocDTO $genericDocDTO): ?StoredObject
+ {
+ throw new \BadMethodCallException('not implemented');
+ }
+
+ public function supportsGenericDoc(GenericDocDTO $genericDocDTO): bool
+ {
+ throw new \BadMethodCallException('not implemented');
+ }
+
+ public function supportsKeyAndIdentifiers(string $key, array $identifiers): bool
+ {
+ return 'accompanying_course_document_dummy' === $key;
+ }
+
+ public function buildOneGenericDoc(string $key, array $identifiers): ?GenericDocDTO
+ {
+ return new GenericDocDTO('accompanying_course_document_dummy', $identifiers, new \DateTimeImmutable(), new AccompanyingPeriod());
+ }
+
public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface
{
$query = new FetchQuery(
diff --git a/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/Providers/AccompanyingCourseDocumentGenericDocProviderTest.php b/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/Providers/AccompanyingCourseDocumentGenericDocProviderTest.php
index a4f5234d5..638d9ae56 100644
--- a/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/Providers/AccompanyingCourseDocumentGenericDocProviderTest.php
+++ b/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/Providers/AccompanyingCourseDocumentGenericDocProviderTest.php
@@ -13,6 +13,7 @@ namespace Chill\DocStoreBundle\Tests\GenericDoc\Providers;
use Chill\DocStoreBundle\GenericDoc\FetchQueryToSqlBuilder;
use Chill\DocStoreBundle\GenericDoc\Providers\AccompanyingCourseDocumentGenericDocProvider;
+use Chill\DocStoreBundle\Repository\AccompanyingCourseDocumentRepository;
use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Doctrine\ORM\EntityManagerInterface;
@@ -56,7 +57,8 @@ class AccompanyingCourseDocumentGenericDocProviderTest extends KernelTestCase
$provider = new AccompanyingCourseDocumentGenericDocProvider(
$security->reveal(),
- $this->entityManager
+ $this->entityManager,
+ $this->prophesize(AccompanyingCourseDocumentRepository::class)->reveal()
);
$query = $provider->buildFetchQueryForAccompanyingPeriod($period, $startDate, $endDate, $content);
diff --git a/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/Providers/PersonDocumentGenericDocProviderTest.php b/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/Providers/PersonDocumentGenericDocProviderTest.php
index 602dd7f4c..0e6c98538 100644
--- a/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/Providers/PersonDocumentGenericDocProviderTest.php
+++ b/src/Bundle/ChillDocStoreBundle/Tests/GenericDoc/Providers/PersonDocumentGenericDocProviderTest.php
@@ -14,6 +14,7 @@ namespace Chill\DocStoreBundle\Tests\GenericDoc\Providers;
use Chill\DocStoreBundle\GenericDoc\FetchQueryToSqlBuilder;
use Chill\DocStoreBundle\GenericDoc\Providers\PersonDocumentGenericDocProvider;
use Chill\DocStoreBundle\Repository\PersonDocumentACLAwareRepositoryInterface;
+use Chill\DocStoreBundle\Repository\PersonDocumentRepository;
use Chill\PersonBundle\Entity\Person;
use Doctrine\ORM\EntityManagerInterface;
use Prophecy\PhpUnit\ProphecyTrait;
@@ -33,11 +34,14 @@ class PersonDocumentGenericDocProviderTest extends KernelTestCase
private PersonDocumentACLAwareRepositoryInterface $personDocumentACLAwareRepository;
+ private PersonDocumentRepository $personDocumentRepository;
+
protected function setUp(): void
{
self::bootKernel();
$this->entityManager = self::getContainer()->get(EntityManagerInterface::class);
$this->personDocumentACLAwareRepository = self::getContainer()->get(PersonDocumentACLAwareRepositoryInterface::class);
+ $this->personDocumentRepository = self::getContainer()->get(PersonDocumentRepository::class);
}
/**
@@ -60,7 +64,8 @@ class PersonDocumentGenericDocProviderTest extends KernelTestCase
$provider = new PersonDocumentGenericDocProvider(
$security->reveal(),
- $this->personDocumentACLAwareRepository
+ $this->personDocumentACLAwareRepository,
+ $this->personDocumentRepository,
);
$query = $provider->buildFetchQueryForPerson($person, $startDate, $endDate, $content);
diff --git a/src/Bundle/ChillDocStoreBundle/Tests/Security/Authorization/StoredObjectVoterTest.php b/src/Bundle/ChillDocStoreBundle/Tests/Security/Authorization/StoredObjectVoterTest.php
index b9a025f45..7180a14d8 100644
--- a/src/Bundle/ChillDocStoreBundle/Tests/Security/Authorization/StoredObjectVoterTest.php
+++ b/src/Bundle/ChillDocStoreBundle/Tests/Security/Authorization/StoredObjectVoterTest.php
@@ -16,6 +16,7 @@ use Chill\DocStoreBundle\Security\Authorization\StoredObjectRoleEnum;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoter;
use Chill\DocStoreBundle\Security\Authorization\StoredObjectVoterInterface;
use Chill\MainBundle\Entity\User;
+use Chill\MainBundle\Repository\Workflow\EntityWorkflowAttachmentRepository;
use PHPUnit\Framework\TestCase;
use Psr\Log\NullLogger;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
@@ -44,7 +45,7 @@ class StoredObjectVoterTest extends TestCase
->with($this->logicalOr($this->identicalTo('ROLE_USER'), $this->identicalTo('ROLE_ADMIN')))
->willReturn($securityIsGrantedResult);
- $voter = new StoredObjectVoter($security, $storedObjectVoters, new NullLogger());
+ $voter = new StoredObjectVoter($security, $storedObjectVoters, new NullLogger(), $this->createMock(EntityWorkflowAttachmentRepository::class));
self::assertEquals($expected, $voter->vote($token, $subject, [$attribute]));
}
diff --git a/src/Bundle/ChillDocStoreBundle/Tests/Serializer/Normalizer/GenericDocNormalizerTest.php b/src/Bundle/ChillDocStoreBundle/Tests/Serializer/Normalizer/GenericDocNormalizerTest.php
new file mode 100644
index 000000000..0d5eb818c
--- /dev/null
+++ b/src/Bundle/ChillDocStoreBundle/Tests/Serializer/Normalizer/GenericDocNormalizerTest.php
@@ -0,0 +1,75 @@
+manager = $this->createMock(ManagerInterface::class);
+
+ $this->normalizer = new GenericDocNormalizer($this->manager);
+
+ $innerNormalizer = $this->createMock(NormalizerInterface::class);
+ $innerNormalizer->method('normalize')
+ ->willReturnCallback(fn ($date) => $date instanceof \DateTimeImmutable ? $date->format(DATE_ATOM) : null);
+
+ $this->normalizer->setNormalizer($innerNormalizer);
+ }
+
+ public function testNormalize()
+ {
+ $docDate = new \DateTimeImmutable('2023-10-01T15:03:01.012345Z');
+
+ $object = new GenericDocDTO(
+ 'some_key',
+ ['id' => 'id1', 'other_id' => 'id2'],
+ $docDate,
+ new AccompanyingPeriod(),
+ );
+
+ $expected = [
+ 'type' => 'doc_store_generic_doc',
+ 'key' => 'some_key',
+ 'identifiers' => ['id' => 'id1', 'other_id' => 'id2'],
+ 'context' => 'accompanying-period',
+ 'doc_date' => $docDate->format(DATE_ATOM),
+ 'uniqueKey' => 'some_keyidother_idid1id2',
+ 'metadata' => [],
+ 'storedObject' => null,
+ ];
+
+ $this->manager->expects($this->once())->method('isGenericDocNormalizable')
+ ->with($object, 'json', [])
+ ->willReturn(true);
+
+ $actual = $this->normalizer->normalize($object, 'json', []);
+
+ $this->assertEquals($expected, $actual);
+ }
+}
diff --git a/src/Bundle/ChillDocStoreBundle/Workflow/AccompanyingCourseDocumentWorkflowHandler.php b/src/Bundle/ChillDocStoreBundle/Workflow/AccompanyingCourseDocumentWorkflowHandler.php
index 193568286..9b91d8aef 100644
--- a/src/Bundle/ChillDocStoreBundle/Workflow/AccompanyingCourseDocumentWorkflowHandler.php
+++ b/src/Bundle/ChillDocStoreBundle/Workflow/AccompanyingCourseDocumentWorkflowHandler.php
@@ -21,6 +21,7 @@ use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
use Chill\MainBundle\Workflow\EntityWorkflowWithPublicViewInterface;
use Chill\MainBundle\Workflow\EntityWorkflowWithStoredObjectHandlerInterface;
use Chill\MainBundle\Workflow\Templating\EntityWorkflowViewMetadataDTO;
+use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Chill\PersonBundle\Service\AccompanyingPeriod\ProvideThirdPartiesAssociated;
use Chill\PersonBundle\Service\AccompanyingPeriod\ProvidePersonsAssociated;
@@ -78,6 +79,15 @@ final readonly class AccompanyingCourseDocumentWorkflowHandler implements Entity
return $this->repository->find($entityWorkflow->getRelatedEntityId());
}
+ public function getRelatedAccompanyingPeriod(EntityWorkflow $entityWorkflow): ?AccompanyingPeriod
+ {
+ if (null === $document = $this->getRelatedEntity($entityWorkflow)) {
+ return null;
+ }
+
+ return $document->getCourse();
+ }
+
/**
* @return array[]
*/
diff --git a/src/Bundle/ChillDocStoreBundle/Workflow/WorkflowWithPublicViewDocumentHelper.php b/src/Bundle/ChillDocStoreBundle/Workflow/WorkflowWithPublicViewDocumentHelper.php
index 5d23150e0..84e647df4 100644
--- a/src/Bundle/ChillDocStoreBundle/Workflow/WorkflowWithPublicViewDocumentHelper.php
+++ b/src/Bundle/ChillDocStoreBundle/Workflow/WorkflowWithPublicViewDocumentHelper.php
@@ -39,6 +39,7 @@ class WorkflowWithPublicViewDocumentHelper
'storedObject' => $storedObject,
'send' => $send,
'metadata' => $metadata,
+ 'attachments' => $entityWorkflow->getAttachments(),
]
);
}
diff --git a/src/Bundle/ChillDocStoreBundle/chill.api.specs.yaml b/src/Bundle/ChillDocStoreBundle/chill.api.specs.yaml
index 127430c70..8570116aa 100644
--- a/src/Bundle/ChillDocStoreBundle/chill.api.specs.yaml
+++ b/src/Bundle/ChillDocStoreBundle/chill.api.specs.yaml
@@ -19,6 +19,22 @@ components:
type: string
type:
type: string
+ GenericDoc:
+ type: object
+ properties:
+ type:
+ type: string
+ enum:
+ - doc_store_generic_doc
+ key:
+ type: string
+ context:
+ type: string
+ enum:
+ - person
+ - accompanying-period
+ doc_date:
+ $ref: '#/components/schemas/Date'
paths:
/1.0/doc-store/stored-object/create:
@@ -69,30 +85,30 @@ paths:
- storedobject
summary: Get a signed route to get a stored object
parameters:
- - in: path
- name: uuid
- required: true
- allowEmptyValue: false
- description: The UUID of the storedObjeect
- schema:
- type: string
- format: uuid
- - in: path
- name: method
- required: true
- allowEmptyValue: false
- description: the method of the signed url (get or head)
- schema:
- type: string
- enum: [get, head]
- - in: query
- name: version
- required: false
- allowEmptyValue: false
- description: the version's filename of the stored object
- schema:
- type: string
- minLength: 2
+ - in: path
+ name: uuid
+ required: true
+ allowEmptyValue: false
+ description: The UUID of the storedObjeect
+ schema:
+ type: string
+ format: uuid
+ - in: path
+ name: method
+ required: true
+ allowEmptyValue: false
+ description: the method of the signed url (get or head)
+ schema:
+ type: string
+ enum: [ get, head ]
+ - in: query
+ name: version
+ required: false
+ allowEmptyValue: false
+ description: the version's filename of the stored object
+ schema:
+ type: string
+ minLength: 2
responses:
200:
description: "OK"
@@ -111,14 +127,14 @@ paths:
- storedobject
summary: Get a signed route to post stored object
parameters:
- - in: path
- name: uuid
- required: true
- allowEmptyValue: false
- description: The UUID of the storedObjeect
- schema:
- type: string
- format: uuid
+ - in: path
+ name: uuid
+ required: true
+ allowEmptyValue: false
+ description: The UUID of the storedObjeect
+ schema:
+ type: string
+ format: uuid
responses:
200:
description: "OK"
@@ -137,13 +153,13 @@ paths:
- storedobject
summary: Restore an old version of a stored object
parameters:
- - in: path
- name: id
- required: true
- allowEmptyValue: false
- description: The id of the stored object version
- schema:
- type: integer
+ - in: path
+ name: id
+ required: true
+ allowEmptyValue: false
+ description: The id of the stored object version
+ schema:
+ type: integer
responses:
200:
description: "OK"
@@ -151,4 +167,32 @@ paths:
application/json:
schema:
type: object
+ /1.0/doc-store/generic-doc/by-period/{id}/index:
+ get:
+ tags:
+ - storedobject
+ summary: A list of generic doc associated with the accompanying period
+ parameters:
+ - in: path
+ name: id
+ required: true
+ allowEmptyValue: false
+ description: The id of the accompanying period
+ schema:
+ type: integer
+ responses:
+ 200:
+ description: "OK"
+ content:
+ application/json:
+ schema:
+ allOf:
+ - $ref: '#/components/schemas/PaginatedResult'
+ - type: object
+ properties:
+ results:
+ type: array
+ items:
+ $ref: '#/components/schemas/GenericDoc'
+ type: object
diff --git a/src/Bundle/ChillDocStoreBundle/config/services.yaml b/src/Bundle/ChillDocStoreBundle/config/services.yaml
index 070731b54..caecc216d 100644
--- a/src/Bundle/ChillDocStoreBundle/config/services.yaml
+++ b/src/Bundle/ChillDocStoreBundle/config/services.yaml
@@ -31,6 +31,10 @@ services:
arguments:
$providersForAccompanyingPeriod: !tagged_iterator chill_doc_store.generic_doc_accompanying_period_provider
$providersForPerson: !tagged_iterator chill_doc_store.generic_doc_person_provider
+ $genericDocNormalizers: !tagged_iterator chill_doc_store.generic_doc_metadata_normalizer
+
+ Chill\DocStoreBundle\GenericDoc\ManagerInterface:
+ alias: Chill\DocStoreBundle\GenericDoc\Manager
Chill\DocStoreBundle\GenericDoc\Twig\GenericDocExtension: ~
@@ -44,6 +48,9 @@ services:
Chill\DocStoreBundle\GenericDoc\Renderer\:
resource: '../GenericDoc/Renderer/'
+ Chill\DocStoreBundle\GenericDoc\Normalizer\:
+ resource: '../GenericDoc/Normalizer/'
+
Chill\DocStoreBundle\Validator\:
resource: '../Validator'
diff --git a/src/Bundle/ChillDocStoreBundle/migrations/Version20241212112733.php b/src/Bundle/ChillDocStoreBundle/migrations/Version20241212112733.php
new file mode 100644
index 000000000..994a33ef3
--- /dev/null
+++ b/src/Bundle/ChillDocStoreBundle/migrations/Version20241212112733.php
@@ -0,0 +1,45 @@
+addSql('UPDATE chill_doc.stored_object SET title = ac_doc.title FROM chill_doc.accompanyingcourse_document ac_doc WHERE ac_doc.object_id = stored_object.id');
+ $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP scope_id');
+ $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document DROP title');
+ $this->addSql('UPDATE chill_doc.stored_object SET title = p_doc.title FROM chill_doc.person_document p_doc WHERE p_doc.object_id = stored_object.id');
+ $this->addSql('ALTER TABLE chill_doc.person_document DROP title');
+ }
+
+ public function down(Schema $schema): void
+ {
+ $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD scope_id INT DEFAULT NULL');
+ $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD title TEXT DEFAULT \'\' NOT NULL');
+ $this->addSql('UPDATE chill_doc.accompanyingcourse_document SET title = so.title FROM chill_doc.stored_object so WHERE object_id = so.id');
+ $this->addSql('ALTER TABLE chill_doc.accompanyingcourse_document ADD CONSTRAINT fk_a45098f6682b5931 FOREIGN KEY (scope_id) REFERENCES scopes (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('CREATE INDEX idx_a45098f6682b5931 ON chill_doc.accompanyingcourse_document (scope_id)');
+
+
+ $this->addSql('ALTER TABLE chill_doc.person_document ADD title TEXT DEFAULT \'\' NOT NULL');
+ $this->addSql('UPDATE chill_doc.person_document SET title = so.title FROM chill_doc.stored_object so WHERE object_id = so.id');
+ }
+}
diff --git a/src/Bundle/ChillDocStoreBundle/translations/messages.fr.yml b/src/Bundle/ChillDocStoreBundle/translations/messages.fr.yml
index 05713ff28..da946a34c 100644
--- a/src/Bundle/ChillDocStoreBundle/translations/messages.fr.yml
+++ b/src/Bundle/ChillDocStoreBundle/translations/messages.fr.yml
@@ -86,6 +86,7 @@ workflow:
shared_doc: Document partagé
title: Document partagé
main_document: Document principal
+ attachment: Pièce jointe
# ROLES
accompanyingCourseDocument: Documents dans les parcours d'accompagnement
diff --git a/src/Bundle/ChillMainBundle/Controller/WorkflowAttachmentController.php b/src/Bundle/ChillMainBundle/Controller/WorkflowAttachmentController.php
new file mode 100644
index 000000000..7a8a45950
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Controller/WorkflowAttachmentController.php
@@ -0,0 +1,101 @@
+security->isGranted(EntityWorkflowVoter::SEE, $entityWorkflow)) {
+ throw new AccessDeniedHttpException();
+ }
+
+ $dto = new AddAttachmentRequestDTO($entityWorkflow);
+ $this->serializer->deserialize($request->getContent(), AddAttachmentRequestDTO::class, 'json', [
+ AbstractNormalizer::OBJECT_TO_POPULATE => $dto, AbstractNormalizer::GROUPS => ['write'],
+ ]);
+
+ $errors = $this->validator->validate($dto);
+
+ if (count($errors) > 0) {
+ return new JsonResponse(
+ $this->serializer->serialize($errors, 'json'),
+ Response::HTTP_UNPROCESSABLE_ENTITY,
+ json: true
+ );
+ }
+
+ $attachment = ($this->addAttachmentAction)($dto);
+
+ $this->entityManager->flush();
+
+ return new JsonResponse(
+ $this->serializer->serialize($attachment, 'json', [AbstractNormalizer::GROUPS => ['read']]),
+ json: true
+ );
+ }
+
+ #[Route('/api/1.0/main/workflow/attachment/{id}', methods: ['DELETE'])]
+ public function removeAttachment(EntityWorkflowAttachment $attachment): Response
+ {
+ if (!$this->security->isGranted(EntityWorkflowVoter::SEE, $attachment->getEntityWorkflow())) {
+ throw new AccessDeniedHttpException();
+ }
+
+ $this->entityManager->remove($attachment);
+ $this->entityManager->flush();
+
+ return new Response(null, Response::HTTP_NO_CONTENT);
+ }
+
+ #[Route('/api/1.0/main/workflow/{id}/attachment', methods: ['GET'])]
+ public function listAttachmentsForEntityWorkflow(EntityWorkflow $entityWorkflow): JsonResponse
+ {
+ if (!$this->security->isGranted(EntityWorkflowVoter::SEE, $entityWorkflow)) {
+ throw new AccessDeniedHttpException();
+ }
+
+ return new JsonResponse(
+ $this->serializer->serialize(
+ $entityWorkflow->getAttachments(),
+ 'json',
+ [AbstractNormalizer::GROUPS => ['read']]
+ ),
+ json: true
+ );
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/Controller/WorkflowController.php b/src/Bundle/ChillMainBundle/Controller/WorkflowController.php
index 1f1372cd2..248bd286e 100644
--- a/src/Bundle/ChillMainBundle/Controller/WorkflowController.php
+++ b/src/Bundle/ChillMainBundle/Controller/WorkflowController.php
@@ -351,6 +351,7 @@ class WorkflowController extends AbstractController
'entity_workflow' => $entityWorkflow,
'transition_form_errors' => $errors,
'signatures' => $signatures,
+ 'related_accompanying_period' => $this->entityWorkflowManager->getRelatedAccompanyingPeriod($entityWorkflow),
]
);
}
diff --git a/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflow.php b/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflow.php
index 1c4413294..ad5fa9e95 100644
--- a/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflow.php
+++ b/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflow.php
@@ -87,12 +87,19 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT)]
private string $workflowName;
+ /**
+ * @var Collection
+ */
+ #[ORM\OneToMany(mappedBy: 'entityWorkflow', targetEntity: EntityWorkflowAttachment::class, cascade: ['remove'], orphanRemoval: true)]
+ private Collection $attachments;
+
public function __construct()
{
$this->subscriberToFinal = new ArrayCollection();
$this->subscriberToStep = new ArrayCollection();
$this->comments = new ArrayCollection();
$this->steps = new ArrayCollection();
+ $this->attachments = new ArrayCollection();
$initialStep = new EntityWorkflowStep();
$initialStep
@@ -142,6 +149,35 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface
return $this;
}
+ /**
+ * @return $this
+ *
+ * @internal use @{EntityWorkflowAttachement::__construct} instead
+ */
+ public function addAttachment(EntityWorkflowAttachment $attachment): self
+ {
+ if (!$this->attachments->contains($attachment)) {
+ $this->attachments[] = $attachment;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return Collection
+ */
+ public function getAttachments(): Collection
+ {
+ return $this->attachments;
+ }
+
+ public function removeAttachment(EntityWorkflowAttachment $attachment): self
+ {
+ $this->attachments->removeElement($attachment);
+
+ return $this;
+ }
+
public function getComments(): Collection
{
return $this->comments;
@@ -356,6 +392,17 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface
return $this->getCurrentStep()->isOnHoldByUser($user);
}
+ public function isUserInvolved(User $user): bool
+ {
+ foreach ($this->getSteps() as $step) {
+ if ($step->getAllDestUser()->contains($user)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
public function isUserSubscribedToFinal(User $user): bool
{
return $this->subscriberToFinal->contains($user);
@@ -420,7 +467,7 @@ class EntityWorkflow implements TrackCreationInterface, TrackUpdateInterface
}
/**
- * Method use by marking store.
+ * Method used by marking store.
*
* @return $this
*/
diff --git a/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowAttachment.php b/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowAttachment.php
new file mode 100644
index 000000000..83f5b8c50
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowAttachment.php
@@ -0,0 +1,80 @@
+ true])]
+ private array $relatedGenericDocIdentifiers,
+ #[ORM\ManyToOne(targetEntity: EntityWorkflow::class, inversedBy: 'attachments')]
+ #[ORM\JoinColumn(nullable: false, name: 'entityworkflow_id')]
+ private EntityWorkflow $entityWorkflow,
+
+ /**
+ * Stored object related to the generic doc.
+ *
+ * This is a story to keep track more easily to stored object
+ */
+ #[ORM\ManyToOne(targetEntity: StoredObject::class)]
+ #[ORM\JoinColumn(nullable: false, name: 'storedobject_id')]
+ private StoredObject $proxyStoredObject,
+ ) {
+ $this->entityWorkflow->addAttachment($this);
+ }
+
+ public function getId(): ?int
+ {
+ return $this->id;
+ }
+
+ public function getEntityWorkflow(): EntityWorkflow
+ {
+ return $this->entityWorkflow;
+ }
+
+ public function getRelatedGenericDocIdentifiers(): array
+ {
+ return $this->relatedGenericDocIdentifiers;
+ }
+
+ public function getRelatedGenericDocKey(): string
+ {
+ return $this->relatedGenericDocKey;
+ }
+
+ public function getProxyStoredObject(): StoredObject
+ {
+ return $this->proxyStoredObject;
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowComment.php b/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowComment.php
index 2943e5cff..6269a4d11 100644
--- a/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowComment.php
+++ b/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowComment.php
@@ -17,6 +17,11 @@ use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
use Doctrine\ORM\Mapping as ORM;
+/**
+ * Contains comment for entity workflow.
+ *
+ * **NOTE**: for now, this class is not in used. Comments are, for now, stored in the EntityWorkflowStep.
+ */
#[ORM\Entity]
#[ORM\Table('chill_main_workflow_entity_comment')]
class EntityWorkflowComment implements TrackCreationInterface, TrackUpdateInterface
diff --git a/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowStep.php b/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowStep.php
index f9556c33a..24acc4f78 100644
--- a/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowStep.php
+++ b/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowStep.php
@@ -16,9 +16,18 @@ use Chill\MainBundle\Entity\UserGroup;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
-use Symfony\Component\Validator\Constraints as Assert;
-use Symfony\Component\Validator\Context\ExecutionContextInterface;
+/**
+ * A step for each EntityWorkflow.
+ *
+ * The step contains the history of position. The current one is the one which transitionAt or transitionAfter is NULL.
+ *
+ * The comments field is populated by the comment of the one who apply the transition, it means that the comment for the
+ * "next" step is stored in the EntityWorkflowStep in the previous step.
+ *
+ * DestUsers are the one added at the transition. DestUserByAccessKey are the users who obtained permission after having
+ * clicked on a link to get access (email notification to groups).
+ */
#[ORM\Entity]
#[ORM\Table('chill_main_workflow_entity_step')]
class EntityWorkflowStep
@@ -80,6 +89,11 @@ class EntityWorkflowStep
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER)]
private ?int $id = null;
+ /**
+ * If this is the final step.
+ *
+ * This property is filled by a listener.
+ */
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::BOOLEAN, options: ['default' => false])]
private bool $isFinal = false;
@@ -254,6 +268,11 @@ class EntityWorkflowStep
return $this->ccUser;
}
+ /**
+ * This is the comment from the one who apply the transition.
+ *
+ * It means that it must be saved when the user apply a transition.
+ */
public function getComment(): string
{
return $this->comment;
@@ -346,6 +365,9 @@ class EntityWorkflowStep
return $this->transitionByEmail;
}
+ /**
+ * @return bool true if this is the end of the EntityWorkflow
+ */
public function isFinal(): bool
{
return $this->isFinal;
@@ -367,6 +389,9 @@ class EntityWorkflowStep
return false;
}
+ /**
+ * @return bool if the EntityWorkflowStep is waiting for a transition, and is not the final step
+ */
public function isWaitingForTransition(): bool
{
if (null !== $this->transitionAfter) {
@@ -506,26 +531,6 @@ class EntityWorkflowStep
return $this->holdsOnStep;
}
- #[Assert\Callback]
- public function validateOnCreation(ExecutionContextInterface $context, mixed $payload): void
- {
- return;
-
- if ($this->isFinalizeAfter()) {
- if (0 !== \count($this->getDestUser())) {
- $context->buildViolation('workflow.No dest users when the workflow is finalized')
- ->atPath('finalizeAfter')
- ->addViolation();
- }
- } else {
- if (0 === \count($this->getDestUser())) {
- $context->buildViolation('workflow.The next step must count at least one dest')
- ->atPath('finalizeAfter')
- ->addViolation();
- }
- }
- }
-
public function addOnHold(EntityWorkflowStepHold $onHold): self
{
if (!$this->holdsOnStep->contains($onHold)) {
diff --git a/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowStepSignature.php b/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowStepSignature.php
index 945e0d024..8ac9b5a02 100644
--- a/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowStepSignature.php
+++ b/src/Bundle/ChillMainBundle/Entity/Workflow/EntityWorkflowStepSignature.php
@@ -53,6 +53,7 @@ class EntityWorkflowStepSignature implements TrackCreationInterface, TrackUpdate
public function __construct(
#[ORM\ManyToOne(targetEntity: EntityWorkflowStep::class, inversedBy: 'signatures')]
+ #[ORM\JoinColumn(nullable: false)]
private EntityWorkflowStep $step,
User|Person $signer,
) {
diff --git a/src/Bundle/ChillMainBundle/Repository/Workflow/EntityWorkflowAttachmentRepository.php b/src/Bundle/ChillMainBundle/Repository/Workflow/EntityWorkflowAttachmentRepository.php
new file mode 100644
index 000000000..9d7884123
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Repository/Workflow/EntityWorkflowAttachmentRepository.php
@@ -0,0 +1,67 @@
+
+ */
+class EntityWorkflowAttachmentRepository implements ObjectRepository
+{
+ private readonly EntityRepository $repository;
+
+ public function __construct(EntityManagerInterface $registry)
+ {
+ $this->repository = $registry->getRepository(EntityWorkflowAttachment::class);
+ }
+
+ public function find($id): ?EntityWorkflowAttachment
+ {
+ return $this->repository->find($id);
+ }
+
+ public function findAll(): array
+ {
+ return $this->repository->findAll();
+ }
+
+ public function findBy(array $criteria, ?array $orderBy = null, ?int $limit = null, ?int $offset = null): array
+ {
+ return $this->repository->findBy($criteria, $orderBy, $limit, $offset);
+ }
+
+ public function findOneBy(array $criteria)
+ {
+ return $this->repository->findOneBy($criteria);
+ }
+
+ /**
+ * @return array
+ */
+ public function findByStoredObject(StoredObject $storedObject): array
+ {
+ $qb = $this->repository->createQueryBuilder('a');
+ $qb->where('a.proxyStoredObject = :storedObject')->setParameter('storedObject', $storedObject);
+
+ return $qb->getQuery()->getResult();
+ }
+
+ public function getClassName()
+ {
+ return EntityWorkflowAttachment::class;
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/Resources/public/chill/chillmain.scss b/src/Bundle/ChillMainBundle/Resources/public/chill/chillmain.scss
index 4f215859f..1dc56dded 100644
--- a/src/Bundle/ChillMainBundle/Resources/public/chill/chillmain.scss
+++ b/src/Bundle/ChillMainBundle/Resources/public/chill/chillmain.scss
@@ -480,7 +480,7 @@ div.workflow {
section.step {
border: 1px solid $chill-l-gray;
padding: 1em 2em;
- div.flex-table {
+ > div.flex-table {
margin: 1.5em -2em;
}
}
diff --git a/src/Bundle/ChillMainBundle/Resources/public/lib/api/apiMethods.ts b/src/Bundle/ChillMainBundle/Resources/public/lib/api/apiMethods.ts
index ea51c85c2..b50bb5534 100644
--- a/src/Bundle/ChillMainBundle/Resources/public/lib/api/apiMethods.ts
+++ b/src/Bundle/ChillMainBundle/Resources/public/lib/api/apiMethods.ts
@@ -83,6 +83,10 @@ export const makeFetch = (
opts = Object.assign(opts, options);
}
return fetch(url, opts).then((response) => {
+ if (response.status === 204) {
+ return Promise.resolve();
+ }
+
if (response.ok) {
return response.json();
}
@@ -173,18 +177,26 @@ function _fetchAction(
throw new Error("other network error");
})
- .catch((reason: any) => {
- console.error(reason);
- throw new Error(reason);
- });
+ .catch(
+ (
+ reason:
+ | NotFoundExceptionInterface
+ | ServerExceptionInterface
+ | ValidationExceptionInterface
+ | TransportExceptionInterface,
+ ) => {
+ console.error(reason);
+ throw reason;
+ },
+ );
}
export const fetchResults = async (
uri: string,
params?: FetchParams,
): Promise => {
- let promises: Promise[] = [],
- page = 1;
+ const promises: Promise[] = [];
+ let page = 1;
const firstData: PaginationResponse = (await _fetchAction(
page,
uri,
@@ -229,6 +241,7 @@ const ValidationException = (
return error;
};
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
const AccessException = (response: Response): AccessExceptionInterface => {
const error = {} as AccessExceptionInterface;
error.name = "AccessException";
@@ -237,6 +250,7 @@ const AccessException = (response: Response): AccessExceptionInterface => {
return error;
};
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
const NotFoundException = (response: Response): NotFoundExceptionInterface => {
const error = {} as NotFoundExceptionInterface;
error.name = "NotFoundException";
@@ -257,6 +271,7 @@ const ServerException = (
};
const ConflictHttpException = (
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
response: Response,
): ConflictHttpExceptionInterface => {
const error = {} as ConflictHttpExceptionInterface;
diff --git a/src/Bundle/ChillMainBundle/Resources/public/lib/workflow/attachments.ts b/src/Bundle/ChillMainBundle/Resources/public/lib/workflow/attachments.ts
new file mode 100644
index 000000000..7e2f23f57
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Resources/public/lib/workflow/attachments.ts
@@ -0,0 +1,22 @@
+import { WorkflowAttachment } from "ChillMainAssets/types";
+import { GenericDocForAccompanyingPeriod } from "ChillDocStoreAssets/types/generic_doc";
+import { makeFetch } from "ChillMainAssets/lib/api/apiMethods";
+
+export const find_attachments_by_workflow = async (
+ workflowId: number,
+): Promise =>
+ makeFetch("GET", `/api/1.0/main/workflow/${workflowId}/attachment`);
+
+export const create_attachment = async (
+ workflowId: number,
+ genericDoc: GenericDocForAccompanyingPeriod,
+): Promise =>
+ makeFetch("POST", `/api/1.0/main/workflow/${workflowId}/attachment`, {
+ relatedGenericDocKey: genericDoc.key,
+ relatedGenericDocIdentifiers: genericDoc.identifiers,
+ });
+
+export const delete_attachment = async (
+ attachment: WorkflowAttachment,
+): Promise =>
+ makeFetch("DELETE", `/api/1.0/main/workflow/attachment/${attachment.id}`);
diff --git a/src/Bundle/ChillMainBundle/Resources/public/types.ts b/src/Bundle/ChillMainBundle/Resources/public/types.ts
index 7fa1c69dd..b7b62980b 100644
--- a/src/Bundle/ChillMainBundle/Resources/public/types.ts
+++ b/src/Bundle/ChillMainBundle/Resources/public/types.ts
@@ -1,3 +1,5 @@
+import { GenericDoc } from "ChillDocStoreAssets/types/generic_doc";
+
export interface DateTime {
datetime: string;
datetime8601: string;
@@ -190,3 +192,14 @@ export interface WorkflowAvailable {
name: string;
text: string;
}
+
+export interface WorkflowAttachment {
+ id: number;
+ relatedGenericDocKey: string;
+ relatedGenericDocIdentifiers: object;
+ createdAt: DateTime | null;
+ createdBy: User | null;
+ updatedAt: DateTime | null;
+ updatedBy: User | null;
+ genericDoc: null | GenericDoc;
+}
diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/App.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/App.vue
new file mode 100644
index 000000000..eeea00d29
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/App.vue
@@ -0,0 +1,70 @@
+
+
+
+
+ emit('removeAttachment', payload)"
+ >
+
+
+
+ Ajouter une pièce jointe
+
+
+
+
+
+
diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/Component/AttachmentList.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/Component/AttachmentList.vue
new file mode 100644
index 000000000..06e6ca6f4
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/Component/AttachmentList.vue
@@ -0,0 +1,52 @@
+
+
+
+
+ Aucune pièce jointe
+
+
+
+
+
+
diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/Component/GenericDocItemBox.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/Component/GenericDocItemBox.vue
new file mode 100644
index 000000000..8b96b4eea
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/Component/GenericDocItemBox.vue
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/Component/PickGenericDoc.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/Component/PickGenericDoc.vue
new file mode 100644
index 000000000..8d0eda735
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/Component/PickGenericDoc.vue
@@ -0,0 +1,281 @@
+
+
+
+
+
+
+
+
emit('pickGenericDoc', payload)"
+ @removeGenericDoc="
+ (payload) => emit('removeGenericDoc', payload)
+ "
+ >
+
+
+ Aucun document dans ce parcours
+
+
+
+
+
+
diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/Component/PickGenericDocItem.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/Component/PickGenericDocItem.vue
new file mode 100644
index 000000000..e8e35573c
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/Component/PickGenericDocItem.vue
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/Component/PickGenericDocModal.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/Component/PickGenericDocModal.vue
new file mode 100644
index 000000000..cd3e9253d
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/Component/PickGenericDocModal.vue
@@ -0,0 +1,113 @@
+
+
+
+
+
+ Ajouter une pièce jointe
+
+
+
+
+
+
+
+
+
+ Ajouter
+ {{ numberOfPicked }} pièces jointes
+
+
+ Ajouter une pièce jointe
+
+
+
+
+
+
+
+
+
diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/index.ts b/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/index.ts
new file mode 100644
index 000000000..872e6c251
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/WorkflowAttachment/index.ts
@@ -0,0 +1,109 @@
+import { createApp } from "vue";
+import App from "./App.vue";
+import { _createI18n } from "../_js/i18n";
+import { WorkflowAttachment } from "ChillMainAssets/types";
+import {
+ create_attachment,
+ delete_attachment,
+ find_attachments_by_workflow,
+} from "ChillMainAssets/lib/workflow/attachments";
+import { GenericDocForAccompanyingPeriod } from "ChillDocStoreAssets/types/generic_doc";
+import ToastPlugin from "vue-toast-notification";
+import "vue-toast-notification/dist/theme-bootstrap.css";
+
+window.addEventListener("DOMContentLoaded", () => {
+ const attachments = document.querySelectorAll(
+ 'div[data-app="workflow_attachments"]',
+ );
+
+ attachments.forEach(async (el) => {
+ const workflowId = parseInt(el.dataset.entityWorkflowId || "");
+ const accompanyingPeriodId = parseInt(
+ el.dataset.relatedAccompanyingPeriodId || "",
+ );
+ const attachments = await find_attachments_by_workflow(workflowId);
+
+ const app = createApp({
+ template:
+ ' ',
+ components: { App },
+ data: function () {
+ return { workflowId, accompanyingPeriodId, attachments };
+ },
+ methods: {
+ onRemoveAttachment: async function ({
+ attachment,
+ }: {
+ attachment: WorkflowAttachment;
+ }): Promise {
+ const index = this.$data.attachments.findIndex(
+ (el: WorkflowAttachment) => el.id === attachment.id,
+ );
+ if (-1 === index) {
+ console.warn(
+ "this attachment is not associated with the workflow",
+ attachment,
+ );
+ this.$toast.error(
+ "This attachment is not associated with the workflow",
+ );
+ return;
+ }
+
+ try {
+ await delete_attachment(attachment);
+ } catch (error) {
+ console.error(error);
+ this.$toast.error("Error while removing element");
+ throw error;
+ }
+ this.$data.attachments.splice(index, 1);
+ this.$toast.success("Pièce jointe supprimée");
+ },
+ onPickGenericDoc: async function ({
+ genericDoc,
+ }: {
+ genericDoc: GenericDocForAccompanyingPeriod;
+ }): Promise {
+ console.log("picked generic doc", genericDoc);
+
+ // prevent to create double attachment:
+ if (
+ -1 !==
+ this.$data.attachments.findIndex(
+ (el: WorkflowAttachment) =>
+ el.genericDoc?.key === genericDoc.key &&
+ JSON.stringify(el.genericDoc?.identifiers) ==
+ JSON.stringify(genericDoc.identifiers),
+ )
+ ) {
+ console.warn(
+ "this document is already attached to the workflow",
+ genericDoc,
+ );
+ this.$toast.error(
+ "Ce document est déjà attaché au workflow",
+ );
+ return;
+ }
+
+ try {
+ const attachment = await create_attachment(
+ workflowId,
+ genericDoc,
+ );
+ this.$data.attachments.push(attachment);
+ } catch (error) {
+ console.error(error);
+ throw error;
+ }
+ },
+ },
+ });
+ const i18n = _createI18n({});
+ app.use(i18n);
+ app.use(ToastPlugin);
+
+ app.mount(el);
+ });
+});
diff --git a/src/Bundle/ChillMainBundle/Resources/views/Workflow/_attachment.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Workflow/_attachment.html.twig
index 2a1041c6f..d06622ece 100644
--- a/src/Bundle/ChillMainBundle/Resources/views/Workflow/_attachment.html.twig
+++ b/src/Bundle/ChillMainBundle/Resources/views/Workflow/_attachment.html.twig
@@ -1,123 +1,5 @@
-{# TODO
- Check if this template is used
- Adapt condition or Delete it
-#}
-{% if random(1) == 0 %}
-
- {# For a document #}
- {{ 'Document'|trans ~ 'target'|trans }}
-
-
-
-
-
-
-
Imprimé unique, parcours n°14635
-
Document PDF (6.2 Mo)
-
- Description du document. Sed euismod nisi porta lorem mollis aliquam. Non curabitur gravida arcu ac tortor.
-
-
-
-
-{% else %}
-
- {# For an action #}
- {{ 'Accompanying Course Action'|trans ~ 'target'|trans }}
-
-
- {# dynamic insertion
- ::: TODO delete all static insertion, remove condition and pass work object in inclusion
- #}{% if dynamic is defined %}
-
- {% set work = '
' %}
- {% include '@ChillPerson/AccompanyingCourseWork/_item.html.twig' with { 'w': work } %}
-
- {% else %}
-
- {# BEGIN static insertion #}
-
-
-
-
- Exercer un AEB > Conclure l'AEB
-
- Date de début : 25/11/2021
- Date de fin : 10/03/2022
-
-
-
-
-
-
-
-
-
Usagers du parcours
-
-
-
-
Problématique sociale
-
-
- AD - PREVENTION, ACCES AUX DROITS, BUDGET > SOUTIEN EQUILIBRE BUDGET
-
-
-
-
-
-
-
-
- Objectif - motif - dispositif
- Résultats - orientations
-
-
-
-
- Aucun objectif - motif - dispositif
-
-
-
- Résultat : Arrêt à l'initiative du ménage pour déménagement
- Orientation vers une MASP
-
-
-
-
-
-
-
-
- Dernière mise à jour par
- Fred(Responsable tous les territoires) (ASE) ,
- le 3 décembre 2021 à 15:19
-
-
-
- {# END static insertion #}
-
- {% endif %}
-
+{% if related_accompanying_period is not null %}
+ {{ 'workflow.attachments.title'|trans }}
+
{% endif %}
-
-
-
-
- {{ 'Download'|trans }}
-
-
-
- {% set x = random(1) %}
-
-
- {{ 'Edit'|trans }}
-
-
-
diff --git a/src/Bundle/ChillMainBundle/Resources/views/Workflow/index.html.twig b/src/Bundle/ChillMainBundle/Resources/views/Workflow/index.html.twig
index f469e7f66..989f2fa72 100644
--- a/src/Bundle/ChillMainBundle/Resources/views/Workflow/index.html.twig
+++ b/src/Bundle/ChillMainBundle/Resources/views/Workflow/index.html.twig
@@ -11,6 +11,7 @@
{{ encore_entry_script_tags('page_workflow_show') }}
{{ encore_entry_script_tags('mod_wopi_link') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
+ {{ encore_entry_script_tags('mod_workflow_attachment') }}
{% endblock %}
{% block css %}
@@ -20,6 +21,7 @@
{{ encore_entry_link_tags('page_workflow_show') }}
{{ encore_entry_link_tags('mod_wopi_link') }}
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
+ {{ encore_entry_link_tags('mod_workflow_attachment') }}
{% endblock %}
{% import '@ChillMain/Workflow/macro_breadcrumb.html.twig' as macro %}
@@ -58,6 +60,8 @@
{% endif %}
+ {% include '@ChillMain/Workflow/_attachment.html.twig' %}
+
{% include '@ChillMain/Workflow/_follow.html.twig' %}
{% if signatures|length > 0 %}
{% include '@ChillMain/Workflow/_signature.html.twig' %}
diff --git a/src/Bundle/ChillMainBundle/Serializer/Normalizer/EntityWorkflowAttachmentNormalizer.php b/src/Bundle/ChillMainBundle/Serializer/Normalizer/EntityWorkflowAttachmentNormalizer.php
new file mode 100644
index 000000000..38b9f19ec
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Serializer/Normalizer/EntityWorkflowAttachmentNormalizer.php
@@ -0,0 +1,54 @@
+manager->buildOneGenericDoc($object->getRelatedGenericDocKey(), $object->getRelatedGenericDocIdentifiers());
+
+ return [
+ 'id' => $object->getId(),
+ 'relatedGenericDocKey' => $object->getRelatedGenericDocKey(),
+ 'relatedGenericDocIdentifiers' => $object->getRelatedGenericDocIdentifiers(),
+ 'createdAt' => $this->normalizer->normalize($object->getCreatedAt(), $format, $context),
+ 'createdBy' => $this->normalizer->normalize($object->getCreatedBy(), $format, $context),
+ 'updatedAt' => $this->normalizer->normalize($object->getUpdatedAt(), $format, $context),
+ 'updatedBy' => $this->normalizer->normalize($object->getUpdatedBy(), $format, $context),
+ 'genericDoc' => $this->normalizer->normalize($genericDoc, $format, [
+ GenericDocNormalizer::ATTACHED_STORED_OBJECT_PROXY => $object->getProxyStoredObject(), ...$context,
+ ]),
+ ];
+ }
+
+ public function supportsNormalization($data, ?string $format = null)
+ {
+ return 'json' === $format && $data instanceof EntityWorkflowAttachment;
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/Tests/Controller/WorkflowViewSendPublicControllerTest.php b/src/Bundle/ChillMainBundle/Tests/Controller/WorkflowViewSendPublicControllerTest.php
index d5a4d6561..1f48e79c1 100644
--- a/src/Bundle/ChillMainBundle/Tests/Controller/WorkflowViewSendPublicControllerTest.php
+++ b/src/Bundle/ChillMainBundle/Tests/Controller/WorkflowViewSendPublicControllerTest.php
@@ -20,6 +20,7 @@ use Chill\MainBundle\Workflow\EntityWorkflowManager;
use Chill\MainBundle\Workflow\EntityWorkflowWithPublicViewInterface;
use Chill\MainBundle\Workflow\Messenger\PostPublicViewMessage;
use Chill\MainBundle\Workflow\Templating\EntityWorkflowViewMetadataDTO;
+use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\ThirdPartyBundle\Entity\ThirdParty;
use Doctrine\ORM\EntityManagerInterface;
use PHPUnit\Framework\TestCase;
@@ -189,6 +190,11 @@ class WorkflowViewSendPublicControllerTest extends TestCase
throw new \BadMethodCallException('not implemented');
}
+ public function getRelatedAccompanyingPeriod(EntityWorkflow $entityWorkflow): ?AccompanyingPeriod
+ {
+ throw new \BadMethodCallException('not implemented');
+ }
+
public function getRelatedObjects(object $object): array
{
throw new \BadMethodCallException('not implemented');
diff --git a/src/Bundle/ChillMainBundle/Tests/Workflow/Attachment/AddAttachmentActionTest.php b/src/Bundle/ChillMainBundle/Tests/Workflow/Attachment/AddAttachmentActionTest.php
new file mode 100644
index 000000000..6baff49b2
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Tests/Workflow/Attachment/AddAttachmentActionTest.php
@@ -0,0 +1,66 @@
+entityManagerMock = $this->createMock(EntityManagerInterface::class);
+ $this->manager = $this->createMock(ManagerInterface::class);
+ $this->addAttachmentAction = new AddAttachmentAction($this->entityManagerMock, $this->manager);
+ }
+
+ public function testInvokeCreatesAndPersistsEntityWorkflowAttachment(): void
+ {
+ $entityWorkflow = new EntityWorkflow();
+ $dto = new AddAttachmentRequestDTO($entityWorkflow);
+ $dto->relatedGenericDocKey = 'doc_key';
+ $dto->relatedGenericDocIdentifiers = ['id' => 1];
+ $this->manager->method('buildOneGenericDoc')->willReturn($g = new GenericDocDTO('doc_key', ['id' => 1], new \DateTimeImmutable(), new AccompanyingPeriod()));
+ $this->manager->method('fetchStoredObject')->with($g)->willReturn($storedObject = new StoredObject());
+
+ $this->entityManagerMock
+ ->expects($this->once())
+ ->method('persist')
+ ->with($this->isInstanceOf(EntityWorkflowAttachment::class));
+
+ $result = $this->addAttachmentAction->__invoke($dto);
+
+ $this->assertInstanceOf(EntityWorkflowAttachment::class, $result);
+ $this->assertSame('doc_key', $result->getRelatedGenericDocKey());
+ $this->assertSame(['id' => 1], $result->getRelatedGenericDocIdentifiers());
+ $this->assertSame($entityWorkflow, $result->getEntityWorkflow());
+ $this->assertSame($storedObject, $result->getProxyStoredObject());
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/Workflow/Attachment/AddAttachmentAction.php b/src/Bundle/ChillMainBundle/Workflow/Attachment/AddAttachmentAction.php
new file mode 100644
index 000000000..9f2220ab3
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Workflow/Attachment/AddAttachmentAction.php
@@ -0,0 +1,42 @@
+manager->buildOneGenericDoc($dto->relatedGenericDocKey, $dto->relatedGenericDocIdentifiers);
+
+ if (null === $genericDoc) {
+ throw new \RuntimeException(sprintf('could not build any generic doc, %s key and %s identifiers', $dto->relatedGenericDocKey, json_encode($dto->relatedGenericDocIdentifiers)));
+ }
+
+ $storedObject = $this->manager->fetchStoredObject($genericDoc);
+
+ $attachement = new EntityWorkflowAttachment($dto->relatedGenericDocKey, $dto->relatedGenericDocIdentifiers, $dto->entityWorkflow, $storedObject);
+
+ $this->em->persist($attachement);
+
+ return $attachement;
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/Workflow/Attachment/AddAttachmentRequestDTO.php b/src/Bundle/ChillMainBundle/Workflow/Attachment/AddAttachmentRequestDTO.php
new file mode 100644
index 000000000..3d93d2f52
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/Workflow/Attachment/AddAttachmentRequestDTO.php
@@ -0,0 +1,30 @@
+getHandler($entityWorkflow)->getSuggestedThirdParties($entityWorkflow);
}
+
+ public function getRelatedAccompanyingPeriod(EntityWorkflow $entityWorkflow): ?AccompanyingPeriod
+ {
+ return $this->getHandler($entityWorkflow)->getRelatedAccompanyingPeriod($entityWorkflow);
+ }
}
diff --git a/src/Bundle/ChillMainBundle/Workflow/Helper/WorkflowRelatedEntityPermissionHelper.php b/src/Bundle/ChillMainBundle/Workflow/Helper/WorkflowRelatedEntityPermissionHelper.php
index cd890154e..b0694549d 100644
--- a/src/Bundle/ChillMainBundle/Workflow/Helper/WorkflowRelatedEntityPermissionHelper.php
+++ b/src/Bundle/ChillMainBundle/Workflow/Helper/WorkflowRelatedEntityPermissionHelper.php
@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\MainBundle\Workflow\Helper;
+use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Entity\Workflow\EntityWorkflowSignatureStateEnum;
use Chill\MainBundle\Workflow\EntityWorkflowManager;
@@ -146,12 +147,14 @@ class WorkflowRelatedEntityPermissionHelper
{
$currentUser = $this->security->getUser();
+ if (!$currentUser instanceof User) {
+ return false;
+ }
+
foreach ($entityWorkflows as $entityWorkflow) {
// so, the workflow is running... We return true if the current user is involved
- foreach ($entityWorkflow->getSteps() as $step) {
- if ($step->getAllDestUser()->contains($currentUser)) {
- return true;
- }
+ if ($entityWorkflow->isUserInvolved($currentUser)) {
+ return true;
}
}
diff --git a/src/Bundle/ChillMainBundle/chill.api.specs.yaml b/src/Bundle/ChillMainBundle/chill.api.specs.yaml
index ea1ae10bd..6236ba206 100644
--- a/src/Bundle/ChillMainBundle/chill.api.specs.yaml
+++ b/src/Bundle/ChillMainBundle/chill.api.specs.yaml
@@ -10,6 +10,50 @@ servers:
components:
schemas:
+ EntityWorkflowAttachment:
+ type: object
+ properties:
+ id:
+ type: number
+ format: u64
+ minimum: 0
+ relatedGenericDocKey:
+ type: string
+ relatedGenericDocIdentifiers:
+ type: object
+ AddAttachmentRequest:
+ description: "A request to add attachment in an entity workflow"
+ type: object
+ properties:
+ relatedGenericDocKey:
+ type: string
+ relatedGenericDocIdentifiers:
+ type: object
+ PaginatedResult:
+ type: object
+ properties:
+ count:
+ type: number
+ format: u64
+ pagination:
+ type: object
+ properties:
+ first:
+ type: number
+ format: u64
+ minimum: 0
+ items_per_page:
+ type: number
+ format: u64
+ minimum: 0
+ next:
+ type: string
+ nullable: true
+ previous:
+ type: string
+ nullable: true
+ more:
+ type: boolean
Date:
type: object
properties:
@@ -990,3 +1034,70 @@ paths:
$ref: '#/components/schemas/UserGroup'
403:
description: "Unauthorized"
+ /1.0/main/workflow/{id}/attachment:
+ get:
+ tags:
+ - workflow
+ summary: Get a list of attachements for a given workflow
+ parameters:
+ - name: id
+ in: path
+ required: true
+ description: The entity workflow id
+ schema:
+ type: integer
+ format: integer
+ minimum: 1
+ responses:
+ 200:
+ description: "ok"
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/EntityWorkflowAttachment'
+ post:
+ tags:
+ - workflow
+ summary: Create a new attachment
+ parameters:
+ - name: id
+ in: path
+ required: true
+ description: The entity workflow id
+ schema:
+ type: integer
+ format: integer
+ minimum: 1
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/AddAttachmentRequest'
+ responses:
+ 200:
+ description: "ok"
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/EntityWorkflowAttachment'
+ /1.0/main/workflow/attachment/{id}:
+ delete:
+ tags:
+ - workflow
+ summary: Remove an attachment
+ parameters:
+ - name: id
+ in: path
+ required: true
+ description: The entity workflow 's attachment id
+ schema:
+ type: integer
+ format: integer
+ minimum: 1
+ responses:
+ 204:
+ description: "resource was deleted successfully"
+
diff --git a/src/Bundle/ChillMainBundle/chill.webpack.config.js b/src/Bundle/ChillMainBundle/chill.webpack.config.js
index 36f34a2fd..ee640e677 100644
--- a/src/Bundle/ChillMainBundle/chill.webpack.config.js
+++ b/src/Bundle/ChillMainBundle/chill.webpack.config.js
@@ -150,6 +150,10 @@ module.exports = function (encore, entries) {
"mod_news",
__dirname + "/Resources/public/module/news/index.js",
);
+ encore.addEntry(
+ "mod_workflow_attachment",
+ __dirname + "/Resources/public/vuejs/WorkflowAttachment/index",
+ );
// Vue entrypoints
encore.addEntry(
diff --git a/src/Bundle/ChillMainBundle/config/services.yaml b/src/Bundle/ChillMainBundle/config/services.yaml
index 86f15097b..a9829f99d 100644
--- a/src/Bundle/ChillMainBundle/config/services.yaml
+++ b/src/Bundle/ChillMainBundle/config/services.yaml
@@ -33,6 +33,8 @@ services:
# workflow related
Chill\MainBundle\Workflow\:
resource: '../Workflow/'
+ exclude:
+ - '../Workflow/Attachment/AddAttachmentRequestDTO.php'
Chill\MainBundle\Workflow\EntityWorkflowManager:
arguments:
diff --git a/src/Bundle/ChillMainBundle/migrations/Version20241129112740.php b/src/Bundle/ChillMainBundle/migrations/Version20241129112740.php
new file mode 100644
index 000000000..b33993209
--- /dev/null
+++ b/src/Bundle/ChillMainBundle/migrations/Version20241129112740.php
@@ -0,0 +1,51 @@
+addSql('CREATE SEQUENCE chill_main_workflow_entity_attachment_id_seq INCREMENT BY 1 MINVALUE 1 START 1');
+ $this->addSql('CREATE TABLE chill_main_workflow_entity_attachment (id INT NOT NULL, relatedGenericDocKey VARCHAR(255) NOT NULL, relatedGenericDocIdentifiers JSONB NOT NULL, createdAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, updatedAt TIMESTAMP(0) WITHOUT TIME ZONE DEFAULT NULL, entityWorkflow_id INT NOT NULL, createdBy_id INT DEFAULT NULL, updatedBy_id INT DEFAULT NULL, PRIMARY KEY(id))');
+ $this->addSql('CREATE INDEX IDX_279415FFFB054143 ON chill_main_workflow_entity_attachment (entityWorkflow_id)');
+ $this->addSql('CREATE INDEX IDX_279415FF3174800F ON chill_main_workflow_entity_attachment (createdBy_id)');
+ $this->addSql('CREATE INDEX IDX_279415FF65FF1AEC ON chill_main_workflow_entity_attachment (updatedBy_id)');
+ $this->addSql('CREATE UNIQUE INDEX unique_generic_doc_by_workflow ON chill_main_workflow_entity_attachment (relatedGenericDocKey, relatedGenericDocIdentifiers, entityworkflow_id)');
+ $this->addSql('COMMENT ON COLUMN chill_main_workflow_entity_attachment.createdAt IS \'(DC2Type:datetime_immutable)\'');
+ $this->addSql('COMMENT ON COLUMN chill_main_workflow_entity_attachment.updatedAt IS \'(DC2Type:datetime_immutable)\'');
+ $this->addSql('ALTER TABLE chill_main_workflow_entity_attachment ADD CONSTRAINT FK_279415FFFB054143 FOREIGN KEY (entityWorkflow_id) REFERENCES chill_main_workflow_entity (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE chill_main_workflow_entity_attachment ADD CONSTRAINT FK_279415FF3174800F FOREIGN KEY (createdBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE chill_main_workflow_entity_attachment ADD CONSTRAINT FK_279415FF65FF1AEC FOREIGN KEY (updatedBy_id) REFERENCES users (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('ALTER TABLE chill_main_workflow_entity_attachment ADD storedobject_id INT NOT NULL');
+ $this->addSql('ALTER TABLE chill_main_workflow_entity_attachment ADD CONSTRAINT FK_279415FFEE684399 FOREIGN KEY (storedobject_id) REFERENCES chill_doc.stored_object (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
+ $this->addSql('CREATE INDEX IDX_279415FFEE684399 ON chill_main_workflow_entity_attachment (storedobject_id)');
+ $this->addSql('ALTER INDEX idx_279415fffb054143 RENAME TO IDX_279415FF7D99CE94');
+ }
+
+ public function down(Schema $schema): void
+ {
+ $this->addSql('DROP SEQUENCE chill_main_workflow_entity_attachment_id_seq CASCADE');
+ $this->addSql('ALTER TABLE chill_main_workflow_entity_attachment DROP CONSTRAINT FK_279415FFFB054143');
+ $this->addSql('ALTER TABLE chill_main_workflow_entity_attachment DROP CONSTRAINT FK_279415FF3174800F');
+ $this->addSql('ALTER TABLE chill_main_workflow_entity_attachment DROP CONSTRAINT FK_279415FF65FF1AEC');
+ $this->addSql('DROP TABLE chill_main_workflow_entity_attachment');
+ }
+}
diff --git a/src/Bundle/ChillMainBundle/translations/messages.fr.yml b/src/Bundle/ChillMainBundle/translations/messages.fr.yml
index d2a760d53..d05ab595c 100644
--- a/src/Bundle/ChillMainBundle/translations/messages.fr.yml
+++ b/src/Bundle/ChillMainBundle/translations/messages.fr.yml
@@ -612,6 +612,9 @@ workflow:
reject_signature_of: Rejet de la signature de %signer%
reject_are_you_sure: Êtes-vous sûr de vouloir rejeter la signature de %signer%
+ attachments:
+ title: Pièces jointes
+
Subscribe final: Recevoir une notification à l'étape finale
Subscribe all steps: Recevoir une notification à chaque étape
CHILL_MAIN_WORKFLOW_APPLY_ALL_TRANSITION: Appliquer les transitions sur tous les workflows
diff --git a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkEvaluationDocument.php b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkEvaluationDocument.php
index ae0546516..01c3ed69d 100644
--- a/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkEvaluationDocument.php
+++ b/src/Bundle/ChillPersonBundle/Entity/AccompanyingPeriod/AccompanyingPeriodWorkEvaluationDocument.php
@@ -60,9 +60,10 @@ class AccompanyingPeriodWorkEvaluationDocument implements \Chill\MainBundle\Doct
#[ORM\ManyToOne(targetEntity: DocGeneratorTemplate::class)]
private ?DocGeneratorTemplate $template = null;
- #[Serializer\Groups(['read', 'write', 'accompanying_period_work_evaluation:create'])]
- #[ORM\Column(type: \Doctrine\DBAL\Types\Types::TEXT, nullable: false, options: ['default' => ''])]
- private ?string $title = '';
+ /**
+ * Store the title only if the storedObject is not yet associated with the instance.
+ */
+ private string $proxyTitle = '';
public function getAccompanyingPeriodWorkEvaluation(): ?AccompanyingPeriodWorkEvaluation
{
@@ -89,9 +90,10 @@ class AccompanyingPeriodWorkEvaluationDocument implements \Chill\MainBundle\Doct
return $this->template;
}
+ #[Serializer\Groups(['read'])]
public function getTitle(): ?string
{
- return $this->title;
+ return (string) $this->getStoredObject()?->getTitle();
}
public function setAccompanyingPeriodWorkEvaluation(?AccompanyingPeriodWorkEvaluation $accompanyingPeriodWorkEvaluation): AccompanyingPeriodWorkEvaluationDocument
@@ -125,6 +127,10 @@ class AccompanyingPeriodWorkEvaluationDocument implements \Chill\MainBundle\Doct
{
$this->storedObject = $storedObject;
+ if ('' !== $this->proxyTitle) {
+ $this->storedObject->setTitle($this->proxyTitle);
+ }
+
return $this;
}
@@ -135,9 +141,14 @@ class AccompanyingPeriodWorkEvaluationDocument implements \Chill\MainBundle\Doct
return $this;
}
- public function setTitle(?string $title): AccompanyingPeriodWorkEvaluationDocument
+ #[Serializer\Groups(['write', 'accompanying_period_work_evaluation:create'])]
+ public function setTitle(?string $proxyTitle): AccompanyingPeriodWorkEvaluationDocument
{
- $this->title = $title;
+ if (null !== $this->storedObject) {
+ $this->storedObject->setTitle((string) $proxyTitle);
+ } else {
+ $this->proxyTitle = (string) $proxyTitle;
+ }
return $this;
}
diff --git a/src/Bundle/ChillPersonBundle/Resources/views/GenericDoc/evaluation_document.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/GenericDoc/evaluation_document.html.twig
index 70ff82b88..7d7852f2e 100644
--- a/src/Bundle/ChillPersonBundle/Resources/views/GenericDoc/evaluation_document.html.twig
+++ b/src/Bundle/ChillPersonBundle/Resources/views/GenericDoc/evaluation_document.html.twig
@@ -1,83 +1,3 @@
-{% import "@ChillDocStore/Macro/macro.html.twig" as m %}
-{% import "@ChillDocStore/Macro/macro_mimeicon.html.twig" as mm %}
-{% import '@ChillPerson/Macro/updatedBy.html.twig' as mmm %}
-
-{% set w = document.accompanyingPeriodWorkEvaluation.accompanyingPeriodWork %}
-
-
-
- {% if document.storedObject.isPending %}
-
{{ 'docgen.Doc generation is pending'|trans }}
- {% elseif document.storedObject.isFailure %}
-
{{ 'docgen.Doc generation failed'|trans }}
- {% endif %}
-
- {% if context == 'person' %}
-
- {{ w.accompanyingPeriod.id }}
-
- {% endif %}
-
-
- {{ w.socialAction|chill_entity_render_string }} > {{ document.accompanyingPeriodWorkEvaluation.evaluation.title|localize_translatable_string }}
-
-
-
- {{ document.title|chill_print_or_message("No title") }}
-
- {% if document.storedObject.type is not empty %}
-
- {{ mm.mimeIcon(document.storedObject.type) }}
-
- {% endif %}
- {% if document.storedObject.hasTemplate %}
-
-
{{ document.storedObject.template.name|localize_translatable_string }}
-
- {% endif %}
-
-
-
-
-
- {{ document.storedObject.createdAt|format_date('short') }}
-
-
-
-
-
-
-
- {{ mmm.createdBy(document) }}
-
-
-
- {{ chill_entity_workflow_list('Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluationDocument', document.id) }}
-
- {% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_EVALUATION_DOCUMENT_SHOW', document) %}
-
- {{ document.storedObject|chill_document_button_group(document.title, is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', document.accompanyingPeriodWorkEvaluation.accompanyingPeriodWork)) }}
-
- {% endif %}
- {% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', w) %}
-
-
-
- {% endif %}
- {% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', w) %}
-
-
-
- {% endif %}
- {% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_SEE', w)%}
-
-
-
- {% endif %}
-
-
-
+ {{ include('@ChillPerson/GenericDoc/evaluation_document_row.html.twig') }}
diff --git a/src/Bundle/ChillPersonBundle/Resources/views/GenericDoc/evaluation_document_row.html.twig b/src/Bundle/ChillPersonBundle/Resources/views/GenericDoc/evaluation_document_row.html.twig
new file mode 100644
index 000000000..451857628
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Resources/views/GenericDoc/evaluation_document_row.html.twig
@@ -0,0 +1,82 @@
+{% import "@ChillDocStore/Macro/macro.html.twig" as m %}
+{% import "@ChillDocStore/Macro/macro_mimeicon.html.twig" as mm %}
+{% import '@ChillPerson/Macro/updatedBy.html.twig' as mmm %}
+
+{% set w = document.accompanyingPeriodWorkEvaluation.accompanyingPeriodWork %}
+
+
+
+ {% if document.storedObject.isPending %}
+
{{ 'docgen.Doc generation is pending'|trans }}
+ {% elseif document.storedObject.isFailure %}
+
{{ 'docgen.Doc generation failed'|trans }}
+ {% endif %}
+
+ {% if context == 'person' %}
+
+ {{ w.accompanyingPeriod.id }}
+
+ {% endif %}
+
+
+ {{ w.socialAction|chill_entity_render_string }} > {{ document.accompanyingPeriodWorkEvaluation.evaluation.title|localize_translatable_string }}
+
+
+
+ {{ document.title|chill_print_or_message("No title") }}
+
+ {% if document.storedObject.type is not empty %}
+
+ {{ mm.mimeIcon(document.storedObject.type) }}
+
+ {% endif %}
+ {% if document.storedObject.hasTemplate %}
+
+
{{ document.storedObject.template.name|localize_translatable_string }}
+
+ {% endif %}
+
+
+
+
+
+ {{ document.storedObject.createdAt|format_date('short') }}
+
+
+
+
+
+{% if show_actions %}
+
+
+ {{ mmm.createdBy(document) }}
+
+
+
+ {{ chill_entity_workflow_list('Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluationDocument', document.id) }}
+
+ {% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_EVALUATION_DOCUMENT_SHOW', document) %}
+
+ {{ document.storedObject|chill_document_button_group(document.title, is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', document.accompanyingPeriodWorkEvaluation.accompanyingPeriodWork)) }}
+
+ {% endif %}
+ {% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', w) %}
+
+
+
+ {% endif %}
+ {% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', w) %}
+
+
+
+ {% endif %}
+ {% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_SEE', w)%}
+
+
+
+ {% endif %}
+
+
+{% endif %}
diff --git a/src/Bundle/ChillPersonBundle/Service/GenericDoc/Normalizer/AccompanyingPeriodWorkEvaluationGenericDocNormalizer.php b/src/Bundle/ChillPersonBundle/Service/GenericDoc/Normalizer/AccompanyingPeriodWorkEvaluationGenericDocNormalizer.php
new file mode 100644
index 000000000..c2536811f
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Service/GenericDoc/Normalizer/AccompanyingPeriodWorkEvaluationGenericDocNormalizer.php
@@ -0,0 +1,51 @@
+key;
+ }
+
+ public function normalize(GenericDocDTO $genericDocDTO, string $format, array $context = []): array
+ {
+ if (null === $evaluationDoc = $this->accompanyingPeriodWorkEvaluationDocumentRepository->find($genericDocDTO->identifiers['id'])) {
+ return ['title' => $this->translator->trans('generic_doc.document removed'), 'isPresent' => false];
+ }
+
+ return [
+ 'title' => $evaluationDoc->getTitle(),
+ 'html' => $this->twig->render(
+ $this->renderer->getTemplate($genericDocDTO, ['show-actions' => false, 'row-only' => true]),
+ $this->renderer->getTemplateData($genericDocDTO, ['show-actions' => false, 'row-only' => true])
+ ),
+ 'isPresent' => true,
+ ];
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/Service/GenericDoc/Providers/AccompanyingPeriodWorkEvaluationGenericDocProvider.php b/src/Bundle/ChillPersonBundle/Service/GenericDoc/Providers/AccompanyingPeriodWorkEvaluationGenericDocProvider.php
index a9617e3c9..3f69c1f1c 100644
--- a/src/Bundle/ChillPersonBundle/Service/GenericDoc/Providers/AccompanyingPeriodWorkEvaluationGenericDocProvider.php
+++ b/src/Bundle/ChillPersonBundle/Service/GenericDoc/Providers/AccompanyingPeriodWorkEvaluationGenericDocProvider.php
@@ -14,10 +14,12 @@ namespace Chill\PersonBundle\Service\GenericDoc\Providers;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\GenericDoc\FetchQuery;
use Chill\DocStoreBundle\GenericDoc\FetchQueryInterface;
+use Chill\DocStoreBundle\GenericDoc\GenericDocDTO;
use Chill\DocStoreBundle\GenericDoc\GenericDocForAccompanyingPeriodProviderInterface;
use Chill\DocStoreBundle\GenericDoc\GenericDocForPersonProviderInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
+use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocumentRepository;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodWorkVoter;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\EntityManagerInterface;
@@ -30,8 +32,38 @@ final readonly class AccompanyingPeriodWorkEvaluationGenericDocProvider implemen
public function __construct(
private Security $security,
private EntityManagerInterface $entityManager,
+ private AccompanyingPeriodWorkEvaluationDocumentRepository $accompanyingPeriodWorkEvaluationDocumentRepository,
) {}
+ public function fetchAssociatedStoredObject(GenericDocDTO $genericDocDTO): ?StoredObject
+ {
+ return $this->accompanyingPeriodWorkEvaluationDocumentRepository->find($genericDocDTO->identifiers['id'])?->getStoredObject();
+ }
+
+ public function supportsGenericDoc(GenericDocDTO $genericDocDTO): bool
+ {
+ return $this->supportsKeyAndIdentifiers($genericDocDTO->key, $genericDocDTO->identifiers);
+ }
+
+ public function supportsKeyAndIdentifiers(string $key, array $identifiers): bool
+ {
+ return self::KEY === $key;
+ }
+
+ public function buildOneGenericDoc(string $key, array $identifiers): ?GenericDocDTO
+ {
+ if (null === $document = $this->accompanyingPeriodWorkEvaluationDocumentRepository->find($identifiers['id'])) {
+ return null;
+ }
+
+ return new GenericDocDTO(
+ $key,
+ $identifiers,
+ $document->getAccompanyingPeriodWorkEvaluation()->getCreatedAt(),
+ $document->getAccompanyingPeriodWorkEvaluation()->getAccompanyingPeriodWork()->getAccompanyingPeriod()
+ );
+ }
+
public function buildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null, ?string $origin = null): FetchQueryInterface
{
$accompanyingPeriodWorkMetadata = $this->entityManager->getClassMetadata(AccompanyingPeriod\AccompanyingPeriodWork::class);
@@ -53,7 +85,6 @@ final readonly class AccompanyingPeriodWorkEvaluationGenericDocProvider implemen
private function addWhereClausesToQuery(FetchQuery $query, ?\DateTimeImmutable $startDate = null, ?\DateTimeImmutable $endDate = null, ?string $content = null): FetchQuery
{
- $classMetadata = $this->entityManager->getClassMetadata(AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument::class);
$storedObjectMetadata = $this->entityManager->getClassMetadata(StoredObject::class);
if (null !== $startDate) {
@@ -74,7 +105,7 @@ final readonly class AccompanyingPeriodWorkEvaluationGenericDocProvider implemen
if (null !== $content) {
$query->addWhereClause(
- sprintf('apwed.%s ilike ?', $classMetadata->getColumnName('title')),
+ sprintf('doc_store.%s ilike ?', $storedObjectMetadata->getColumnName('title')),
['%'.$content.'%'],
[Types::STRING]
);
diff --git a/src/Bundle/ChillPersonBundle/Service/GenericDoc/Renderer/AccompanyingPeriodWorkEvaluationGenericDocRenderer.php b/src/Bundle/ChillPersonBundle/Service/GenericDoc/Renderer/AccompanyingPeriodWorkEvaluationGenericDocRenderer.php
index 7c6f2264f..42fc5b658 100644
--- a/src/Bundle/ChillPersonBundle/Service/GenericDoc/Renderer/AccompanyingPeriodWorkEvaluationGenericDocRenderer.php
+++ b/src/Bundle/ChillPersonBundle/Service/GenericDoc/Renderer/AccompanyingPeriodWorkEvaluationGenericDocRenderer.php
@@ -16,6 +16,9 @@ use Chill\DocStoreBundle\GenericDoc\Twig\GenericDocRendererInterface;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocumentRepository;
use Chill\PersonBundle\Service\GenericDoc\Providers\AccompanyingPeriodWorkEvaluationGenericDocProvider;
+/**
+ * @implements GenericDocRendererInterface
+ */
final readonly class AccompanyingPeriodWorkEvaluationGenericDocRenderer implements GenericDocRendererInterface
{
public function __construct(
@@ -29,7 +32,8 @@ final readonly class AccompanyingPeriodWorkEvaluationGenericDocRenderer implemen
public function getTemplate(GenericDocDTO $genericDocDTO, $options = []): string
{
- return '@ChillPerson/GenericDoc/evaluation_document.html.twig';
+ return ($options['row-only'] ?? false) ? '@ChillPerson/GenericDoc/evaluation_document_row.html.twig'
+ : '@ChillPerson/GenericDoc/evaluation_document.html.twig';
}
public function getTemplateData(GenericDocDTO $genericDocDTO, $options = []): array
@@ -37,6 +41,7 @@ final readonly class AccompanyingPeriodWorkEvaluationGenericDocRenderer implemen
return [
'document' => $this->accompanyingPeriodWorkEvaluationDocumentRepository->find($genericDocDTO->identifiers['id']),
'context' => $genericDocDTO->getContext(),
+ 'show_actions' => $options['show-actions'] ?? true,
];
}
}
diff --git a/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/AccompanyingPeriodCalendarGenericDocProviderTest.php b/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/AccompanyingPeriodCalendarGenericDocProviderTest.php
index cae53d9a5..06d4b37f9 100644
--- a/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/AccompanyingPeriodCalendarGenericDocProviderTest.php
+++ b/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/AccompanyingPeriodCalendarGenericDocProviderTest.php
@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Service\GenericDoc\Providers;
+use Chill\CalendarBundle\Repository\CalendarDocRepositoryInterface;
use Chill\CalendarBundle\Security\Voter\CalendarVoter;
use Chill\CalendarBundle\Service\GenericDoc\Providers\AccompanyingPeriodCalendarGenericDocProvider;
use Chill\DocStoreBundle\GenericDoc\FetchQueryToSqlBuilder;
@@ -35,11 +36,14 @@ class AccompanyingPeriodCalendarGenericDocProviderTest extends KernelTestCase
private EntityManagerInterface $entityManager;
+ private CalendarDocRepositoryInterface $calendarDocRepository;
+
protected function setUp(): void
{
self::bootKernel();
$this->security = self::getContainer()->get(Security::class);
$this->entityManager = self::getContainer()->get(EntityManagerInterface::class);
+ $this->calendarDocRepository = self::getContainer()->get(CalendarDocRepositoryInterface::class);
}
/**
@@ -47,7 +51,7 @@ class AccompanyingPeriodCalendarGenericDocProviderTest extends KernelTestCase
*/
public function testBuildFetchQueryForAccompanyingPeriod(AccompanyingPeriod $accompanyingPeriod, ?\DateTimeImmutable $startDate, ?\DateTimeImmutable $endDate, ?string $content): void
{
- $provider = new AccompanyingPeriodCalendarGenericDocProvider($this->security, $this->entityManager);
+ $provider = new AccompanyingPeriodCalendarGenericDocProvider($this->security, $this->entityManager, $this->calendarDocRepository);
$query = $provider->buildFetchQueryForAccompanyingPeriod($accompanyingPeriod, $startDate, $endDate, $content);
@@ -66,7 +70,7 @@ class AccompanyingPeriodCalendarGenericDocProviderTest extends KernelTestCase
$security = $this->prophesize(Security::class);
$security->isGranted(CalendarVoter::SEE, Argument::any())->willReturn(true);
- $provider = new AccompanyingPeriodCalendarGenericDocProvider($security->reveal(), $this->entityManager);
+ $provider = new AccompanyingPeriodCalendarGenericDocProvider($security->reveal(), $this->entityManager, $this->calendarDocRepository);
$query = $provider->buildFetchQueryForPerson($person, $startDate, $endDate, $content);
@@ -87,7 +91,7 @@ class AccompanyingPeriodCalendarGenericDocProviderTest extends KernelTestCase
$security = $this->prophesize(Security::class);
$security->isGranted(CalendarVoter::SEE, Argument::any())->willReturn(false);
- $provider = new AccompanyingPeriodCalendarGenericDocProvider($security->reveal(), $this->entityManager);
+ $provider = new AccompanyingPeriodCalendarGenericDocProvider($security->reveal(), $this->entityManager, $this->calendarDocRepository);
$query = $provider->buildFetchQueryForPerson($person, $startDate, $endDate, $content);
diff --git a/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/AccompanyingPeriodWorkEvaluationGenericDocProviderTest.php b/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/AccompanyingPeriodWorkEvaluationGenericDocProviderTest.php
index a90d5f751..7bf2b6bd8 100644
--- a/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/AccompanyingPeriodWorkEvaluationGenericDocProviderTest.php
+++ b/src/Bundle/ChillPersonBundle/Tests/Service/GenericDoc/Providers/AccompanyingPeriodWorkEvaluationGenericDocProviderTest.php
@@ -9,10 +9,11 @@ declare(strict_types=1);
* the LICENSE file that was distributed with this source code.
*/
-namespace Service\GenericDoc\Providers;
+namespace Chill\PersonBundle\Tests\Service\GenericDoc\Providers;
use Chill\DocStoreBundle\GenericDoc\FetchQueryToSqlBuilder;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
+use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocumentRepository;
use Chill\PersonBundle\Service\GenericDoc\Providers\AccompanyingPeriodWorkEvaluationGenericDocProvider;
use Doctrine\ORM\EntityManagerInterface;
use Prophecy\PhpUnit\ProphecyTrait;
@@ -29,10 +30,13 @@ class AccompanyingPeriodWorkEvaluationGenericDocProviderTest extends KernelTestC
use ProphecyTrait;
private EntityManagerInterface $entityManager;
+ private AccompanyingPeriodWorkEvaluationDocumentRepository $repository;
+
protected function setUp(): void
{
self::bootKernel();
$this->entityManager = self::getContainer()->get(EntityManagerInterface::class);
+ $this->repository = self::getContainer()->get(AccompanyingPeriodWorkEvaluationDocumentRepository::class);
}
/**
@@ -55,7 +59,8 @@ class AccompanyingPeriodWorkEvaluationGenericDocProviderTest extends KernelTestC
$provider = new AccompanyingPeriodWorkEvaluationGenericDocProvider(
$security->reveal(),
- $this->entityManager
+ $this->entityManager,
+ $this->repository,
);
$query = $provider->buildFetchQueryForAccompanyingPeriod($period, $startDate, $endDate, $content);
diff --git a/src/Bundle/ChillPersonBundle/Workflow/AccompanyingPeriodWorkEvaluationDocumentWorkflowHandler.php b/src/Bundle/ChillPersonBundle/Workflow/AccompanyingPeriodWorkEvaluationDocumentWorkflowHandler.php
index 780b81c1d..9d3b30df3 100644
--- a/src/Bundle/ChillPersonBundle/Workflow/AccompanyingPeriodWorkEvaluationDocumentWorkflowHandler.php
+++ b/src/Bundle/ChillPersonBundle/Workflow/AccompanyingPeriodWorkEvaluationDocumentWorkflowHandler.php
@@ -20,6 +20,7 @@ use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\MainBundle\Workflow\EntityWorkflowWithPublicViewInterface;
use Chill\MainBundle\Workflow\EntityWorkflowWithStoredObjectHandlerInterface;
use Chill\MainBundle\Workflow\Templating\EntityWorkflowViewMetadataDTO;
+use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocumentRepository;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodWorkEvaluationDocumentVoter;
@@ -85,6 +86,12 @@ class AccompanyingPeriodWorkEvaluationDocumentWorkflowHandler implements EntityW
return $this->repository->find($entityWorkflow->getRelatedEntityId());
}
+ public function getRelatedAccompanyingPeriod(EntityWorkflow $entityWorkflow): ?AccompanyingPeriod
+ {
+ return $this->getRelatedEntity($entityWorkflow)?->getAccompanyingPeriodWorkEvaluation()->getAccompanyingPeriodWork()
+ ->getAccompanyingPeriod();
+ }
+
/**
* @return array[]
*/
diff --git a/src/Bundle/ChillPersonBundle/Workflow/AccompanyingPeriodWorkEvaluationWorkflowHandler.php b/src/Bundle/ChillPersonBundle/Workflow/AccompanyingPeriodWorkEvaluationWorkflowHandler.php
index 3e72e65bd..3943cb5d4 100644
--- a/src/Bundle/ChillPersonBundle/Workflow/AccompanyingPeriodWorkEvaluationWorkflowHandler.php
+++ b/src/Bundle/ChillPersonBundle/Workflow/AccompanyingPeriodWorkEvaluationWorkflowHandler.php
@@ -15,6 +15,7 @@ use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\MainBundle\Workflow\EntityWorkflowHandlerInterface;
+use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument;
use Chill\PersonBundle\Repository\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationRepository;
@@ -66,6 +67,11 @@ readonly class AccompanyingPeriodWorkEvaluationWorkflowHandler implements Entity
return $this->repository->find($entityWorkflow->getRelatedEntityId());
}
+ public function getRelatedAccompanyingPeriod(EntityWorkflow $entityWorkflow): ?AccompanyingPeriod
+ {
+ return $this->getRelatedEntity($entityWorkflow)?->getAccompanyingPeriodWork()->getAccompanyingPeriod();
+ }
+
public function getRelatedObjects(object $object): array
{
$relateds = [];
diff --git a/src/Bundle/ChillPersonBundle/Workflow/AccompanyingPeriodWorkWorkflowHandler.php b/src/Bundle/ChillPersonBundle/Workflow/AccompanyingPeriodWorkWorkflowHandler.php
index 58d3c9875..6f67c5c59 100644
--- a/src/Bundle/ChillPersonBundle/Workflow/AccompanyingPeriodWorkWorkflowHandler.php
+++ b/src/Bundle/ChillPersonBundle/Workflow/AccompanyingPeriodWorkWorkflowHandler.php
@@ -15,6 +15,7 @@ use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use Chill\MainBundle\Workflow\EntityWorkflowHandlerInterface;
+use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument;
@@ -68,6 +69,11 @@ readonly class AccompanyingPeriodWorkWorkflowHandler implements EntityWorkflowHa
return $this->repository->find($entityWorkflow->getRelatedEntityId());
}
+ public function getRelatedAccompanyingPeriod(EntityWorkflow $entityWorkflow): ?AccompanyingPeriod
+ {
+ return $this->getRelatedEntity($entityWorkflow)?->getAccompanyingPeriod();
+ }
+
public function getRelatedObjects(object $object): array
{
$relateds = [];
diff --git a/src/Bundle/ChillPersonBundle/migrations/Version20241212120202.php b/src/Bundle/ChillPersonBundle/migrations/Version20241212120202.php
new file mode 100644
index 000000000..dbf42ccff
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/migrations/Version20241212120202.php
@@ -0,0 +1,35 @@
+addSql('UPDATE chill_doc.stored_object SET title = doc.title FROM chill_person_accompanying_period_work_evaluation_document doc WHERE storedobject_id = stored_object.id');
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_work_evaluation_document DROP title');
+ }
+
+ public function down(Schema $schema): void
+ {
+ $this->addSql('ALTER TABLE chill_person_accompanying_period_work_evaluation_document ADD title TEXT DEFAULT \'\' NOT NULL');
+ $this->addSql('UPDATE chill_person_accompanying_period_work_evaluation_document SET title = so.title FROM chill_doc.stored_object so WHERE storedobject_id = so.id');
+ }
+}
diff --git a/tsconfig.json b/tsconfig.json
index f4eec6d81..34cea65e0 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,9 +1,9 @@
{
- "extends": "@tsconfig/node14/tsconfig.json",
+ "extends": "@tsconfig/node20/tsconfig.json",
"compilerOptions": {
"paths": {
- "ChillMainAssets": ["./src/Bundle/ChillMainBundle/Resources/public"],
- "ChillDocStoreAssets": ["./src/Bundle/ChillDocStoreBundle/Resources/public"]
+ "ChillMainAssets/*": ["./src/Bundle/ChillMainBundle/Resources/public/*"],
+ "ChillDocStoreAssets/*": ["./src/Bundle/ChillDocStoreBundle/Resources/public/*"]
},
"lib": [
"es2020",
diff --git a/yarn.lock b/yarn.lock
index 152ba9185..9539fd93f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2065,10 +2065,10 @@
resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
-"@tsconfig/node14@^1.0.1":
- version "1.0.3"
- resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1"
- integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
+"@tsconfig/node20@^20.1.4":
+ version "20.1.4"
+ resolved "https://registry.yarnpkg.com/@tsconfig/node20/-/node20-20.1.4.tgz#3457d42eddf12d3bde3976186ab0cd22b85df928"
+ integrity sha512-sqgsT69YFeLWf5NtJ4Xq/xAF8p4ZQHlmGW74Nu2tD4+g5fAsposc4ZfaaPixVu4y01BEiDCWLRDCvDM5JOsRxg==
"@types/body-parser@*":
version "1.19.5"