Merge branch 'signature-app-master' into 'master'

Signature app master

Closes #307

See merge request Chill-Projet/chill-bundles!743
This commit is contained in:
2024-11-12 20:30:00 +00:00
426 changed files with 22236 additions and 2253 deletions

View File

@@ -3,8 +3,10 @@
*/
span.badge-user,
span.badge-user-group,
span.badge-person,
span.badge-thirdparty {
margin: 0.2rem 0.1rem;
display: inline-block;
padding: 0 0.5em !important;
background-color: $white;
@@ -18,6 +20,11 @@ span.badge-thirdparty {
}
}
span.badge-user-group {
font-weight: 600;
border-width: 0px;
}
span.badge-user {
border-bottom-width: 1px;
&.system {
@@ -231,6 +238,10 @@ div[class*='budget-'] {
background-color: $chill-ll-gray;
color: $chill-blue;
}
&.bg-user-group {
background-color: $chill-l-gray;
color: $chill-blue;
}
&.bg-confidential {
background-color: $chill-ll-gray;
color: $chill-red;

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

@@ -340,9 +340,8 @@ import ThirdPartyRenderBox from 'ChillThirdPartyAssets/vuejs/_components/Entity/
import PickTemplate from 'ChillDocGeneratorAssets/vuejs/_components/PickTemplate.vue';
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 = {
@@ -406,7 +405,6 @@ export default {
PickTemplate,
ListWorkflowModal,
OnTheFly,
PickWorkflow,
PersonText,
},
i18n,

View File

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

View File

@@ -103,7 +103,7 @@
<div class="item-row">
<div class="item-col">
<ul class="record_actions">
<li v-if="d.workflows_availables.length > 0">
<li v-if="d.workflows_availables.length > 0 || d.workflows.length > 0">
<list-workflow-modal
:workflows="d.workflows"
:allowCreate="true"
@@ -140,19 +140,16 @@
@on-stored-object-status-change="onStatusDocumentChanged"
></document-action-buttons-group>
</li>
<li>
<add-async-upload
:buttonTitle="$t('replace')"
:options="asyncUploadOptions"
:btnClasses="{'btn': true, 'btn-edit': true}"
@addDocument="(arg) => replaceDocument(d, arg)"
>
</add-async-upload>
<li v-if="d.storedObject._permissions.canEdit">
<drop-file-modal :existing-doc="d.storedObject" :allow-remove="false" @add-document="(arg) => replaceDocument(d, arg.stored_object, arg.stored_object_version)"></drop-file-modal>
</li>
<li v-if="d.workflows.length === 0">
<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>
@@ -177,12 +174,7 @@
<label class="col-form-label">{{ $t('document_upload') }}</label>
<ul class="record_actions document-upload">
<li>
<add-async-upload
:buttonTitle="$t('browse')"
:options="asyncUploadOptions"
@addDocument="addDocument"
>
</add-async-upload>
<drop-file-modal :allow-remove="false" @add-document="addDocument"></drop-file-modal>
</li>
</ul>
</div>
@@ -199,12 +191,11 @@ import ClassicEditor from 'ChillMainAssets/module/ckeditor5/editor_config';
import { mapGetters, mapState } from 'vuex';
import PickTemplate from 'ChillDocGeneratorAssets/vuejs/_components/PickTemplate.vue';
import {buildLink} from 'ChillDocGeneratorAssets/lib/document-generator';
import AddAsyncUpload from 'ChillDocStoreAssets/vuejs/_components/AddAsyncUpload.vue';
import AddAsyncUploadDownloader from 'ChillDocStoreAssets/vuejs/_components/AddAsyncUploadDownloader.vue';
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";
const i18n = {
messages: {
@@ -243,10 +234,9 @@ export default {
name: "FormEvaluation",
props: ['evaluation', 'docAnchorId'],
components: {
DropFileModal,
ckeditor: CKEditor.component,
PickTemplate,
AddAsyncUpload,
AddAsyncUploadDownloader,
ListWorkflowModal,
DocumentActionButtonsGroup,
},
@@ -380,27 +370,38 @@ export default {
const title = event.target.value;
this.$store.commit('updateDocumentTitle', {id: id, key: key, evaluationKey: this.evaluation.key, title: title});
},
addDocument(storedObject) {
addDocument({stored_object, stored_object_version}) {
let document = {
type: 'accompanying_period_work_evaluation_document',
storedObject: storedObject,
storedObject: stored_object,
title: 'Nouveau document',
};
this.$store.commit('addDocument', {key: this.evaluation.key, document: document});
this.$store.commit('addDocument', {key: this.evaluation.key, document, stored_object_version});
},
replaceDocument(oldDocument, storedObject) {
/**
* Replaces a document in the store with a new document.
*
* @param {Object} oldDocument - The document to be replaced.
* @param {StoredObject} storedObject - The stored object of the new document.
* @param {StoredObjectVersion} storedObjectVersion - The new version of the document
* @return {void}
*/
replaceDocument(oldDocument, storedObject, storedObjectVersion) {
let document = {
type: 'accompanying_period_work_evaluation_document',
storedObject: storedObject,
title: oldDocument.title
};
this.$store.commit('replaceDocument', {key: this.evaluation.key, document: document, oldDocument: oldDocument});
this.$store.commit('replaceDocument', {key: this.evaluation.key, document, oldDocument: oldDocument, stored_object_version: storedObjectVersion});
},
removeDocument(document) {
if (window.confirm("Êtes-vous sûr·e de vouloir supprimer le document qui a pour titre \"" + document.title +"\" ?")) {
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");
@@ -219,7 +220,11 @@ const store = createStore({
found.results = found.results.filter(r => r.id !== result.id);
},
addDocument(state, payload) {
// associate version to stored object
payload.document.storedObject.currentVersion = payload.stored_object_version;
let evaluation = state.evaluationsPicked.find(e => e.key === payload.key);
evaluation.documents.push(Object.assign(
payload.document, {
key: evaluation.documents.length + 1,
@@ -234,6 +239,21 @@ 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.
*
* @param {object} state - The current state of the application.
* @param {{key: number, oldDocument: {key: number}, stored_object_version: StoredObjectVersion}} payload - The object containing the information about the document to be replaced.
* @return {void} - returns nothing.
*/
replaceDocument(state, payload) {
let evaluation = state.evaluationsPicked.find(e => e.key === payload.key);
if (evaluation === undefined) {
@@ -244,9 +264,10 @@ const store = createStore({
if (typeof doc === 'undefined') {
console.error('doc not found');
return;
}
doc.storedObject = payload.document.storedObject;
doc.storedObject.currentVersion = payload.stored_object_version;
return;
let newDocument = Object.assign(
payload.document, {
@@ -494,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

@@ -27,6 +27,11 @@
v-bind:item="item">
</suggestion-user>
<suggestion-user-group
v-if="item.result.type === 'user_group'"
v-bind:item="item">
></suggestion-user-group>
<suggestion-household
v-if="item.result.type === 'household'"
v-bind:item="item">
@@ -41,6 +46,7 @@ import SuggestionPerson from './TypePerson';
import SuggestionThirdParty from './TypeThirdParty';
import SuggestionUser from './TypeUser';
import SuggestionHousehold from './TypeHousehold';
import SuggestionUserGroup from './TypeUserGroup';
export default {
name: 'PersonSuggestion',
@@ -49,6 +55,7 @@ export default {
SuggestionThirdParty,
SuggestionUser,
SuggestionHousehold,
SuggestionUserGroup,
},
props: [
'item',

View File

@@ -0,0 +1,30 @@
<script setup lang="ts">
import {ResultItem, UserGroup} from "../../../../../../ChillMainBundle/Resources/public/types";
import BadgeEntity from "ChillMainAssets/vuejs/_components/BadgeEntity.vue";
import UserRenderBoxBadge from "ChillMainAssets/vuejs/_components/Entity/UserRenderBoxBadge.vue";
import UserGroupRenderBox from "ChillMainAssets/vuejs/_components/Entity/UserGroupRenderBox.vue";
interface TypeUserGroupProps {
item: ResultItem<UserGroup>;
}
const props = defineProps<TypeUserGroupProps>();
</script>
<template>
<div class="container user-group-container">
<div class="user-group-identification">
<user-group-render-box :user-group="props.item.result"></user-group-render-box>
</div>
</div>
<div class="right_actions">
<span class="badge rounded-pill bg-user-group">
Groupe d'utilisateur
</span>
</div>
</template>
<style scoped lang="scss">
</style>

View File

@@ -211,7 +211,7 @@
<h3 class="chill-beige">Public</h3>
{% if w.note is not empty %}
<blockquote class="chill-user-quote">
{{ w.note|chill_entity_render_box({'metadata': true }) }}
{{ w.note }}
</blockquote>
{% else %}
<span class="chill-no-data-statement">{{ 'No comment associated'|trans }}</span>

View File

@@ -237,8 +237,7 @@
{% if displayContent is defined and displayContent == 'long' %}
{% if e.comment is not empty %}
<blockquote
class="chill-user-quote">{{ e.comment|chill_entity_render_box }}</blockquote>
<blockquote class="chill-user-quote">{{ e.comment }}</blockquote>
{% endif %}
{% import "@ChillDocStore/Macro/macro.html.twig" as m %}

View File

@@ -60,9 +60,11 @@
{{ document.storedObject|chill_document_button_group(document.title, is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', document.accompanyingPeriodWorkEvaluation.accompanyingPeriodWork)) }}
</li>
{% endif %}
{% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_SEE', w)%}
{% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', w) %}
<li>
<a href="{{ chill_path_add_return_path('chill_person_accompanying_period_work_show', {'id': w.id, 'docId': document.id}) }}" class="btn btn-show"></a>
<form method="post" action="{{ chill_path_add_return_path('chill_person_accompanying_period_work_evaluation_document_duplicate', {id: document.id}) }}">
<button type="submit" class="btn btn-duplicate" title="{{ 'crud.view.link_duplicate'|trans }}"></button>
</form>
</li>
{% endif %}
{% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', w) %}
@@ -70,6 +72,11 @@
<a href="{{ chill_path_add_return_path('chill_person_accompanying_period_work_edit', {'id': w.id, 'docId': document.id}) }}" class="btn btn-edit"></a>
</li>
{% endif %}
{% if is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_SEE', w)%}
<li>
<a href="{{ chill_path_add_return_path('chill_person_accompanying_period_work_show', {'id': w.id, 'docId': document.id}) }}" class="btn btn-show"></a>
</li>
{% endif %}
</ul>
</div>

View File

@@ -328,8 +328,33 @@
</div>
</div>
{% endif %}
{% if person.signaturesPending|length > 0 %}
<div class="item-row separator">
<div class="wrap-list periods-list">
<div class="wl-row">
<div class="wl-col title">
<h3>{{ 'workflow.pending_signatures'|trans({nb_signatures: person.signaturesPending|length}) }}</h3>
</div>
<div class="wl-col list">
{% for signature in person.signaturesPending %}
{% set entityWorkflow = signature.step.entityWorkflow %}
{{ entityWorkflow|chill_entity_render_string }}
<ul class="record_actions small slim">
<li>
<a href="{{ chill_path_force_return_path(path('chill_main_workflow_show', {id: entityWorkflow.id}), 'chill_main_workflow_signature_metadata', {signature_id: signature.id}) }}" class="btn btn-misc">
<i class="fa fa-pencil"></i>
</a>
</li>
<li>
<a href="{{ chill_path_add_return_path('chill_main_workflow_show', {id: entityWorkflow.id}) }}" class="btn btn-show"></a>
</li>
</ul>
{% endfor %}
</div>
</div>
</div>
</div>
{% endif %}
</div>
{% endfor %}
</div>

View File

@@ -0,0 +1,44 @@
{% extends "@ChillPerson/Person/layout.html.twig" %}
{% set activeRouteKey = 'chill_person_signature_list' %}
{% block title %}{{ 'Person signatures'|trans ~ ' ' ~ person|chill_entity_render_string }}{% endblock %}
{% block dam %}
<a class="btn btn-misc" href="{{ chill_path_add_return_path('chill_main_workflow_signature_metadata', { 'signature_id': s.signature.id}) }}"><i class="fa fa-pencil-square-o"></i> {{ 'workflow.signature_zone.button_sign'|trans }}</a>
{% endblock %}
{% block content %}
<h1>{{ 'workflow.signature_list.title'|trans }}</h1>
<div class="container">
<div class="row align-items-center">
{% for s in signatures %}
{% set signature = s.signature %}
{% set workflow = s.workflow %}
{% set document = s.document %}
<div class="item-bloc">
<div class="item-row">
<div class="item-col flex-grow-1">
{% include workflow.handler_template with workflow.handler_template_data|merge({'display_action': true, 'display_action_more': [block('dam')|raw] }) %}
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
{% block css %}
{{ parent() }}
{{ encore_entry_link_tags('mod_async_upload') }}
{{ encore_entry_script_tags('mod_document_action_buttons_group') }}
{% endblock css %}
{% block js %}
{{ parent() }}
{{ encore_entry_script_tags('mod_async_upload') }}
{{ encore_entry_link_tags('mod_document_action_buttons_group') }}
{% endblock js %}

View File

@@ -13,6 +13,11 @@
</div>
{% if display_action is defined and display_action == true %}
<ul class="record_actions">
{% for dam in display_action_more|default([]) %}
<li>
{{ dam|raw }}
</li>
{% endfor %}
<li>
<a class="btn btn-update"
href="{{ chill_path_add_return_path('chill_person_accompanying_period_work_edit', { 'id': work.id }) }}">

View File

@@ -94,6 +94,11 @@
{% if display_action is defined and display_action == true %}
{# TODO add acl #}
<ul class="record_actions">
{% for dam in display_action_more|default([]) %}
<li>
{{ dam|raw }}
</li>
{% endfor %}
<li>
<a class="btn btn-show" href="{{ path('chill_person_accompanying_period_work_edit', {'id': evaluation.accompanyingPeriodWork.id}) }}">
{{ 'Show'|trans }}

View File

@@ -121,6 +121,11 @@
{% if display_action is defined and display_action == true %}
<ul class="record_actions">
{% for dam in display_action_more|default([]) %}
<li>
{{ dam|raw }}
</li>
{% endfor %}
<li>{{ doc.storedObject|chill_document_button_group(doc.title, is_granted('CHILL_MAIN_ACCOMPANYING_PERIOD_WORK_UPDATE', evaluation.accompanyingPeriodWork)) }}</li>
<li>
<a class="btn btn-show" href="{{ path('chill_person_accompanying_period_work_edit', {'id': evaluation.accompanyingPeriodWork.id, 'doc_id': doc.id}) }}">