Duplicate and accompanying course evaluation document

- create a service which duplicate the accompanying course work evaluation document
- create a controller to duplicate this document
- update the vuejs component to use this duplicate action
This commit is contained in:
Julien Fastré 2024-09-23 16:32:47 +02:00
parent ce80207d98
commit 611a968162
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
12 changed files with 228 additions and 11 deletions

View File

@ -19,8 +19,6 @@ use Chill\DocStoreBundle\Workflow\AccompanyingCourseDocumentDuplicator;
use Chill\MainBundle\Entity\User;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Clock\MockClock;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Contracts\Translation\TranslatorInterface;
/**

View File

@ -12,11 +12,8 @@ declare(strict_types=1);
namespace Chill\DocStoreBundle\Workflow;
use Chill\DocStoreBundle\Entity\AccompanyingCourseDocument;
use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter;
use Chill\DocStoreBundle\Service\StoredObjectDuplicate;
use Symfony\Component\Clock\ClockInterface;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Security;
use Symfony\Contracts\Translation\TranslatorInterface;
/**

View File

@ -17,7 +17,6 @@ use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Security\Authorization\AccompanyingCourseDocumentVoter;
use Chill\MainBundle\Entity\Workflow\EntityWorkflow;
use Chill\MainBundle\Repository\Workflow\EntityWorkflowRepository;
use Chill\MainBundle\Workflow\EntityWorkflowWithDuplicableRelatedEntityInterface;
use Chill\MainBundle\Workflow\EntityWorkflowWithStoredObjectHandlerInterface;
use Chill\PersonBundle\Entity\AccompanyingPeriodParticipation;
use Symfony\Contracts\Translation\TranslatorInterface;
@ -28,8 +27,8 @@ use Symfony\Contracts\Translation\TranslatorInterface;
readonly class AccompanyingCourseDocumentWorkflowHandler implements EntityWorkflowWithStoredObjectHandlerInterface
{
public function __construct(
private TranslatorInterface $translator,
private EntityWorkflowRepository $workflowRepository,
private TranslatorInterface $translator,
private EntityWorkflowRepository $workflowRepository,
private AccompanyingCourseDocumentRepository $repository,
) {}

View File

@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Controller;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument;
use Chill\PersonBundle\Security\Authorization\AccompanyingPeriodWorkVoter;
use Chill\PersonBundle\Service\AccompanyingPeriodWorkEvaluationDocument\AccompanyingPeriodWorkEvaluationDocumentDuplicator;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\SerializerInterface;
class AccompanyingPeriodWorkEvaluationDocumentDuplicateController
{
public function __construct(
private readonly AccompanyingPeriodWorkEvaluationDocumentDuplicator $duplicator,
private readonly Security $security,
private readonly SerializerInterface $serializer,
private readonly EntityManagerInterface $entityManager,
) {}
#[Route('/api/1.0/person/accompanying-course-work-evaluation-document/{id}/duplicate', methods: ['POST'])]
public function __invoke(AccompanyingPeriodWorkEvaluationDocument $document): Response
{
$work = $document->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
);
}
}

View File

@ -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[];
}

View File

@ -147,6 +147,9 @@
<a class="btn btn-delete" @click="removeDocument(d)">
</a>
</li>
<li v-if="Number.isInteger(d.id)">
<button type="button" @click="duplicateDocument(d)" class="btn btn-duplicate" title="Dupliquer"></button>
</li>
</ul>
</div>
</div>
@ -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});

View File

@ -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);
},

View File

@ -0,0 +1,6 @@
import {AccompanyingPeriodWorkEvaluationDocument} from "../../types";
import {makeFetch} from "../../../../../ChillMainBundle/Resources/public/lib/api/apiMethods";
export const duplicate = async (id: number): Promise<AccompanyingPeriodWorkEvaluationDocument> => {
return makeFetch<null, AccompanyingPeriodWorkEvaluationDocument>("POST", `/api/1.0/person/accompanying-course-work-evaluation-document/${id}/duplicate`);
}

View File

@ -0,0 +1,39 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Service\AccompanyingPeriodWorkEvaluationDocument;
use Chill\DocStoreBundle\Service\StoredObjectDuplicate;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument;
use Symfony\Component\Clock\ClockInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class AccompanyingPeriodWorkEvaluationDocumentDuplicator
{
public function __construct(
private readonly StoredObjectDuplicate $storedObjectDuplicate,
private readonly TranslatorInterface $translator,
private readonly ClockInterface $clock,
) {}
public function duplicate(AccompanyingPeriodWorkEvaluationDocument $document): AccompanyingPeriodWorkEvaluationDocument
{
$newDocument = new AccompanyingPeriodWorkEvaluationDocument();
$newDocument
->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;
}
}

View File

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Tests\Service\AccompanyingPeriodWorkEvaluationDocument;
use Chill\DocStoreBundle\Entity\StoredObject;
use Chill\DocStoreBundle\Service\StoredObjectDuplicate;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluation;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWorkEvaluationDocument;
use Chill\PersonBundle\Service\AccompanyingPeriodWorkEvaluationDocument\AccompanyingPeriodWorkEvaluationDocumentDuplicator;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Clock\MockClock;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* @internal
*
* @coversNothing
*/
class AccompanyingPeriodWorkEvaluationDocumentDuplicatorTest extends TestCase
{
public function testDuplicate()
{
$storedObject = new StoredObject();
$evaluation = new AccompanyingPeriodWorkEvaluation();
$document = new AccompanyingPeriodWorkEvaluationDocument();
$document
->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());
}
}

View File

@ -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

View File

@ -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}