diff --git a/src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseDuplicateController.php b/src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseDuplicateController.php
new file mode 100644
index 000000000..129109634
--- /dev/null
+++ b/src/Bundle/ChillDocStoreBundle/Controller/DocumentAccompanyingCourseDuplicateController.php
@@ -0,0 +1,55 @@
+security->isGranted(AccompanyingCourseDocumentVoter::SEE, $document)) {
+ throw new AccessDeniedHttpException('not allowed to see this document');
+ }
+
+ if (!$this->security->isGranted(AccompanyingCourseDocumentVoter::CREATE, $document->getCourse())) {
+ throw new AccessDeniedHttpException('not allowed to create this document');
+ }
+
+ $duplicated = $this->documentWorkflowDuplicator->duplicate($document);
+ $this->entityManager->persist($duplicated);
+ $this->entityManager->flush();
+
+ return new RedirectResponse(
+ $this->urlGenerator->generate('accompanying_course_document_edit', ['id' => $duplicated->getId(), 'course' => $duplicated->getCourse()->getId()])
+ );
+ }
+}
diff --git a/src/Bundle/ChillDocStoreBundle/Repository/AccompanyingCourseDocumentRepository.php b/src/Bundle/ChillDocStoreBundle/Repository/AccompanyingCourseDocumentRepository.php
index 7033a53c9..3590aae7f 100644
--- a/src/Bundle/ChillDocStoreBundle/Repository/AccompanyingCourseDocumentRepository.php
+++ b/src/Bundle/ChillDocStoreBundle/Repository/AccompanyingCourseDocumentRepository.php
@@ -23,7 +23,7 @@ class AccompanyingCourseDocumentRepository implements ObjectRepository, Associat
{
private readonly EntityRepository $repository;
- public function __construct(private readonly EntityManagerInterface $em)
+ public function __construct(EntityManagerInterface $em)
{
$this->repository = $em->getRepository(AccompanyingCourseDocument::class);
}
diff --git a/src/Bundle/ChillDocStoreBundle/Resources/views/List/list_item.html.twig b/src/Bundle/ChillDocStoreBundle/Resources/views/List/list_item.html.twig
index 2a3592d73..7ec761464 100644
--- a/src/Bundle/ChillDocStoreBundle/Resources/views/List/list_item.html.twig
+++ b/src/Bundle/ChillDocStoreBundle/Resources/views/List/list_item.html.twig
@@ -73,8 +73,15 @@
{{ document.object|chill_document_button_group(document.title) }}
+ {% endif %}
+ {% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_DELETE', document) %}
+
+
+
+ {% endif %}
+ {% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_CREATE', document.course) %}
-
+
{% endif %}
{% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_UPDATE', document) %}
@@ -82,9 +89,9 @@
{% endif %}
- {% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_DELETE', document) %}
-
-
+ {% if is_granted('CHILL_ACCOMPANYING_COURSE_DOCUMENT_SEE_DETAILS', document) %}
+
+
{% endif %}
{% else %}
diff --git a/src/Bundle/ChillDocStoreBundle/Service/StoredObjectDuplicate.php b/src/Bundle/ChillDocStoreBundle/Service/StoredObjectDuplicate.php
new file mode 100644
index 000000000..b1c7e7a87
--- /dev/null
+++ b/src/Bundle/ChillDocStoreBundle/Service/StoredObjectDuplicate.php
@@ -0,0 +1,47 @@
+getCurrentVersion();
+
+ $oldContent = $this->storedObjectManager->read($fromVersion);
+
+ $storedObject = new StoredObject();
+
+ $newVersion = $this->storedObjectManager->write($storedObject, $oldContent, $fromVersion->getType());
+
+ $newVersion->setCreatedFrom($fromVersion);
+
+ $this->logger->info('[StoredObjectDuplicate] Duplicated stored object from a version of a previous stored object', [
+ 'from_stored_object_uuid' => $fromVersion->getStoredObject()->getUuid(),
+ 'to_stored_object_uuid' => $storedObject->getUuid(),
+ 'old_version_id' => $fromVersion->getId(),
+ 'old_version_version' => $fromVersion->getVersion(),
+ 'new_version_id' => $newVersion->getVersion(),
+ ]);
+
+ return $storedObject;
+ }
+}
diff --git a/src/Bundle/ChillDocStoreBundle/Service/StoredObjectRestore.php b/src/Bundle/ChillDocStoreBundle/Service/StoredObjectRestore.php
index 3c6469185..bad032346 100644
--- a/src/Bundle/ChillDocStoreBundle/Service/StoredObjectRestore.php
+++ b/src/Bundle/ChillDocStoreBundle/Service/StoredObjectRestore.php
@@ -14,6 +14,9 @@ namespace Chill\DocStoreBundle\Service;
use Chill\DocStoreBundle\Entity\StoredObjectVersion;
use Psr\Log\LoggerInterface;
+/**
+ * Class responsible for restoring stored object versions into the same stored object.
+ */
final readonly class StoredObjectRestore implements StoredObjectRestoreInterface
{
public function __construct(private readonly StoredObjectManagerInterface $storedObjectManager, private readonly LoggerInterface $logger) {}
diff --git a/src/Bundle/ChillDocStoreBundle/Service/WorkflowStoredObjectPermissionHelper.php b/src/Bundle/ChillDocStoreBundle/Service/WorkflowStoredObjectPermissionHelper.php
index b27b6d96a..545325121 100644
--- a/src/Bundle/ChillDocStoreBundle/Service/WorkflowStoredObjectPermissionHelper.php
+++ b/src/Bundle/ChillDocStoreBundle/Service/WorkflowStoredObjectPermissionHelper.php
@@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\DocStoreBundle\Service;
+use Chill\MainBundle\Entity\Workflow\EntityWorkflowSignatureStateEnum;
use Chill\MainBundle\Workflow\EntityWorkflowManager;
use Symfony\Component\Security\Core\Security;
@@ -31,6 +32,16 @@ class WorkflowStoredObjectPermissionHelper
if (!$workflow->getCurrentStep()->getAllDestUser()->contains($currentUser)) {
return false;
}
+
+ // as soon as there is one signatured applyied, we are not able to
+ // edit the document any more
+ foreach ($workflow->getSteps() as $step) {
+ foreach ($step->getSignatures() as $signature) {
+ if (EntityWorkflowSignatureStateEnum::SIGNED === $signature->getState()) {
+ return false;
+ }
+ }
+ }
}
return true;
diff --git a/src/Bundle/ChillDocStoreBundle/Tests/Service/StoredObjectDuplicateTest.php b/src/Bundle/ChillDocStoreBundle/Tests/Service/StoredObjectDuplicateTest.php
new file mode 100644
index 000000000..2e9da0bab
--- /dev/null
+++ b/src/Bundle/ChillDocStoreBundle/Tests/Service/StoredObjectDuplicateTest.php
@@ -0,0 +1,48 @@
+registerVersion(type: $type = 'application/test');
+
+ $manager = $this->createMock(StoredObjectManagerInterface::class);
+ $manager->method('read')->with($version)->willReturn('1234');
+ $manager
+ ->expects($this->once())
+ ->method('write')
+ ->with($this->isInstanceOf(StoredObject::class), '1234', 'application/test')
+ ->willReturnCallback(fn (StoredObject $so, $content, $type) => $so->registerVersion(type: $type));
+
+ $storedObjectDuplicate = new StoredObjectDuplicate($manager, new NullLogger());
+
+ $actual = $storedObjectDuplicate->duplicate($storedObject);
+
+ self::assertNotNull($actual->getCurrentVersion());
+ self::assertNotNull($actual->getCurrentVersion()->getCreatedFrom());
+ self::assertSame($version, $actual->getCurrentVersion()->getCreatedFrom());
+ }
+}
diff --git a/src/Bundle/ChillDocStoreBundle/Tests/Service/WorkflowStoredObjectPermissionHelperTest.php b/src/Bundle/ChillDocStoreBundle/Tests/Service/WorkflowStoredObjectPermissionHelperTest.php
new file mode 100644
index 000000000..e87ea4653
--- /dev/null
+++ b/src/Bundle/ChillDocStoreBundle/Tests/Service/WorkflowStoredObjectPermissionHelperTest.php
@@ -0,0 +1,101 @@
+buildHelper($object, $entityWorkflow, $user);
+
+ self::assertEquals($expected, $helper->notBlockedByWorkflow($entityWorkflow), $message);
+ }
+
+ private function buildHelper(object $relatedEntity, EntityWorkflow $entityWorkflow, User $user): WorkflowStoredObjectPermissionHelper
+ {
+ $security = $this->prophesize(Security::class);
+ $security->getUser()->willReturn($user);
+
+ $entityWorkflowManager = $this->prophesize(EntityWorkflowManager::class);
+ $entityWorkflowManager->findByRelatedEntity(Argument::type('object'))->willReturn([$entityWorkflow]);
+
+ return new WorkflowStoredObjectPermissionHelper($security->reveal(), $entityWorkflowManager->reveal());
+ }
+
+ public static function provideDataNotBlockByWorkflow(): iterable
+ {
+ $entityWorkflow = new EntityWorkflow();
+ $dto = new WorkflowTransitionContextDTO($entityWorkflow);
+ $entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable());
+
+ yield [$entityWorkflow, new User(), false, 'blocked because the user is not present as a dest user'];
+
+ $entityWorkflow = new EntityWorkflow();
+ $dto = new WorkflowTransitionContextDTO($entityWorkflow);
+ $dto->futureDestUsers[] = $user = new User();
+ $entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable(), $user);
+
+ yield [$entityWorkflow, $user, true, 'allowed because the user is present as a dest user'];
+
+ $entityWorkflow = new EntityWorkflow();
+ $dto = new WorkflowTransitionContextDTO($entityWorkflow);
+ $dto->futureDestUsers[] = $user = new User();
+ $entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable(), $user);
+ $entityWorkflow->getCurrentStep()->setIsFinal(true);
+
+ yield [$entityWorkflow, $user, false, 'blocked because the step is final'];
+
+ $entityWorkflow = new EntityWorkflow();
+ $dto = new WorkflowTransitionContextDTO($entityWorkflow);
+ $dto->futureDestUsers[] = $user = new User();
+ $entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable(), $user);
+ $step = $entityWorkflow->getCurrentStep();
+ new EntityWorkflowStepSignature($step, new Person());
+
+ yield [$entityWorkflow, $user, true, 'allow, a signature is present but still pending'];
+
+ $entityWorkflow = new EntityWorkflow();
+ $dto = new WorkflowTransitionContextDTO($entityWorkflow);
+ $dto->futureDestUsers[] = $user = new User();
+ $entityWorkflow->setStep('test', $dto, 'to_test', new \DateTimeImmutable(), $user);
+ $step = $entityWorkflow->getCurrentStep();
+ $signature = new EntityWorkflowStepSignature($step, new Person());
+ $signature->setState(EntityWorkflowSignatureStateEnum::SIGNED);
+
+ yield [$entityWorkflow, $user, false, 'blocked, a signature is present and signed'];
+
+ }
+}
diff --git a/src/Bundle/ChillDocStoreBundle/Tests/Workflow/AccompanyingCourseDocumentDuplicatorTest.php b/src/Bundle/ChillDocStoreBundle/Tests/Workflow/AccompanyingCourseDocumentDuplicatorTest.php
new file mode 100644
index 000000000..71df75d20
--- /dev/null
+++ b/src/Bundle/ChillDocStoreBundle/Tests/Workflow/AccompanyingCourseDocumentDuplicatorTest.php
@@ -0,0 +1,70 @@
+setDate($date = new \DateTimeImmutable())
+ ->setObject($object)
+ ->setTitle('Title')
+ ->setUser($user = new User())
+ ->setCategory($category = new DocumentCategory('bundle', 10))
+ ->setDescription($description = 'Description');
+
+ $actual = $this->buildDuplicator()->duplicate($document);
+
+ self::assertSame($date, $actual->getDate());
+ // FYI, the duplication of object is checked by the mock
+ self::assertNotNull($actual->getObject());
+ self::assertStringStartsWith('Title', $actual->getTitle());
+ self::assertSame($user, $actual->getUser());
+ self::assertSame($category, $actual->getCategory());
+ self::assertEquals($description, $actual->getDescription());
+ }
+
+ private function buildDuplicator(): AccompanyingCourseDocumentDuplicator
+ {
+ $storedObjectDuplicate = $this->createMock(StoredObjectDuplicate::class);
+ $storedObjectDuplicate->expects($this->once())->method('duplicate')
+ ->with($this->isInstanceOf(StoredObject::class))->willReturn(new StoredObject());
+ $translator = $this->createMock(TranslatorInterface::class);
+ $translator->method('trans')->withAnyParameters()->willReturn('duplicated');
+ $clock = new MockClock();
+
+ return new AccompanyingCourseDocumentDuplicator(
+ $storedObjectDuplicate,
+ $translator,
+ $clock
+ );
+ }
+}
diff --git a/src/Bundle/ChillDocStoreBundle/Workflow/AccompanyingCourseDocumentDuplicator.php b/src/Bundle/ChillDocStoreBundle/Workflow/AccompanyingCourseDocumentDuplicator.php
new file mode 100644
index 000000000..22ee65cc3
--- /dev/null
+++ b/src/Bundle/ChillDocStoreBundle/Workflow/AccompanyingCourseDocumentDuplicator.php
@@ -0,0 +1,45 @@
+setCourse($document->getCourse())
+ ->setTitle($document->getTitle().' ('.$this->translator->trans('acc_course_document.duplicated_at', ['at' => $this->clock->now()]).')')
+ ->setDate($document->getDate())
+ ->setDescription($document->getDescription())
+ ->setCategory($document->getCategory())
+ ->setUser($document->getUser())
+ ->setObject($this->storedObjectDuplicate->duplicate($document->getObject()))
+ ;
+
+ return $newDoc;
+ }
+}
diff --git a/src/Bundle/ChillDocStoreBundle/translations/messages+intl-icu.fr.yml b/src/Bundle/ChillDocStoreBundle/translations/messages+intl-icu.fr.yml
new file mode 100644
index 000000000..0132cdc4f
--- /dev/null
+++ b/src/Bundle/ChillDocStoreBundle/translations/messages+intl-icu.fr.yml
@@ -0,0 +1,3 @@
+acc_course_document:
+ duplicated_at: >-
+ Dupliqué le {at, date, long} à {at, time, short}
diff --git a/src/Bundle/ChillMainBundle/Resources/public/lib/entity-workflow/api.js b/src/Bundle/ChillMainBundle/Resources/public/lib/entity-workflow/api.ts
similarity index 52%
rename from src/Bundle/ChillMainBundle/Resources/public/lib/entity-workflow/api.js
rename to src/Bundle/ChillMainBundle/Resources/public/lib/entity-workflow/api.ts
index a89dd66f5..486421904 100644
--- a/src/Bundle/ChillMainBundle/Resources/public/lib/entity-workflow/api.js
+++ b/src/Bundle/ChillMainBundle/Resources/public/lib/entity-workflow/api.ts
@@ -1,12 +1,8 @@
-const buildLinkCreate = function(workflowName, relatedEntityClass, relatedEntityId) {
+export const buildLinkCreate = (workflowName: string, relatedEntityClass: string, relatedEntityId: number): string => {
let params = new URLSearchParams();
params.set('entityClass', relatedEntityClass);
- params.set('entityId', relatedEntityId);
+ params.set('entityId', relatedEntityId.toString(10));
params.set('workflow', workflowName);
return `/fr/main/workflow/create?`+params.toString();
};
-
-export {
- buildLinkCreate,
-};
diff --git a/src/Bundle/ChillMainBundle/Resources/public/types.ts b/src/Bundle/ChillMainBundle/Resources/public/types.ts
index 2e33b8248..304ebd8e4 100644
--- a/src/Bundle/ChillMainBundle/Resources/public/types.ts
+++ b/src/Bundle/ChillMainBundle/Resources/public/types.ts
@@ -168,3 +168,8 @@ export interface NewsItemType {
startDate: DateTime;
endDate: DateTime | null;
}
+
+export interface WorkflowAvailable {
+ name: string;
+ text: string;
+}
diff --git a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/PickWorkflow.vue b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/PickWorkflow.vue
index 9ed1ef6cc..e429adf31 100644
--- a/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/PickWorkflow.vue
+++ b/src/Bundle/ChillMainBundle/Resources/public/vuejs/_components/EntityWorkflow/PickWorkflow.vue
@@ -1,63 +1,52 @@
-
+
-
diff --git a/src/Bundle/ChillMainBundle/Workflow/Templating/WorkflowTwigExtensionRuntime.php b/src/Bundle/ChillMainBundle/Workflow/Templating/WorkflowTwigExtensionRuntime.php
index f2b7d80db..332ccd2e5 100644
--- a/src/Bundle/ChillMainBundle/Workflow/Templating/WorkflowTwigExtensionRuntime.php
+++ b/src/Bundle/ChillMainBundle/Workflow/Templating/WorkflowTwigExtensionRuntime.php
@@ -13,7 +13,6 @@ namespace Chill\MainBundle\Workflow\Templating;
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
-use Chill\MainBundle\Workflow\EntityWorkflowManager;
use Chill\MainBundle\Workflow\Helper\MetadataExtractor;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Workflow\Registry;
@@ -23,7 +22,7 @@ use Twig\Extension\RuntimeExtensionInterface;
class WorkflowTwigExtensionRuntime implements RuntimeExtensionInterface
{
- public function __construct(private readonly EntityWorkflowManager $entityWorkflowManager, private readonly Registry $registry, private readonly EntityWorkflowRepository $repository, private readonly MetadataExtractor $metadataExtractor, private readonly NormalizerInterface $normalizer) {}
+ public function __construct(private readonly Registry $registry, private readonly EntityWorkflowRepository $repository, private readonly MetadataExtractor $metadataExtractor, private readonly NormalizerInterface $normalizer) {}
public function getTransitionByString(EntityWorkflow $entityWorkflow, string $key): ?Transition
{
diff --git a/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkEvaluationDocumentDuplicateController.php b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkEvaluationDocumentDuplicateController.php
new file mode 100644
index 000000000..ec48b5b24
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Controller/AccompanyingPeriodWorkEvaluationDocumentDuplicateController.php
@@ -0,0 +1,55 @@
+getAccompanyingPeriodWorkEvaluation()->getAccompanyingPeriodWork();
+
+ if (!$this->security->isGranted(AccompanyingPeriodWorkVoter::UPDATE, $work)) {
+ throw new AccessDeniedHttpException('not allowed to edit this accompanying period work');
+ }
+
+ $duplicatedDocument = $this->duplicator->duplicate($document);
+
+ $this->entityManager->persist($duplicatedDocument);
+ $this->entityManager->persist($duplicatedDocument->getStoredObject());
+ $this->entityManager->flush();
+
+ return new JsonResponse(
+ $this->serializer->serialize($duplicatedDocument, 'json', [AbstractNormalizer::GROUPS => ['read']]),
+ json: true
+ );
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/Resources/public/types.ts b/src/Bundle/ChillPersonBundle/Resources/public/types.ts
index 755c23e2d..aae801fc3 100644
--- a/src/Bundle/ChillPersonBundle/Resources/public/types.ts
+++ b/src/Bundle/ChillPersonBundle/Resources/public/types.ts
@@ -1,4 +1,12 @@
-import {Address, Center, Civility, DateTime} from "../../../ChillMainBundle/Resources/public/types";
+import {
+ Address,
+ Center,
+ Civility,
+ DateTime,
+ User,
+ WorkflowAvailable
+} from "../../../ChillMainBundle/Resources/public/types";
+import {StoredObject} from "../../../ChillDocStoreBundle/Resources/public/types";
export interface Person {
id: number;
@@ -20,3 +28,16 @@ export interface Person {
current_household_id: number;
current_residential_addresses: Address[];
}
+
+export interface AccompanyingPeriodWorkEvaluationDocument {
+ id: number;
+ type: "accompanying_period_work_evaluation_document"
+ storedObject: StoredObject;
+ title: string;
+ createdAt: DateTime | null;
+ createdBy: User | null;
+ updatedAt: DateTime | null;
+ updatedBy: User | null;
+ workflows_availables: WorkflowAvailable[];
+ workflows: object[];
+}
diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/App.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/App.vue
index c0f5178fd..d0b4affbf 100644
--- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/App.vue
+++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/App.vue
@@ -342,7 +342,7 @@ import OnTheFly from 'ChillMainAssets/vuejs/OnTheFly/components/OnTheFly.vue';
import ListWorkflowModal from 'ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue';
import PickWorkflow from 'ChillMainAssets/vuejs/_components/EntityWorkflow/PickWorkflow.vue';
import PersonText from 'ChillPersonAssets/vuejs/_components/Entity/PersonText.vue';
-import {buildLinkCreate} from 'ChillMainAssets/lib/entity-workflow/api.js';
+import {buildLinkCreate} from 'ChillMainAssets/lib/entity-workflow/api';
import { makeFetch } from 'ChillMainAssets/lib/api/apiMethods';
const i18n = {
diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/components/AddEvaluation.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/components/AddEvaluation.vue
index baa3fa798..6c2c7f58d 100644
--- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/components/AddEvaluation.vue
+++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/components/AddEvaluation.vue
@@ -54,7 +54,7 @@
import FormEvaluation from './FormEvaluation.vue';
import Modal from 'ChillMainAssets/vuejs/_components/Modal';
import ListWorkflowModal from 'ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue';
-import {buildLinkCreate} from 'ChillMainAssets/lib/entity-workflow/api.js';
+import {buildLinkCreate} from 'ChillMainAssets/lib/entity-workflow/api';
const i18n = {
messages: {
diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/components/FormEvaluation.vue b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/components/FormEvaluation.vue
index 2f02333b1..dbc53c4e8 100644
--- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/components/FormEvaluation.vue
+++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/components/FormEvaluation.vue
@@ -147,6 +147,9 @@
+
+
+
@@ -189,7 +192,7 @@ import { mapGetters, mapState } from 'vuex';
import PickTemplate from 'ChillDocGeneratorAssets/vuejs/_components/PickTemplate.vue';
import {buildLink} from 'ChillDocGeneratorAssets/lib/document-generator';
import ListWorkflowModal from 'ChillMainAssets/vuejs/_components/EntityWorkflow/ListWorkflowModal.vue';
-import {buildLinkCreate} from 'ChillMainAssets/lib/entity-workflow/api.js';
+import {buildLinkCreate} from 'ChillMainAssets/lib/entity-workflow/api';
import {buildLinkCreate as buildLinkCreateNotification} from 'ChillMainAssets/lib/entity-notification/api';
import DocumentActionButtonsGroup from "ChillDocStoreAssets/vuejs/DocumentActionButtonsGroup.vue";
import DropFileModal from "ChillDocStoreAssets/vuejs/DropFileWidget/DropFileModal.vue";
@@ -396,6 +399,9 @@ export default {
this.$store.commit('removeDocument', {key: this.evaluation.key, document: document});
}
},
+ duplicateDocument(document) {
+ this.$store.dispatch('duplicateDocument', {evaluation_key: this.evaluation.key, document: document});
+ },
onStatusDocumentChanged(newStatus) {
console.log('onStatusDocumentChanged', newStatus);
this.$store.commit('statusDocumentChanged', {key: this.evaluation.key, newStatus: newStatus});
diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/store.js b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/store.js
index 236c77140..4279aa366 100644
--- a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/store.js
+++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/AccompanyingCourseWorkEdit/store.js
@@ -4,6 +4,7 @@ import { findSocialActionsBySocialIssue } from 'ChillPersonAssets/vuejs/_api/Soc
import { create } from 'ChillPersonAssets/vuejs/_api/AccompanyingCourseWork.js';
import { fetchResults, makeFetch } from 'ChillMainAssets/lib/api/apiMethods.ts';
import { fetchTemplates } from 'ChillDocGeneratorAssets/api/pickTemplate.js';
+import { duplicate } from '../_api/accompanyingCourseWorkEvaluationDocument';
const debug = process.env.NODE_ENV !== 'production';
const evalFQDN = encodeURIComponent("Chill\\PersonBundle\\Entity\\AccompanyingPeriod\\AccompanyingPeriodWorkEvaluation");
@@ -238,6 +239,14 @@ const store = createStore({
}
evaluation.documents = evaluation.documents.filter(d => d.key !== document.key);
},
+ addDuplicatedDocument(state, {document, evaluation_key}) {
+ console.log('add duplicated document', document);
+ console.log('add duplicated dcuemnt - evaluation key', evaluation_key);
+
+ let evaluation = state.evaluationsPicked.find(e => e.key === evaluation_key);
+ document.key = evaluation.documents.length + 1;
+ evaluation.documents.splice(0, 0, document);
+ },
/**
* Replaces a document in the state with a new document.
*
@@ -506,6 +515,10 @@ const store = createStore({
addDocument({commit}, payload) {
commit('addDocument', payload);
},
+ async duplicateDocument({commit}, {document, evaluation_key}) {
+ const newDoc = await duplicate(document.id);
+ commit('addDuplicatedDocument', {document: newDoc, evaluation_key});
+ },
removeDocument({commit}, payload) {
commit('removeDocument', payload);
},
diff --git a/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_api/accompanyingCourseWorkEvaluationDocument.ts b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_api/accompanyingCourseWorkEvaluationDocument.ts
new file mode 100644
index 000000000..a7c03e5ea
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Resources/public/vuejs/_api/accompanyingCourseWorkEvaluationDocument.ts
@@ -0,0 +1,6 @@
+import {AccompanyingPeriodWorkEvaluationDocument} from "../../types";
+import {makeFetch} from "../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
+
+export const duplicate = async (id: number): Promise => {
+ return makeFetch("POST", `/api/1.0/person/accompanying-course-work-evaluation-document/${id}/duplicate`);
+}
diff --git a/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriodWorkEvaluationDocument/AccompanyingPeriodWorkEvaluationDocumentDuplicator.php b/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriodWorkEvaluationDocument/AccompanyingPeriodWorkEvaluationDocumentDuplicator.php
new file mode 100644
index 000000000..5ca37aa71
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Service/AccompanyingPeriodWorkEvaluationDocument/AccompanyingPeriodWorkEvaluationDocumentDuplicator.php
@@ -0,0 +1,39 @@
+setTitle($document->getTitle().' ('.$this->translator->trans('accompanying_course_evaluation_document.duplicated_at', ['at' => $this->clock->now()]).')')
+ ->setStoredObject($this->storedObjectDuplicate->duplicate($document->getStoredObject()))
+ ;
+
+ $document->getAccompanyingPeriodWorkEvaluation()->addDocument($newDocument);
+
+ return $newDocument;
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/Tests/Service/AccompanyingPeriodWorkEvaluationDocument/AccompanyingPeriodWorkEvaluationDocumentDuplicatorTest.php b/src/Bundle/ChillPersonBundle/Tests/Service/AccompanyingPeriodWorkEvaluationDocument/AccompanyingPeriodWorkEvaluationDocumentDuplicatorTest.php
new file mode 100644
index 000000000..e24caef63
--- /dev/null
+++ b/src/Bundle/ChillPersonBundle/Tests/Service/AccompanyingPeriodWorkEvaluationDocument/AccompanyingPeriodWorkEvaluationDocumentDuplicatorTest.php
@@ -0,0 +1,57 @@
+setStoredObject($storedObject)
+ ->setTitle('test title')
+ ->setAccompanyingPeriodWorkEvaluation($evaluation);
+
+ $storedObjectDuplicator = $this->createMock(StoredObjectDuplicate::class);
+ $storedObjectDuplicator->expects($this->once())->method('duplicate')->with($storedObject)->willReturn($newStoredObject = new StoredObject());
+
+ $translator = $this->createMock(TranslatorInterface::class);
+ $translator->method('trans')->willReturn('test translated');
+
+ $clock = new MockClock();
+
+ $duplicator = new AccompanyingPeriodWorkEvaluationDocumentDuplicator($storedObjectDuplicator, $translator, $clock);
+
+ $actual = $duplicator->duplicate($document);
+
+ self::assertNotSame($document, $actual);
+ self::assertStringStartsWith('test title', $actual->getTitle());
+ self::assertSame($newStoredObject, $actual->getStoredObject());
+ self::assertSame($evaluation, $actual->getAccompanyingPeriodWorkEvaluation());
+ }
+}
diff --git a/src/Bundle/ChillPersonBundle/chill.api.specs.yaml b/src/Bundle/ChillPersonBundle/chill.api.specs.yaml
index 72a4b78e3..45cccf958 100644
--- a/src/Bundle/ChillPersonBundle/chill.api.specs.yaml
+++ b/src/Bundle/ChillPersonBundle/chill.api.specs.yaml
@@ -1948,3 +1948,25 @@ paths:
responses:
200:
description: "OK"
+
+ /1.0/person/accompanying-course-work-evaluation-document/{id}/duplicate:
+ post:
+ tags:
+ - accompanying-course-work-evaluation-document
+ summary: Dupliate an an accompanying period work evaluation document
+ parameters:
+ - in: path
+ name: id
+ required: true
+ description: The document's id
+ schema:
+ type: integer
+ format: integer
+ minimum: 1
+ responses:
+ 200:
+ description: "OK"
+ content:
+ application/json:
+ schema:
+ type: object
diff --git a/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml b/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml
index 9b2edf573..3ea21e06d 100644
--- a/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml
+++ b/src/Bundle/ChillPersonBundle/translations/messages+intl-icu.fr.yaml
@@ -163,8 +163,8 @@ exports:
{ total, plural,
=0 {Aucun usager ne correspond aux termes de recherche}
one {Un usager correspond aux termes de recherche}
- many {# usagers correspondent aux terms de recherche}
- other {# usagers correspondent aux terms de recherche}
+ many {# usagers correspondent aux termes de recherche}
+ other {# usagers correspondent aux termes de recherche}
}
'nb person with similar name. Please verify that this is a new person': >-
@@ -173,3 +173,7 @@ exports:
one {Un usager a un nom similaire. Vérifiez qu'il ne s'agit pas de lui.}
other {# usagers ont un nom similaire. Vérifiez qu'il ne s'agit pas de l'un d'eux}
}
+
+accompanying_course_evaluation_document:
+ duplicated_at: >-
+ Dupliqué le {at, date, long} à {at, time, short}