diff --git a/CHANGELOG.md b/CHANGELOG.md index c7ed37b4c932ee5925f1c3dfe3268ce3041bc5fe..56ddf9335324ad21e3760e0249d0ff8d0cd7b67a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,27 @@ Journal des modifications ========================= +6.0.6 +----- +- Passage dans UnicaenRenderer du template des historiques de co-encadrements +- Ajout d'un filtre sur l'année sur l'écran des formations pour masquer/afficher les sessions +- Extraction CSV des thèses : amélioration du temps de génération (création d'une vue en bdd) ; ajout des colonnes +'Dernier rapport d'activité', 'Dernier rapport CSI', 'Date d'extraction', 'Discipline Code SISE', 'Autorisation de MEL', +'Années financées' ; modification du séparateur de valeurs multiples ',' en ' ; ' ; correction de la colonne +'Date de dépôt version corrigée' toujours vide. +- [FIX] Création d'un compte utilisateur local : vérif de l'email déjà utilisé remplacée par vérif de l'email déjà utilisé comme username. +- [FIX] Création d'un compte utilisateur local : redirection vers la fiche du nouveau compte après création. +- [FIX] Soutenance : message d'alerte affiché à tort systématiquement à propos de l'adresse Doctorat manquante. +- [FIX] Chargement de la navigation : plantage d'une assertion à cause d'une variable null (role). +- [FIX] Accès aux fiches individus. +- [FIX] Pages de couverture : réduction de la marge en haut de page. + 6.0.5 ----- - [FIX] Correction d'un bug empêchant la création d'établissement ; améliorations des validateurs des formulaires de structures. - [FIX] Correction de bugs en cas d'utilisateur ayant à la fois le rôle Doctorant et un autre rôle. - [FIX] Correction du plantage survenant dans RapportActiviteAssertion (interrogée par la navigation) lorsque l'utilisateur n'est pas authentifié. -- [FIX] Destinataires de la notification de demande de validation d'une proposition de soutenance : adresse mail "aspects doctorat" +- [FIX] Destinataires de la notification de demande de validation d'une proposition de soutenance : adresse mail 'aspects doctorat' de l'établissement d'inscription, plutôt que la liste des individus ayant le rôle BDD obsolète. - Onglet 'Rôles et membres' d'une ED/UR : renommage de 'Site' en 'Établissement d'inscription' (clarification). - Complétion des qualités du jury sur la page de couverture avec le dossier de soutenance si manquante dans la donnée source @@ -66,7 +81,7 @@ Journal des modifications 5.3.1 ----- -- [FIX] Donnée : ajout de garde lorsque le mail fourni par les données sources est " " +- [FIX] Donnée : ajout de garde lorsque le mail fourni par les données sources est ' ' - [FIX] hydration des justificatifs 5.3.0 @@ -79,10 +94,10 @@ Journal des modifications - Soutenance : Renommange de Parité en Équilibre (et ajustement des couleurs des barres de l'indicateur) - Soutenance : Retravail du rapport de soutenance (Ajout d'une page blacnhe et d'une troisième page pour les signatures) - Soutenance : Ajout du dépôt de l'autorisation de soutenance et du rapport de soutenance -- Soutenance : Dépôt de l'attestation de la formation "Intégrité scientifique" +- Soutenance : Dépôt de l'attestation de la formation 'Intégrité scientifique' - Soutenance : Mise en place de l'horodatage - Soutenance : Ajout d'une étape intermédiaire avant feu vert pour soutenance -- Soutenance : [Fix] Echappement des caractères " et encapsulation des réponses +- Soutenance : [Fix] Echappement des caractères ' et encapsulation des réponses - Dépôt de thèse : un dépôt existant de la version corrigée reste visible même si l'avis de reproduction Apogée revient à Non. - Menu Dépôt fichiers divers : remonté et affiché sans condition - Page Dépôt fichiers divers : téléversement bloqué pour PV soutenance, Pré-rapport soutenance, Rapport soutenance @@ -127,7 +142,7 @@ Journal des modifications - Suppression du menu 'Mes données' : la modif de l'adresse de contact et du consentement associé est désormais sur la fiche Thèse - Abandon (avant suppression) de la table obsolète doctorant_compl. - Ajout d'un bloc dans l'écran de proposition de soutenance pour le téléchargement des pré-rapports et du serment -- Nouveau document "Serment du docteur" +- Nouveau document 'Serment du docteur' - Modification du pv de soutenance - Ajout d'un nouvel mail intermediare à la clôture des inscriptions + deplacement du mail d'echec d'inscription - [FIX] Module Formation : Ordonnancement des séances sur les index des formations et des sessions @@ -192,7 +207,7 @@ Journal des modifications - Changement de l'assertion pour l'accès des rapporteurs à la proposition de soutenance - [FIX] Remise en place du menu de dépôt de rapport de pré-soutenance - Changement du libellé 'Aucun Site' => 'Multi-site' (module de formation) -- Extension du mail "échec d'inscription" aux personnes non classées (module de formation) +- Extension du mail 'échec d'inscription' aux personnes non classées (module de formation) - Changements de libellés. 5.2.1 @@ -219,7 +234,7 @@ Journal des modifications 5.1.1 ----- - [FIX] Corrections suite à l'intégration du nouveau module Fichier. -- [FIX] Suppression à tort des "attestations" du 1er dépôt à la place de celles du 2nd dépôt. +- [FIX] Suppression à tort des 'attestations' du 1er dépôt à la place de celles du 2nd dépôt. - [FIX] Suppression physique de l'ancien fichier lors du changement de logo d'une structure. - [FIX] Correction et amélioration du calcul du nom de fichier du logo (existant ou nouveau) d'une structure. - Template de pagination : abandon du module/Application/view/paginator.phtml et généralisation du module/Application/view/application/paginator.phtml @@ -227,7 +242,7 @@ Journal des modifications 5.1.0 ----- -- Nouveau module "technique" Fichier proposant 2 modes de stockage des fichiers téléversés : Filesystem ou S3 +- Nouveau module 'technique' Fichier proposant 2 modes de stockage des fichiers téléversés : Filesystem ou S3 (cf. [releases notes](./doc/release-notes/v5.1.0.md)). - [FIX] Correction du chemin de stockage des rapports CSI et de mi-parcours @@ -305,7 +320,7 @@ Journal des modifications 4.0.4 ----- - Correction de typos dans mail de feu vert de la soutenance -- Ajout de redirection de mail lorsque certains mails n'ont pas de destinataire "ATTENTION MAIL NON DÉLIVRÉ". +- Ajout de redirection de mail lorsque certains mails n'ont pas de destinataire 'ATTENTION MAIL NON DÉLIVRÉ'. - Compléments d'individu : mise en place des éléments de base - Modification du texte de mail de réussite au doctorat - [FIX] verification des assertions au niveau des actions de PropositionController @@ -334,14 +349,14 @@ Journal des modifications - Migration vers Bootstrap 5 (front-end JS & CSS). - Réorganisation des infos affichées à propos de la connexion dans le menu principal. - Cas de la connexion d'un utilisateur sans possibilité de trouver d'individu associé : plus de création automatique d'individu car peut bloquer un import ultétieur. -- Amélioration de la page "Contact Assistance" en cas d'établissement indéterminé et/ou d'adresse d'assistance indéterminé ou invalide. -- [FIX] Plantage de la page "Contact Assistance" en cas de connexion avec un compte local. +- Amélioration de la page 'Contact Assistance' en cas d'établissement indéterminé et/ou d'adresse d'assistance indéterminé ou invalide. +- [FIX] Plantage de la page 'Contact Assistance' en cas de connexion avec un compte local. - [FIX] Activation de la mise en cache de la config lorsque le mode development est désactivé. - [FIX] Lancement de la synchro des thèses pour prendre en compte la création/modification/suppression de substitution de structures. - Ajout des unités de recherche fermées dans le filtre des thèses - [FIX] correction du bug lié au typage de retour trop strict de l'entité Structure - Mise en place de la déclaration de non plagiat dans la proposition de soutenance -- [FIX] Plantage lors de la création/modification/suppression d'une substitution de structure ("Synchro introuvable avec ce nom : these") +- [FIX] Plantage lors de la création/modification/suppression d'une substitution de structure ('Synchro introuvable avec ce nom : these') 3.0.12 ------ @@ -368,7 +383,7 @@ Journal des modifications 3.0.10 ----- -- Ajout de la mention "La réservation du lieu de soutenance n'est pas faite automatiquement et reste à votre charge" +- Ajout de la mention 'La réservation du lieu de soutenance n'est pas faite automatiquement et reste à votre charge' - Meilleure gestion des tokens des membres d'une soutenance - Déclaration tardive de visoconférence ajouté aux interventions de soutenance - Avis sur rapport d'activité de fin de thèse @@ -428,7 +443,7 @@ Journal des modifications 3.0.3 ----- -- Ajout d'une valeur d'état aux soutenances "Validée par l'établissement" post validation d'une soutenance par la présidence de l'établissement +- Ajout d'une valeur d'état aux soutenances 'Validée par l'établissement' post validation d'une soutenance par la présidence de l'établissement - [FIX] Plus de demande de justificatif pour la confidentialité si la demande est faite en amont de la soutenance - [FIX] La notif de validation de la version corrigée par le Président du jury faisait mention à tort du Directeur de thèse. - [FIX] Plantage de l'export CSV des thèses à cause d'un appel de méthode erroné (getMailContact). @@ -466,12 +481,12 @@ Journal des modifications 2.2.3 ----- -- Scission du rôle "École doctorale" en 2 : "Responsable École doctorale" et "Gestionnaire École doctorale". -- Scission du rôle "Unité de recherche" en 2 : "Responsable Unité de recherche" et "Gestionnaire Unité de recherche". +- Scission du rôle 'École doctorale' en 2 : 'Responsable École doctorale' et 'Gestionnaire École doctorale'. +- Scission du rôle 'Unité de recherche' en 2 : 'Responsable Unité de recherche' et 'Gestionnaire Unité de recherche'. - Envoi automatique par mail des jetons d'authentification créés + possibilité de les renvoyer. - Utilisation des dates et lieux des dossiers de soutenances plutôt que celles saisies dans les SIs pour la génération des documents du module soutenance. - Précision de la date de rendu des rapports dès le premier mail des rapporteurs -- Recherche de rapports d'activité : nouveau filtre "Annuel ou fin de thèse". +- Recherche de rapports d'activité : nouveau filtre 'Annuel ou fin de thèse'. - Fiche d'identité de la thèse : la date prévisionnelle de soutenance n'est plus affichée car elle peut être erronée. - Rapports d'activité, CSI, de fin de thèse : la date de bascule pour déterminer l'année universitaire est le 01/11. - [FIX] Dédoublonnage des origines de financement dans le filtres de la page des rapports. @@ -489,7 +504,7 @@ Journal des modifications - [FIX] Ligne de commande de lancement de toutes les synchros. - [FIX] Correction du texte de la convocation s'attendant à avoir un individu (pas toujours le cas car le lien n'est pas fait systèmatiquement). - [FIX] La recherche du doctorant lié à un individu doit écarter les individus historisés. -- [FIX] Warning lors de la génération de la PDC à cause d'un tableau non initialisé" +- [FIX] Warning lors de la génération de la PDC à cause d'un tableau non initialisé' 2.2.0 ----- @@ -569,8 +584,8 @@ Journal des modifications - Ajout à l'export de l'annuaire des co-encadrants - Onglets dans les pages d'information des structures - Page de connexion scindée par type d'authentification activée. -- Import du témoin "corrections effectuées" de chaque thèse. -- Pages de dépôt de la version corrigée : visibles dès lors que le témoin "corrections effectuées" est à Oui. +- Import du témoin 'corrections effectuées' de chaque thèse. +- Pages de dépôt de la version corrigée : visibles dès lors que le témoin 'corrections effectuées' est à Oui. - Amélioration du temps de réponse de la recherche textuelle de thèses. - Retour du bouton d'import forcé de thèse qui avait disparu à cause d'une erreur de config. - Mise en retrait des items de menus concernant le dépôt de la version initiale en cas de corrections attendues ou effectuées. @@ -619,7 +634,7 @@ Journal des modifications - Ajout d'une configuration pour le fil d'actualité. - Ajout du champ IdREF pour toutes les structures et modification de l'affichage/saisie des informations. - Changement de l'affichage des structures fermées dans le filtre des thèses. -- Nouveau message "Dépôt terminé" au doctorant sur la page Rendez-vous BU. +- Nouveau message 'Dépôt terminé' au doctorant sur la page Rendez-vous BU. 1.4.8 (01/09/2020) ------------------ @@ -631,15 +646,15 @@ Journal des modifications ------------------ - Lors du dépôt d'une version corrigée, l'autorisation de mise en ligne est reprise texto (dupliquée) du 1er dépôt, -sauf si l'utilisateur possède le privilège "Saisie du formulaire d'autorisation de diffusion de la version corrigée", +sauf si l'utilisateur possède le privilège 'Saisie du formulaire d'autorisation de diffusion de la version corrigée', auquel cas elle est redemandée à l'utilisateur. -Idem pour les attestations et le privilège "Modification des attestations concernant la version corrigée". +Idem pour les attestations et le privilège 'Modification des attestations concernant la version corrigée'. - Masquage du complément de financement dans la fiche d'identité de la thèse - Optimisation de l'export CSV des thèses - Pages de téléversement et de recherche des rapports annuels. - Correction d'un bug dans la recherche de thèses par nom du doctorant. - Correction d'un bug dans le package Oracle APP_IMPORT qui ne filtrait pas les thèses selon l'établissement spécifié. -- Possibilité d'attribuer un "identifiant permanent" à un fichier (ex: 'RAPPORT_ANNUEL_MODELE') facilitant l'intégration +- Possibilité d'attribuer un 'identifiant permanent' à un fichier (ex: 'RAPPORT_ANNUEL_MODELE') facilitant l'intégration de lien de téléchargement de ce fichier dans une page. - Listes de diffusion dynamique Sympa alimentées par SyGAL : pages de consultation des listes de diffusion déclarées dans la config ; une URL pour fournir les abonnés, une autre pour fournir les propriétaires. @@ -647,16 +662,16 @@ Idem pour les attestations et le privilège "Modification des attestations conce 1.4.6 (29/05/2020) ------------------ -- Ajout du drapeau "établissement d'inscription" et ajout des visualisations et interfaces pour gérer ce nouveau drapeau. +- Ajout du drapeau 'établissement d'inscription' et ajout des visualisations et interfaces pour gérer ce nouveau drapeau. - Restriction du filtre des établissements sur la partie annuaire aux établissements d'inscription. - Ajout dans structures des champs adresse, tel, fax, site web, email qui sont utilisables pour l'édition de document. - Utilisation des nouveaux champs dans la génération de la convention de MEL (requiert unicaen/app v1.3.19). - Amélioration de la recherche textuelle de thèses : ajout d'une liste déroulante permettant de sélectionner - précisément sur quels critères porte la recherche : "Titre de la thèse", "Numéro étudiant de l'auteur", - "Nom de l'auteur", "Prénom de l'auteur", "Nom du directeur ou co-directeur de thèse", - "Code national de l'école doctorale concernée (ex: 181)", "Unité de recherche concernée (ex: umr6211)". -- Correction d'un dysfonctionnement de la recherche textuelle sur les critères "numéro étudiant", "unité de recherche" - et "école doctorale". + précisément sur quels critères porte la recherche : 'Titre de la thèse', 'Numéro étudiant de l'auteur', + 'Nom de l'auteur', 'Prénom de l'auteur', 'Nom du directeur ou co-directeur de thèse', + 'Code national de l'école doctorale concernée (ex: 181)', 'Unité de recherche concernée (ex: umr6211)'. +- Correction d'un dysfonctionnement de la recherche textuelle sur les critères 'numéro étudiant', 'unité de recherche' + et 'école doctorale'. 1.4.5 (08/04/2020) @@ -685,7 +700,7 @@ Idem pour les attestations et le privilège "Modification des attestations conce - Extraction CSV des thèses : nouvelles colonnes concernant l'embargo et refus de diffusion ; virgule plutôt que point dans la durée de la thèse. - Page d'accueil : affichage des actualités issues du flux RSS fourni par la COMUE. -- Filtrage de la liste des thèses : correction de l'affichage du filtre "Unité de recherche". +- Filtrage de la liste des thèses : correction de l'affichage du filtre 'Unité de recherche'. - Corrections de textes sur la page RDV BU. @@ -705,8 +720,8 @@ Idem pour les attestations et le privilège "Modification des attestations conce - Modification des textes liés à l'autorisation de diffusion dans le formulaire et dans la convention PDF générée. - Convention de MEL : suppression du petit logo dans l'entête puisqu'il y en a déjà un sous le titre - Nouvelle charte de diffusion téléchargeable. -- Ajout du flag "fermé" pour les structures et utilisations dans la recherche de thèses. -- Ajout d'un champ "Id HAL" dans le formulaire d'autorisation de diffusion. +- Ajout du flag 'fermé' pour les structures et utilisations dans la recherche de thèses. +- Ajout d'un champ 'Id HAL' dans le formulaire d'autorisation de diffusion. - Ajout d'un menu dépôt pour séparer les action liés au dépôt de la partie annuaire - La couverture est maintenant recto/verso lorsque la premiere page n'est pas retirée - Ajout de la colonne durée des thèses dans l'export @@ -746,7 +761,7 @@ Idem pour les attestations et le privilège "Modification des attestations conce - Convention de mise en ligne : - Le libellé du tribunal compétent mentionné est importé de chaque établissement. - - Utilisation de la mention générique "Le chef d'établissement" plutôt que d'exploiter les libellés + - Utilisation de la mention générique 'Le chef d'établissement' plutôt que d'exploiter les libellés importés des établissements. - Nouvelle ligne de commande pour importer une thèse à la demande. @@ -757,7 +772,7 @@ Idem pour les attestations et le privilège "Modification des attestations conce - Améliorations pour utiliser moins de mémoire ; meilleurs logs. - Correction des exceptions de type `ORA-00001: unique constraint (SYGAL.TMP_ACTEUR_UNIQ) violated` par un changement de stratégie côté web service (interrogation de tables plutôt que des vues). -- Le bouton d'import d'une thèse à la demande avait disparu (menu "Page de couverture") à cause d'une config erronée. +- Le bouton d'import d'une thèse à la demande avait disparu (menu 'Page de couverture') à cause d'une config erronée. 1.2.11 (13/11/2019) ------------------ @@ -776,7 +791,7 @@ Idem pour les attestations et le privilège "Modification des attestations conce ### Ajout - Un message avertissant des formats d'image valide est maintenant ajouté dans les pages de modification des structures concertes -- Utilisation de convert (imagemagick) pour convertir les logos "automatiquement" au format png +- Utilisation de convert (imagemagick) pour convertir les logos 'automatiquement' au format png 1.2.9 (24/10/2019) ------------------ @@ -846,19 +861,19 @@ Idem pour les attestations et le privilège "Modification des attestations conce ### Ajout -- Nouvelle page consacrée au dépôt de fichiers divers liés à une thèse (précédemment dans la page "Thèse"). -- Possibilité de déposer des fichiers dits "communs" utiles aux gestionnaires, ex: modèle d'avenant à la convention +- Nouvelle page consacrée au dépôt de fichiers divers liés à une thèse (précédemment dans la page 'Thèse'). +- Possibilité de déposer des fichiers dits 'communs' utiles aux gestionnaires, ex: modèle d'avenant à la convention de mise en ligne. ### Améliorations -- Améliorations de la page "Privilèges", notamment le filtrage par rôle. +- Améliorations de la page 'Privilèges', notamment le filtrage par rôle. - Déplacement des privilèges de la catégorie `fichier-divers` vers la catégorie `these` car ils concernent des fichiers liés à une thèse (ex: PV de soutenance). La catégorie `fichier-divers` désigne désormais les privilèges concernant des fichiers sans lien aux thèses (ex: fichiers déposés pour les pages d'informations). - Refonte technique de la gestion des fichiers liés aux pages d'informations, prélable au travail sur les droits de - dépôt de fichiers "divers" et "communs". + dépôt de fichiers 'divers' et 'communs'. 1.2.0 (10/07/2019) diff --git a/doc/release-notes/v6.0.6.md b/doc/release-notes/v6.0.6.md new file mode 100644 index 0000000000000000000000000000000000000000..ba1620098ea9504dc6fdf138beeb498081b5da37 --- /dev/null +++ b/doc/release-notes/v6.0.6.md @@ -0,0 +1,243 @@ +# Version 6.0.6 + +## 1. Sur le serveur d'application + +*Rappel : depuis la version 6.0.0, la version de PHP requise est la 8.0.* + +- Placez-vous dans le répertoire de l'application puis lancez la commande suivante + pour installer la nouvelle version : + +```bash +git fetch --tags && git checkout --force 6.0.6 && bash ./install.sh +``` + +- Rechargez le moteur PHP, exemple : + +```bash +systemctl reload php8.0-fpm +``` + +## 2. Dans la base de données + +```postgresql +alter table structure + alter column type_structure_id set not null; + +-- INSERTION DE NOUVELLES MACROS -- +INSERT INTO unicaen_renderer_macro (code, description, variable_name, methode_name) VALUES ('Acteur#Denomination', '<p>Retourne la dénomination de l''acteur sous la forme - Prénom Nom -</p>', 'acteur', 'getDenomination'); +INSERT INTO unicaen_renderer_macro (code, description, variable_name, methode_name) VALUES ('Acteur#Etablissement', '<p>Retourne le libellé de l''établissement du co-encadrant</p>', 'acteur', 'getEtablissementAsLibelle'); +INSERT INTO unicaen_renderer_macro (code, description, variable_name, methode_name) VALUES ('Acteur#Qualite', '<p>retourne la qualité de l''acteur (maître de conférence, directeur de recherche, ...)</p>', 'acteur', 'getQualite'); +-- INSERTION DU TEMPLATE POUR L'HISTORIQUE DES CO-ENCADREMENTS +INSERT INTO unicaen_renderer_template (code, description, document_type, document_sujet, document_corps, document_css, namespace) VALUES ('COENCADREMENTS_JUSTIFICATIF', null, 'pdf', 'Justificatif de co-encadrements de VAR[Acteur#Denomination]', e'<h1>Justificatif de co-encadrements</h1> +<p>Ce document certifie que VAR[Acteur#Denomination], actuellement VAR[Acteur#Qualite] à VAR[Acteur#Etablissement], a assuré la fonction de co-encadrant sur pour les thèses suivantes :<br />###LISTING_THESE###</p>', null, 'These\Provider\Template'); + +-- +-- Nouvelle vue pour l'extraction CSV des thèses. +-- +drop view if exists v_extract_theses; +create or replace view v_extract_theses as + with mails_contacts as ( + select distinct individu_id, + first_value(email) over (partition by individu_id order by id desc) email + from mail_confirmation + where etat = 'C'/*confirmé*/ + ), directeurs as ( + select these_id, + string_agg(concat(i.nom_usuel, ' ', i.prenom1), ' ; ') identites + from acteur a + join role r on a.role_id = r.id and r.code = 'D' + join individu i on a.individu_id = i.id + where a.histo_destruction is null + group by these_id + ), codirecteurs as ( + select these_id, + string_agg(concat(i.nom_usuel, ' ', i.prenom1), ' ; ') identites + from acteur a + join role r on a.role_id = r.id and r.code in ('C','K') + join individu i on a.individu_id = i.id + where a.histo_destruction is null + group by these_id + ), coencadrants as ( + select these_id, + string_agg(concat(i.nom_usuel, ' ', i.prenom1), ' ; ') identites + from acteur a + join role r on a.role_id = r.id and r.code in ('B','N') + join individu i on a.individu_id = i.id + where a.histo_destruction is null + group by these_id + ), financements as ( + select these_id, + string_agg(case o.visible when true then 'O' else 'N' end, ' ; ') financ_origs_visibles, + string_agg(f.annee::varchar, ' ; ') financ_annees, + string_agg(o.libelle_long, ' ; ') financ_origs, + string_agg(f.complement_financement, ' ; ') financ_compls, + string_agg(f.libelle_type_financement, ' ; ') financ_types + from financement f + join origine_financement o on f.origine_financement_id = o.id + where f.histo_destruction is null + group by these_id + ), domaines as ( + select unite_id, + string_agg(d.libelle, ' ; ') libelles + from unite_domaine_linker udl + join domaine_scientifique d on d.id = udl.domaine_id + group by unite_id + ), depots_vo_pdf as ( + select distinct these_id, + first_value(vf.code) over (partition by these_id order by ft.id desc) version_code, + first_value(f.histo_creation) over (partition by these_id order by ft.id desc) histo_creation + from fichier_these ft + join fichier f on ft.fichier_id = f.id and f.histo_destruction is null + join nature_fichier nf on f.nature_id = nf.id and nf.code = 'THESE_PDF' + join version_fichier vf on f.version_fichier_id = vf.id and vf.code = 'VO' + ), depots_voc_pdf as ( + select distinct these_id, + first_value(vf.code) over (partition by these_id order by ft.id desc) version_code, + first_value(f.histo_creation) over (partition by these_id order by ft.id desc) histo_creation + from fichier_these ft + join fichier f on ft.fichier_id = f.id and f.histo_destruction is null + join nature_fichier nf on f.nature_id = nf.id and nf.code = 'THESE_PDF' + join version_fichier vf on f.version_fichier_id = vf.id and vf.code = 'VOC' + ), depots_non_pdf as ( + select distinct these_id, + first_value(vf.code) over (partition by these_id order by ft.id desc) version_code, + first_value(f.histo_creation) over (partition by these_id order by ft.id desc) histo_creation + from fichier_these ft + join fichier f on ft.fichier_id = f.id and f.histo_destruction is null + join nature_fichier nf on f.nature_id = nf.id and nf.code = 'FICHIER_NON_PDF' + join version_fichier vf on f.version_fichier_id = vf.id and vf.code in ('VO', 'VOC') + ), diffusion as ( + select distinct these_id, + first_value(autoris_mel) over (partition by these_id order by version_corrigee desc, id desc) autoris_mel, + first_value(autoris_embargo_duree) over (partition by these_id order by version_corrigee desc, id desc) autoris_embargo_duree, + first_value(autoris_motif) over (partition by these_id order by version_corrigee desc, id desc) autoris_motif + from diffusion d + where histo_destruction is null + ), dernier_rapport_activite as ( + select distinct these_id, + first_value(annee_univ) over (partition by these_id order by annee_univ desc) annee + from rapport_activite ra + where ra.histo_destruction is null + ), dernier_rapport_csi as ( + select distinct these_id, + first_value(annee_univ) over (partition by these_id order by annee_univ desc) annee + from rapport r + join type_rapport tr on r.type_rapport_id = tr.id and tr.code = 'RAPPORT_CSI' + where r.histo_destruction is null + ) + select to_char(current_timestamp,'DD/MM/YYYY HH24:MI:SS') date_extraction, + th.id, + di.civilite, + di.nom_usuel, + di.nom_patronymique, + di.prenom1, + to_char(di.date_naissance,'DD/MM/YYYY') date_naissance, + di.nationalite, + coalesce(dic.email, di.email) email_pro, + mc.email email_contact, + d.ine, + substr(d.source_code, strpos(d.source_code, '::') + 2) num_etudiant, + th.source_code num_these, + th.titre, + th.code_sise_disc, + th.lib_disc, + dirs.identites dirs, + codirs.identites codirs, + coencs.identites coencs, + coalesce(se2.libelle, se.libelle) etab_lib, + coalesce(sed2.code, sed.code) ed_code, + coalesce(sed2.libelle, sed.libelle) ed_lib, + coalesce(sur2.code, sur.code) ur_code, + coalesce(sur2.libelle, sur.libelle) ur_lib, + th.lib_etab_cotut, + th.lib_pays_cotut, + ta.libelle_titre_acces, + ta.libelle_etb_titre_acces, + f.financ_origs_visibles, + f.financ_annees, + f.financ_origs, + f.financ_compls, + f.financ_types, + dom.libelles domaines, + to_char(th.date_prem_insc,'DD/MM/YYYY') date_prem_insc, to_char(th.date_abandon,'DD/MM/YYYY') date_abandon, + to_char(th.date_transfert,'DD/MM/YYYY') date_transfert, to_char(th.date_prev_soutenance,'DD/MM/YYYY') date_prev_soutenance, + to_char(th.date_soutenance,'DD/MM/YYYY') date_soutenance, to_char(th.date_fin_confid,'DD/MM/YYYY') date_fin_confid, + round((th.date_soutenance::date - th.date_prem_insc::date) / 30.5, 2) duree_these_mois, + to_char(depots_vo_pdf.histo_creation,'DD/MM/YYYY') date_depot_vo, + to_char(depots_voc_pdf.histo_creation,'DD/MM/YYYY') date_depot_voc, + case th.etat_these when 'E' then 'En cours' when 'A' then 'Abandonnée' when 'S' then 'Soutenue' when 'U' then 'Transférée' end etat_these, + th.soutenance_autoris, + case when th.date_fin_confid is null or th.date_fin_confid < current_timestamp then 'N' else 'O' end confidentielle, + th.resultat, + case when th.correc_autorisee_forcee = 'aucune' then 'N' else coalesce(th.correc_autorisee_forcee, th.correc_autorisee) end correc_autorisee, + case when depots_vo_pdf.these_id is null and depots_voc_pdf.these_id is null then 'N' else 'O' end depot_pdf, + case when depots_non_pdf.these_id is null then 'N' else 'O' end depot_annexe, + case diff.autoris_mel when 0 then 'Non' when 1 then 'Oui, avec embargo' when 2 then 'Oui, immédiatement' end autoris_mel, + diff.autoris_embargo_duree, + diff.autoris_motif, + case when ract.annee is not null then concat(ract.annee,'/',ract.annee+1) else null end dernier_rapport_activite, + case when rcsi.annee is not null then concat(rcsi.annee,'/',rcsi.annee+1) else null end dernier_rapport_csi + from these th + join doctorant d on th.doctorant_id = d.id + join individu di on d.individu_id = di.id + left join individu_compl dic on di.id = dic.individu_id and dic.histo_destruction is null + left join mails_contacts mc on mc.individu_id = di.id + join etablissement e on d.etablissement_id = e.id + join structure se on e.structure_id = se.id + left join structure_substit ses on se.id = ses.from_structure_id and ses.histo_destruction is null + left join structure se2 on se2.id = ses.to_structure_id + left join ecole_doct ed on th.ecole_doct_id = ed.id + left join structure sed on ed.structure_id = sed.id + left join structure_substit seds on sed.id = seds.from_structure_id and seds.histo_destruction is null + left join structure sed2 on sed2.id = seds.to_structure_id + left join unite_rech ur on th.unite_rech_id = ur.id + left join structure sur on ur.structure_id = sur.id + left join structure_substit surs on sur.id = surs.from_structure_id and surs.histo_destruction is null + left join structure sur2 on sur2.id = surs.to_structure_id + left join domaines dom on dom.unite_id = ur.id + left join titre_acces ta on th.id = ta.these_id and ta.histo_destruction is null + left join financements f on th.id = f.these_id + left join directeurs dirs on dirs.these_id = th.id + left join codirecteurs codirs on codirs.these_id = th.id + left join coencadrants coencs on coencs.these_id = th.id + left join depots_vo_pdf on depots_vo_pdf.these_id = th.id + left join depots_voc_pdf on depots_voc_pdf.these_id = th.id + left join depots_non_pdf on depots_non_pdf.these_id = th.id + left join diffusion diff on diff.these_id = th.id + left join dernier_rapport_activite ract on ract.these_id = th.id + left join dernier_rapport_csi rcsi on rcsi.these_id = th.id + where th.histo_destruction is null +; + + +create or replace function transfert_these(fromtheseid bigint, totheseid bigint) returns void + language plpgsql +as +$$ +BEGIN + -- select 'update '||rpad(table_name, 35)||' set '||column_name||' = totheseid where '||column_name||' = fromtheseid ;' from information_schema.columns +-- where column_name ilike 'these_id' and +-- table_name not ilike 'v\_%' and +-- table_name not ilike 'src_%' and +-- table_name not ilike 'tmp_%' and +-- lower(table_name) not in ('acteur', 'financement', 'these_annee_univ', 'titre_acces', 'step_star_log'); + + --update soutenance_proposition set histo_destruction = now(), histo_destructeur_id = 1 where these_id = totheseid ; + + update attestation set these_id = totheseid where these_id = fromtheseid ; + update diffusion set these_id = totheseid where these_id = fromtheseid ; + update fichier_these set these_id = totheseid where these_id = fromtheseid ; + update metadonnee_these set these_id = totheseid where these_id = fromtheseid ; + update rapport set these_id = totheseid where these_id = fromtheseid ; + update rdv_bu set these_id = totheseid where these_id = fromtheseid ; + update soutenance_intervention set these_id = totheseid where these_id = fromtheseid ; + update soutenance_proposition set these_id = totheseid where these_id = fromtheseid ; + update validation set these_id = totheseid where these_id = fromtheseid ; + update csi_membre set these_id = totheseid where these_id = fromtheseid ; + update rapport_activite set these_id = totheseid where these_id = fromtheseid ; + + refresh materialized view mv_recherche_these; +END; +$$; + +``` \ No newline at end of file diff --git a/module/Application/config/others/export.config.php b/module/Application/config/others/export.config.php index c06e427a15cac3fbe2e60520667f3d4304669dde..f73e85dac79e9812ffa6f7a5421e6eba93a2bb63 100755 --- a/module/Application/config/others/export.config.php +++ b/module/Application/config/others/export.config.php @@ -1,5 +1,6 @@ <?php +use Application\Controller\ExportController; use Application\Controller\Factory\ExportControllerFactory; use These\Provider\Privilege\ThesePrivileges; use UnicaenAuth\Guard\PrivilegeController; @@ -9,7 +10,7 @@ return [ 'guards' => [ PrivilegeController::class => [ [ - 'controller' => 'Application\Controller\Export', + 'controller' => ExportController::class, 'action' => [ 'csv', ], @@ -25,8 +26,7 @@ return [ 'options' => [ 'route' => '/export', 'defaults' => [ - '__NAMESPACE__' => 'Application\Controller', - 'controller' => 'Export', + 'controller' => ExportController::class, ], ], 'may_terminate' => false, @@ -36,6 +36,7 @@ return [ 'options' => [ 'route' => '/csv', 'defaults' => [ + /** @see ExportController::csvAction() */ 'action' => 'csv', ], ], @@ -51,7 +52,7 @@ return [ ], 'controllers' => [ 'factories' => [ - 'Application\Controller\Export' => ExportControllerFactory::class, + ExportController::class => ExportControllerFactory::class, ], ], ]; \ No newline at end of file diff --git a/module/Application/src/Application/Assertion/Rapport/RapportPageAssertion.php b/module/Application/src/Application/Assertion/Rapport/RapportPageAssertion.php index 9aa0b7aeb383bd8065eb6ceb2c67ae9fff4748cc..04d73f230617cee8407d65130838149e33a149dc 100644 --- a/module/Application/src/Application/Assertion/Rapport/RapportPageAssertion.php +++ b/module/Application/src/Application/Assertion/Rapport/RapportPageAssertion.php @@ -57,7 +57,7 @@ class RapportPageAssertion implements PageAssertionInterface, UserContextService $role = $this->userContextService->getSelectedIdentityRole(); // rôle doctorant - if ($role->isDoctorant()) { + if ($role && $role->isDoctorant()) { $doctorant = $this->userContextService->getIdentityDoctorant(); $this->assertTrue( $this->these->getDoctorant()->getId() === $doctorant->getId(), diff --git a/module/Application/src/Application/Controller/ExportController.php b/module/Application/src/Application/Controller/ExportController.php index c64e7510f9dad9e0c73668afbfdad356ebe31375..da03865ef8a952d3f3e596505742aa87fb6f2639 100644 --- a/module/Application/src/Application/Controller/ExportController.php +++ b/module/Application/src/Application/Controller/ExportController.php @@ -2,16 +2,14 @@ namespace Application\Controller; -use These\Entity\Db\Acteur; -use Application\Entity\Db\Financement; -use Application\Entity\Db\Role; -use These\Entity\Db\These; +use Application\Entity\Db\OrigineFinancement; use Application\Provider\Privilege\FinancementPrivileges; +use Application\SourceCodeStringHelperAwareTrait; use Depot\Service\FichierThese\FichierTheseServiceAwareTrait; +use Doctrine\DBAL\Exception; +use RuntimeException; use These\Service\These\TheseSearchServiceAwareTrait; use These\Service\These\TheseServiceAwareTrait; -use Application\SourceCodeStringHelperAwareTrait; -use UnicaenApp\Exception\LogicException; use UnicaenApp\View\Model\CsvModel; class ExportController extends AbstractController @@ -21,144 +19,90 @@ class ExportController extends AbstractController use FichierTheseServiceAwareTrait; use SourceCodeStringHelperAwareTrait; - public function csvAction() + public function csvAction(): CsvModel { + $originesFinancementsFilter = function ($r) { + if (empty($r['financ_origs'])) { + return null; + } + // certaines origines ne sont pas visibles par tout le monde (ex : handicap) + $origines = array_map('trim', explode(';', $r['financ_origs'])); + $visibles = array_map('trim', explode(';', $r['financ_origs_visibles'])); + $filteredOrigines = []; + foreach ($origines as $i => $orig) { + $isVisible = ['O'=>true,'N'=>false][$visibles[$i]]; + if ($isVisible || $this->isAllowed(new OrigineFinancement(), FinancementPrivileges::FINANCEMENT_VOIR_ORIGINE_NON_VISIBLE)) { + $filteredOrigines[] = $orig; + } + } + return implode(" ; ", $filteredOrigines); + }; + $headers = [ + 'id' => fn($r) => $r['id'], // Doctorant - 'Civilité' => function ($variables) { return $variables['doctorant']->getIndividu()->getCivilite(); }, - 'Nom usuel' => function ($variables) { return $variables['doctorant']->getIndividu()->getNomUsuel(); }, - 'Prenom' => function ($variables) { return $variables['doctorant']->getIndividu()->getPrenom(); }, - 'Nom patronymique' => function ($variables) { return $variables['doctorant']->getIndividu()->getNomPatronymique(); }, - 'Date de naissance' => function ($variables) { return $variables['doctorant']->getIndividu()->getDateNaissance(); }, - 'Nationalité' => function ($variables) { return $variables['doctorant']->getIndividu()->getNationalite(); }, - 'Adresse électronique' => function ($variables) { return $variables['doctorant']->getIndividu()->getEmailPro(); }, - 'Adresse électronique personnelle' => function ($variables) { return $variables['doctorant']->getIndividu()->getEmailContact(); }, - 'Numéro étudiant' => function ($variables) { return $this->sourceCodeStringHelper->removePrefixFrom($variables['doctorant']->getSourceCode()); }, - 'I.N.E.' => function ($variables) { return $variables['doctorant']->getIne(); }, + 'Civilité' => fn($r) => $r['civilite'], + 'Nom usuel' => fn($r) => $r['nom_usuel'], + 'Prenom' => fn($r) => $r['prenom1'], + 'Nom patronymique' => fn($r) => $r['nom_patronymique'], + 'Date de naissance' => fn($r) => $r['date_naissance'], + 'Nationalité' => fn($r) => $r['nationalite'], + 'Adresse électronique' => fn($r) => $r['email_pro'], + 'Adresse électronique personnelle' => fn($r) => $r['email_contact'], + 'Numéro étudiant' => fn($r) => $r['num_etudiant'], + 'I.N.E.' => fn($r) => $r['ine'], //These - 'Identifiant de la thèse' => function ($variables) { return $variables['these']->getSourceCode(); }, - 'Titre' => function ($variables) { return $variables['these']->getTitre(); }, - 'Discipline' => function ($variables) { return $variables['these']->getLibelleDiscipline(); }, + 'Identifiant de la thèse' => fn($r) => $r['num_these'], + 'Titre' => fn($r) => $r['titre'], + 'Discipline Code SISE' => fn($r) => $r['code_sise_disc'], + 'Discipline' => fn($r) => $r['lib_disc'], //Encadrements - 'Directeurs' => function ($variables) { - $directeurs = $variables['directeurs']; - $noms = []; - /** @var Acteur $directeur */ - foreach ($directeurs as $directeur) $noms[] = $directeur->getIndividu()->getNomComplet(); - return implode(",", $noms); - }, - 'Co-directeurs' => function ($variables) { - $directeurs = $variables['co-directeurs']; - $noms = []; - /** @var Acteur $directeur */ - foreach ($directeurs as $directeur) $noms[] = $directeur->getIndividu()->getNomComplet(); - return implode(",", $noms); - }, - 'Co-encadrants' => function ($variables) { - $acteurs = $variables['co-encadrants']; - $noms = []; - /** @var Acteur $acteurs */ - foreach ($acteurs as $directeur) $noms[] = $directeur->getIndividu()->getNomComplet(); - return implode(",", $noms); - }, + 'Directeurs' => fn($r) => $r['dirs'], + 'Co-directeurs' => fn($r) => $r['codirs'], + 'Co-encadrants' => fn($r) => $r['coencs'], //Structures - 'Etablissement' => function ($variables) { return $variables['etablissement']->getStructure()->getLibelle(); }, - 'Ecole Doctorale Code' => function ($variables) { return ($variables['ecole doctorale'])?$variables['ecole doctorale']->getStructure()->getCode():null; }, - 'Ecole Doctorale' => function ($variables) { return ($variables['ecole doctorale'])?$variables['ecole doctorale']->getStructure()->getLibelle():null; }, - 'Unité de Recherche Code' => function ($variables) { return ($variables['unite de recherche'])?$variables['unite de recherche']->getStructure()->getCode():null; }, - 'Unité de Recherche' => function ($variables) { return ($variables['unite de recherche'])?$variables['unite de recherche']->getStructure()->getLibelle():null; }, - 'Etablissement Co-Tutelle' => function ($variables) { return $variables['these']->getLibelleEtabCotutelle(); }, - 'Pays Co-Tutelle' => function ($variables) { return $variables['these']->getLibellePaysCotutelle(); }, + 'Etablissement' => fn($r) => $r['etab_lib'], + 'Ecole Doctorale Code' => fn($r) => $r['ed_code'], + 'Ecole Doctorale' => fn($r) => $r['ed_lib'], + 'Unité de Recherche Code' => fn($r) => $r['ur_code'], + 'Unité de Recherche' => fn($r) => $r['ur_lib'], + 'Etablissement Co-Tutelle' => fn($r) => $r['lib_etab_cotut'], + 'Pays Co-Tutelle' => fn($r) => $r['lib_pays_cotut'], //accession - 'Diplôme d\'accession à la thèse' => function ($variables) { return ($variables['these']->getTitreAcces())?$variables['these']->getTitreAcces()->getLibelleTitreAcces():null; }, - 'Établissement d\'accession à la thèse' => function ($variables) { return ($variables['these']->getTitreAcces())?$variables['these']->getTitreAcces()->getLibelleEtabTitreAcces():null; }, + "Diplôme d'accession à la thèse" => fn($r) => $r['libelle_titre_acces'], + "Établissement d'accession à la thèse" => fn($r) => $r['libelle_etb_titre_acces'], //Financements - 'Origines du financement' => function ($variables) { - $these = $variables['these']; - $financements = $these->getFinancements(); - $origines = []; - /** @var Financement $financement */ - foreach ($financements as $financement) { - $origine = $financement->getOrigineFinancement(); - if ($origine->isVisible() || $this->isAllowed($origine, FinancementPrivileges::FINANCEMENT_VOIR_ORIGINE_NON_VISIBLE)) { - $origines[] = $origine->getLibelleLong(); - } - } - return implode(",", $origines); - }, - 'Complément sur les financements' => function ($variables) { - $these = $variables['these']; - $financements = $these->getFinancements(); - $origines = []; - /** @var Financement $financement */ - foreach ($financements as $financement) $origines[] = ($financement->getComplementFinancement())?:" - "; - return implode(",", $origines); - }, - 'Type du financement' => function ($variables) { - $these = $variables['these']; - $financements = $these->getFinancements(); - $types = []; - /** @var Financement $financement */ - foreach ($financements as $financement) $types[] = $financement->getLibelleTypeFinancement(); - return implode(",", array_filter($types)); - }, + 'Années financées' => fn($r) => $r['financ_annees'], + 'Origines du financement' => $originesFinancementsFilter, + 'Complément sur les financements' => fn($r) => $r['financ_compls'], + 'Type du financement' => fn($r) => $r['financ_types'], //Domaine - 'Domaines scientifiques' => function ($variables) { - $unite = $variables['unite de recherche']; - $domaines = ($unite)?$unite->getDomaines():[]; - $liste = []; - /** @var Financement $financement */ - foreach ($domaines as $domaine) $liste[] = $domaine->getLibelle(); - return implode(",", $liste); - }, + 'Domaines scientifiques' => fn($r) => $r['domaines'], //Dates - 'Date de première inscription' => function ($variables) { return $variables['these']->getDatePremiereInscription(); }, - "Date d'abandon" => function ($variables) { return $variables['these']->getDateAbandon(); }, - 'Date de transfert' => function ($variables) { return $variables['these']->getDateTransfert(); }, - 'Date de prévisionnel de soutenance' => function ($variables) { return $variables['these']->getDatePrevisionSoutenance(); }, - 'Date de soutenance' => function ($variables) { return $variables['these']->getDateSoutenance(); }, - 'Date de fin de confientialité' => function ($variables) { return $variables['these']->getDateFinConfidentialite(); }, - 'Date de dépôt version initiale' => function ($variables) { return ($variables['version_initiale'])?$variables['version_initiale']->getFichier()->getHistoCreation()->format('d/m/Y'):"";}, - 'Date de dépôt version corigée' => function ($variables) { return ($variables['version_corrigee'])?$variables['version_corrigee']->getFichier()->getHistoCreation()->format('d/m/Y'):"";}, - 'Durée en mois de la thèse' => function ($variables) { try { return number_format($variables['these']->getDureeThese(), 2, ',', ''); } catch (LogicException $e) { return ""; } }, + 'Date de première inscription' => fn($r) => $r['date_prem_insc'], + "Date d'abandon" => fn($r) => $r['date_abandon'], + 'Date de transfert' => fn($r) => $r['date_transfert'], + 'Date de prévisionnel de soutenance' => fn($r) => $r['date_prev_soutenance'], + 'Date de soutenance' => fn($r) => $r['date_soutenance'], + 'Date de fin de confientialité' => fn($r) => $r['date_fin_confid'], + 'Date de dépôt version initiale' => fn($r) => $r['date_depot_vo'], + 'Date de dépôt version corrigée' => fn($r) => $r['date_depot_voc'], + 'Durée en mois de la thèse' => fn($r) => $r['duree_these_mois'], //Flags - 'Etat de la thèse' => function ($variables) { return $variables['these']->getEtatTheseToString();}, - 'Autorisation à soutenir' => function ($variables) { return $variables['these']->getSoutenanceAutorisee();}, - 'Est confidentielle' => function ($variables) { $now = new \DateTime(); $end= $variables['these']->getDateFinConfidentialite(); if ($now > $end) return "N"; else return "O"; }, - 'Résultat' => function ($variables) { return $variables['these']->getResultat();}, - 'Corrections' => function ($variables) { return $variables['these']->getCorrectionAutorisee();}, - 'Thèse format PDF' => function ($variables) { return $variables['version_initiale']?'O':'N'; }, - 'Annexe non PDF' => function ($variables) { return $variables['annexe']?'O':'N'; }, -// - //Embargo et refus de diffusion - 'Embargo' => function ($variables) { - $these = $variables['these']; - $versionInitiale = $variables['version_initiale']; - $versionCorrigee = $variables['version_corrigee']; - if ($versionCorrigee !== null) { - $diffusionCorrigee = $these->getDiffusionForVersion($versionCorrigee->getFichier()->getVersion()); - if ($diffusionCorrigee !== null) return $diffusionCorrigee->getAutorisEmbargoDuree(); - } - if ($versionInitiale !== null) { - $diffusionInitiale = $these->getDiffusionForVersion($versionInitiale->getFichier()->getVersion()); - if ($diffusionInitiale !== null) return $diffusionInitiale->getAutorisEmbargoDuree(); - } - return null; - }, - 'Refus de diffusion' => function ($variables) { - $these = $variables['these']; - $versionInitiale = $variables['version_initiale']; - $versionCorrigee = $variables['version_corrigee']->getVersion; - if ($versionCorrigee !== null) { - $diffusionCorrigee = $these->getDiffusionForVersion($versionCorrigee->getFichier()->getVersion()); - if ($diffusionCorrigee !== null) return $diffusionCorrigee->getAutorisMotif(); - } - if ($versionInitiale !== null) { - $diffusionInitiale = $these->getDiffusionForVersion($versionInitiale->getFichier()->getVersion()); - if ($diffusionInitiale !== null) return $diffusionInitiale->getAutorisMotif(); - } - return null; - }, + 'Etat de la thèse' => fn($r) => $r['etat_these'], + 'Autorisation à soutenir' => fn($r) => $r['soutenance_autoris'], + 'Est confidentielle' => fn($r) => $r['confidentielle'], + 'Résultat' => fn($r) => $r['resultat'], + 'Corrections' => fn($r) => $r['correc_autorisee'], + 'Thèse format PDF' => fn($r) => $r['depot_pdf'], + 'Annexe non PDF' => fn($r) => $r['depot_annexe'], + //Diffusion + 'Autorisation de MEL' => fn($r) => $r['autoris_mel'], + 'Embargo' => fn($r) => $r['autoris_embargo_duree'], + 'Refus de diffusion' => fn($r) => $r['autoris_motif'], + //Rapports + "Dernier rapport d'activité" => fn($r) => $r['dernier_rapport_activite'], + "Dernier rapport CSI" => fn($r) => $r['dernier_rapport_csi'], ]; $queryParams = $this->params()->fromQuery(); @@ -166,37 +110,40 @@ class ExportController extends AbstractController $this->theseSearchService->init(); $this->theseSearchService->processQueryParams($queryParams); $qb = $this->theseSearchService->getQueryBuilder(); - $theses = $qb->getQuery()->getResult(); + $qb->select('these'); // pas besoin de tout sélectionner, seuls les ids nous intéressent + $theses = $qb->getQuery()->getArrayResult(); + $thesesIds = array_map(fn(array $t) => $t['id'], $theses); // extraction des 'id' + + // on fragmente la liste des id pour éviter de dépasser le nombre maxi de termes autorisés dans un IN() + $wheres = array_map( + fn(string $ids) => "id in ($ids)", + array_map( + fn(array $ids) => implode(',', $ids), + array_chunk($thesesIds, 3000) + ) + ); + $sql = sprintf('select * from v_extract_theses where %s', implode(' or ', $wheres)); + try { + $records = $qb->getEntityManager()->getConnection()->executeQuery($sql)->fetchAllAssociative(); + } catch (Exception $e) { + throw new RuntimeException("Erreur rencontrée lors de l'exécution de la requête SQL", null, $e); + } - $records = []; - for ($i = 0 ; $i < count($theses) ; $i++) { - /** @var These $these */ - $these = $theses[$i]; - $record = []; - foreach($headers as $key => $fct) { - $variables = [ - 'these' => $these, - 'doctorant' => $these->getDoctorant(), - 'directeurs' => $these->getActeursByRoleCode(Role::CODE_DIRECTEUR_THESE), - 'co-directeurs' => $these->getActeursByRoleCode(Role::CODE_CODIRECTEUR_THESE), - 'co-encadrants' => $these->getActeursByRoleCode(Role::CODE_CO_ENCADRANT), - 'etablissement' => $these->getEtablissement(), - 'ecole doctorale' => $these->getEcoleDoctorale(), - 'unite de recherche' => $these->getUniteRecherche(), - 'version_initiale' => $these->hasVersionInitiale(), - 'version_corrigée' => $these->hasVersionCorrigee(), - 'annexe' => $these->hasAnnexe(), - ]; - $record[] = $fct($variables); + $data = []; + foreach ($records as $r) { + $row = []; + /** @var callable $fct */ + foreach ($headers as $fct) { + $row[] = $fct($r); } - $records[] = $record; + $data[] = $row; } $result = new CsvModel(); $result->setDelimiter(';'); - $result->setEnclosure('"'); + $result->setEnclosure('"'); // indispensable car il peut y avoir des ; dans les données $result->setHeader(array_keys($headers)); - $result->setData($records); + $result->setData($data); $result->setFilename('export_theses.csv'); return $result; diff --git a/module/Application/src/Application/Controller/UtilisateurController.php b/module/Application/src/Application/Controller/UtilisateurController.php index 7e5ea56fbb615894275a143652c9e1b6f636ef26..76de3e40a11974d36e5577b9f7a9fe5ecd923716 100644 --- a/module/Application/src/Application/Controller/UtilisateurController.php +++ b/module/Application/src/Application/Controller/UtilisateurController.php @@ -275,7 +275,7 @@ class UtilisateurController extends \UnicaenAuth\Controller\UtilisateurControlle $this->flashMessenger()->addSuccessMessage("Utilisateur <strong>{$utilisateur->getUsername()}</strong> créé avec succès."); - return $this->redirect()->toRoute('utilisateur'); + return $this->redirect()->toRoute('utilisateur/voir', ['utilisateur' => $utilisateur->getId()], [], true); } } diff --git a/module/Application/src/Application/Form/Validator/NewEmailValidator.php b/module/Application/src/Application/Form/Validator/NewEmailValidator.php index e584e31b4b98b88f86f648f739b8052effedc865..358d27f2df93e562d5b1d51072a5b2b46acc92e3 100644 --- a/module/Application/src/Application/Form/Validator/NewEmailValidator.php +++ b/module/Application/src/Application/Form/Validator/NewEmailValidator.php @@ -34,7 +34,7 @@ class NewEmailValidator extends AbstractValidator $perimetre = $this->getPerimetre(); if (in_array('utilisateur', $perimetre)) { - if ($this->entityManager->getRepository(Utilisateur::class)->findOneBy(['email' => $value]) !== null) { + if ($this->entityManager->getRepository(Utilisateur::class)->findOneBy(['username' => $value]) !== null) { $this->error(self::UTILISATEUR); $nb_pb++; } diff --git a/module/Depot/src/Depot/Service/FichierThese/FichierTheseServiceFactory.php b/module/Depot/src/Depot/Service/FichierThese/FichierTheseServiceFactory.php index 268145630d6b71c206269634345219a3421f320e..94888984678ecdf60033d6126554c9a463626145 100644 --- a/module/Depot/src/Depot/Service/FichierThese/FichierTheseServiceFactory.php +++ b/module/Depot/src/Depot/Service/FichierThese/FichierTheseServiceFactory.php @@ -65,6 +65,8 @@ class FichierTheseServiceFactory /** @var PageDeCouverturePdfExporter $pdcPdfExporter */ $pdcPdfExporter = $container->get(PageDeCouverturePdfExporter::class); $pdcPdfExporter + ->setMarginTop(5) + ->setMarginBottom(5) ->setTemplateFilePath($templateFilePath) ->setCssFilePath($cssFilePath); diff --git a/module/Formation/src/Formation/Service/Session/SessionService.php b/module/Formation/src/Formation/Service/Session/SessionService.php index 997192f1f52ef1cafff5cf2260771d9bdc497995..fccd16eafe547eba245b1aa5d72fb034d182e7b2 100644 --- a/module/Formation/src/Formation/Service/Session/SessionService.php +++ b/module/Formation/src/Formation/Service/Session/SessionService.php @@ -5,7 +5,8 @@ namespace Formation\Service\Session; use Application\Entity\Db\Utilisateur; use Application\Service\UserContextServiceAwareTrait; use DateTime; -use Doctrine\ORM\ORMException; +use Doctrine\ORM\Exception\NotSupported; +use Doctrine\ORM\Exception\ORMException; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\Query\Expr\Join; use Formation\Entity\Db\Etat; @@ -15,7 +16,7 @@ use Formation\Entity\Db\Seance; use Formation\Entity\Db\Session; use Formation\Entity\Db\SessionEtatHeurodatage; use Formation\Service\Formation\FormationServiceAwareTrait; -use UnicaenApp\Exception\RuntimeException; +use RuntimeException; use UnicaenApp\Service\EntityManagerAwareTrait; class SessionService { @@ -29,7 +30,11 @@ class SessionService { public function getRepository() : SessionRepository { /** @var SessionRepository $repo */ - $repo = $this->entityManager->getRepository(Session::class); + try { + $repo = $this->entityManager->getRepository(Session::class); + } catch (NotSupported $e) { + throw new RuntimeException("Un problème est survenu lors de la création du QueryBuilder de [".Session::class."]",0,$e); + } return $repo; } @@ -181,7 +186,13 @@ class SessionService { $heurodatage->setEtat($etat); $heurodatage->setHeurodatage(new DateTime()); $user = $this->userContextService->getIdentityDb(); - if ($user === null) $user = $this->getEntityManager()->getRepository(Utilisateur::class)->find(1); + if ($user === null) { + try { + $user = $this->getEntityManager()->getRepository(Utilisateur::class)->find(1); + } catch (NotSupported $e) { + throw new RuntimeException("Un erreur est survenu lors de la récupération de l'utilisateur d'id 1 (sygal-app)",0,$e); + } + } $heurodatage->setUtilisateur($user); try { diff --git a/module/Formation/view/formation/formation/afficher.phtml b/module/Formation/view/formation/formation/afficher.phtml index 0f9e8d82522e4a1cb2c15872b9bd7cd1a3387b8e..1bbc3bca27e0902ca8b2f07bc38447ca8335d2c9 100644 --- a/module/Formation/view/formation/formation/afficher.phtml +++ b/module/Formation/view/formation/formation/afficher.phtml @@ -115,16 +115,42 @@ $canSupprimerSession = $this->isAllowed(SessionPrivileges::getResourceId(Sess <h2> Liste des sessions </h2> -<?php if ($canAjouterSession) : ?> - <?php /** @see \Formation\Controller\SessionController::ajouterAction() */ ?> - <a href="<?php echo $this->url('formation/session/ajouter', ['formation' => $formation->getId()], [], true); ?>" - class="btn btn-primary action ajax-modal" data-event="modification" - title="Ajouter une session" - data-bs-toggle="tooltip" data-bs-html="true"> - <span class="icon icon-ajouter"></span> - Ajouter une session - </a> -<?php endif; ?> +<div class="row"> + <div class="col-md-12"> + + <?php if ($canAjouterSession) : ?> + <?php /** @see \Formation\Controller\SessionController::ajouterAction() */ ?> + <a href="<?php echo $this->url('formation/session/ajouter', ['formation' => $formation->getId()], [], true); ?>" + class="btn btn-primary action ajax-modal" data-event="modification" + title="Ajouter une session" + data-bs-toggle="tooltip" data-bs-html="true"> + <span class="icon icon-ajouter"></span> + Ajouter une session + </a> + <?php endif; ?> + + <?php + $mois = (new DateTime())->format('m'); + $anneeCourante = (new DateTime())->format('Y'); + if ($mois < 9) $anneeCourante--; + $anneeMin = null; + foreach ($sessions as $session) { + $anneeMin = ($anneeMin === null || $anneeMin > $session->getAnneeScolaire())?$session->getAnneeScolaire():$anneeMin; + } + ?> + + <div class="float-end"> + <label for="annee"> Filtre sur l'année :</label> + <select id="annee" name="annee"> + <?php for($annee=$anneeMin; $annee<=$anneeCourante; $annee++) : ?> + <option value="<?php echo $annee; ?>" <?php if ($annee == $anneeCourante) echo " selected "; ?> ><?php echo $annee; ?>/<?php echo ($annee+1); ?></option> + <?php endfor; ?> + </select> + </div> + + + </div> +</div> <div class="index-result"> <?php if (empty($sessions)) : ?> @@ -145,7 +171,7 @@ $canSupprimerSession = $this->isAllowed(SessionPrivileges::getResourceId(Sess </thead> <tbody> <?php foreach ($sessions as $session) : ?> - <tr> + <tr class="<?php echo $session->getAnneeScolaire(); ?>"> <td> <span class=" <?php if ($session->estHistorise()) echo "historise text-danger"; ?> "> <?php echo $session->getIndex(); ?> @@ -226,11 +252,22 @@ $canSupprimerSession = $this->isAllowed(SessionPrivileges::getResourceId(Sess <script> + function toggleAnnee() { + let anneeSelected = $('#annee option:selected').val(); + // alert(anneeSelected); + $('tbody tr').hide(); + $('tbody tr.' + anneeSelected).show(); + } + $(function() { + toggleAnnee(); $("body").on("modification", function (event) { event.div.modal('hide'); window.location.reload(); }); + + $("select#annee").on("change", toggleAnnee); + $("select#annee").selectpicker(); }); </script> diff --git a/module/Individu/config/individu.config.php b/module/Individu/config/individu.config.php index e721e1c10519f4fe4c1d6959d6a8afdef7b57ca6..e1bcbe5b8e60db38ad5aef49a4747aa046f27a53 100644 --- a/module/Individu/config/individu.config.php +++ b/module/Individu/config/individu.config.php @@ -3,6 +3,8 @@ namespace Individu; use BjyAuthorize\Provider\Resource\Config; +use Individu\Assertion\IndividuAssertion; +use Individu\Assertion\IndividuAssertionFactory; use Individu\Controller\IndividuController; use Individu\Controller\IndividuControllerFactory; use Individu\Form\IndividuForm; @@ -46,27 +48,27 @@ return [ [ 'controller' => IndividuController::class, 'action' => ['index', 'rechercher'], - 'privilege' => IndividuPrivileges::INDIVIDU_LISTER, + 'privileges' => IndividuPrivileges::INDIVIDU_LISTER, ], [ 'controller' => IndividuController::class, 'action' => ['voir'], - 'privilege' => IndividuPrivileges::INDIVIDU_CONSULTER, + 'privileges' => IndividuPrivileges::INDIVIDU_CONSULTER, ], [ 'controller' => IndividuController::class, 'action' => ['ajouter'], - 'privilege' => IndividuPrivileges::INDIVIDU_AJOUTER, + 'privileges' => IndividuPrivileges::INDIVIDU_AJOUTER, ], [ 'controller' => IndividuController::class, 'action' => ['modifier'], - 'privilege' => IndividuPrivileges::INDIVIDU_MODIFIER, + 'privileges' => IndividuPrivileges::INDIVIDU_MODIFIER, ], [ 'controller' => IndividuController::class, 'action' => ['supprimer', 'restaurer'], - 'privilege' => IndividuPrivileges::INDIVIDU_SUPPRIMER, + 'privileges' => IndividuPrivileges::INDIVIDU_SUPPRIMER, ], ], ], @@ -173,6 +175,7 @@ return [ 'factories' => [ IndividuService::class => IndividuServiceFactory::class, IndividuSearchService::class => IndividuSearchServiceFactory::class, + IndividuAssertion::class => IndividuAssertionFactory::class, ], 'aliases' => [ 'IndividuService' => IndividuService::class, diff --git a/module/Soutenance/view/soutenance/proposition/proposition.phtml b/module/Soutenance/view/soutenance/proposition/proposition.phtml index 7e1d1fd09af6c54c3857af482526b45e92399a88..7e923341dc26d2de91e9dc7e3d24988b20e83179 100644 --- a/module/Soutenance/view/soutenance/proposition/proposition.phtml +++ b/module/Soutenance/view/soutenance/proposition/proposition.phtml @@ -39,7 +39,7 @@ use These\Entity\Db\These; * * @var IndividuRole[] $ecoleResponsables * @var IndividuRole[] $uniteResponsables - * @var IndividuRole[] $etablissementResponsables + * @var string[] $emailsAspectDoctorats * @var bool $informationsOk * * @var $FORMULAIRE_DELOCALISATION @@ -87,7 +87,7 @@ echo $this->partial('partial/informations', [ 'directeurs' => $directeurs, 'uniteResponsables' => $uniteResponsables, 'ecoleResponsables' => $ecoleResponsables, - 'etablissementResponsables' => $etablissementResponsables, + 'emailsAspectDoctorats' => $emailsAspectDoctorats, 'canModifier' => $canModifier]); ?> diff --git a/module/These/config/others/co-encadrant.config.php b/module/These/config/others/co-encadrant.config.php index e09011838a0bb1173a1fb5a96985c48ebf7834b4..847b471567e0498880bd6092d2691dec3b1b3212 100644 --- a/module/These/config/others/co-encadrant.config.php +++ b/module/These/config/others/co-encadrant.config.php @@ -51,6 +51,7 @@ return [ 'options' => [ 'route' => '/co-encadrant', 'defaults' => [ + /** @see CoEncadrantController::indexAction() */ 'controller' => CoEncadrantController::class, 'action' => 'index', ], @@ -62,6 +63,7 @@ return [ 'options' => [ 'route' => '/historique[/:co-encadrant]', 'defaults' => [ + /** @see CoEncadrantController::historiqueAction() */ 'controller' => CoEncadrantController::class, 'action' => 'historique', ], @@ -72,6 +74,7 @@ return [ 'options' => [ 'route' => '/generer-justificatif-coencadrements/:co-encadrant', 'defaults' => [ + /** @see CoEncadrantController::genererJustificatifCoencadrementsAction() */ 'controller' => CoEncadrantController::class, 'action' => 'generer-justificatif-coencadrements', ], @@ -82,6 +85,7 @@ return [ 'options' => [ 'route' => '/generer-export-csv/:structure-type/:structure-id', 'defaults' => [ + /** @see CoEncadrantController::genererExportCsvAction() */ 'controller' => CoEncadrantController::class, 'action' => 'generer-export-csv', ], @@ -92,6 +96,7 @@ return [ 'options' => [ 'route' => '/rechercher-co-encadrant', 'defaults' => [ + /** @see CoEncadrantController::rechercherCoEncadrantAction() */ 'controller' => CoEncadrantController::class, 'action' => 'rechercher-co-encadrant', ], @@ -102,6 +107,7 @@ return [ 'options' => [ 'route' => '/ajouter-co-encadrant/:these', 'defaults' => [ + /** @see CoEncadrantController::ajouterCoEncadrantAction() */ 'controller' => CoEncadrantController::class, 'action' => 'ajouter-co-encadrant', ], @@ -112,6 +118,7 @@ return [ 'options' => [ 'route' => '/retirer-co-encadrant/:these/:co-encadrant', 'defaults' => [ + /** @see CoEncadrantController::retirerCoEncadrantAction() */ 'controller' => CoEncadrantController::class, 'action' => 'retirer-co-encadrant', ], diff --git a/module/These/src/These/Controller/CoEncadrantController.php b/module/These/src/These/Controller/CoEncadrantController.php index dc65b3ba850915b717b5434fee48bc384089a4b4..ffd08f1a9bd388760aadf40650c38ba8ec37c555 100644 --- a/module/These/src/These/Controller/CoEncadrantController.php +++ b/module/These/src/These/Controller/CoEncadrantController.php @@ -13,6 +13,8 @@ use Laminas\Mvc\Controller\AbstractActionController; use Laminas\View\Model\JsonModel; use Laminas\View\Model\ViewModel; use Laminas\View\Renderer\PhpRenderer; +use Mpdf\MpdfException; +use RuntimeException; use Structure\Entity\Db\EcoleDoctorale; use Structure\Entity\Db\UniteRecherche; use Structure\Service\EcoleDoctorale\EcoleDoctoraleServiceAwareTrait; @@ -21,11 +23,13 @@ use Structure\Service\UniteRecherche\UniteRechercheServiceAwareTrait; use These\Entity\Db\Acteur; use These\Entity\Db\These; use These\Form\CoEncadrant\RechercherCoEncadrantFormAwareTrait; +use These\Provider\Template\PdfTemplates; use These\Service\Acteur\ActeurServiceAwareTrait; use These\Service\CoEncadrant\CoEncadrantServiceAwareTrait; -use These\Service\CoEncadrant\Exporter\JustificatifCoencadrements\JustificatifCoencadrementPdfExporter; use These\Service\These\TheseServiceAwareTrait; use UnicaenApp\View\Model\CsvModel; +use UnicaenPdf\Exporter\PdfExporter as PdfExporter; +use UnicaenRenderer\Service\Rendu\RenduServiceAwareTrait; class CoEncadrantController extends AbstractActionController { @@ -38,15 +42,11 @@ class CoEncadrantController extends AbstractActionController use EcoleDoctoraleServiceAwareTrait; use EtablissementServiceAwareTrait; use UniteRechercheServiceAwareTrait; + use RenduServiceAwareTrait; - /** @var PhpRenderer */ - private $renderer; - - /** - * @param PhpRenderer $renderer - */ - public function setRenderer($renderer) + private ?PhpRenderer $renderer = null; + public function setRenderer(PhpRenderer $renderer): void { $this->renderer = $renderer; } @@ -55,7 +55,8 @@ class CoEncadrantController extends AbstractActionController { $form = $this->getRechercherCoEncadrantForm(); $form->setAttribute('action', $this->url()->fromRoute('co-encadrant', [], [], true)); - //todo !doit remonter un acteur + + /** @see CoEncadrantController::rechercherCoEncadrantAction() */ $form->setUrlCoEncadrant($this->url()->fromRoute('co-encadrant/rechercher-co-encadrant', [], [], true)); $form->get('bouton')->setLabel("Afficher l'historique de co-encadrement"); @@ -63,6 +64,7 @@ class CoEncadrantController extends AbstractActionController if ($request->isPost()) { $data = $request->getPost(); if ($data['co-encadrant']['id'] !== "") { + /** @see CoEncadrantController::historiqueAction() */ $this->redirect()->toRoute('co-encadrant/historique', ['co-encadrant' => $data['co-encadrant']['id']]); } } @@ -115,7 +117,7 @@ class CoEncadrantController extends AbstractActionController if (isset($data['co-encadrant']['id'])) { /** @var Individu $individu */ $individu = $this->getIndividuService()->getRepository()->find($data['co-encadrant']['id']); - $etablissement = (isset($data['etablissement']['id']) && $data['etablissement']['id'] !== '')?$this->getEtablissementService()->getRepository()->find($data['etablissement']['id']):null; + $etablissement = (isset($data['etablissement']['id']) && $data['etablissement']['id'] !== '') ? $this->getEtablissementService()->getRepository()->find($data['etablissement']['id']) : null; $this->getActeurService()->ajouterCoEncradrant($these, $individu, $etablissement); } } @@ -166,26 +168,62 @@ class CoEncadrantController extends AbstractActionController ]); } - public function genererJustificatifCoencadrementsAction(): void + public function genererJustificatifCoencadrementsAction(): ?string { $coencadrant = $this->getCoEncadrantService()->getRequestedCoEncadrant($this); $theses = $this->getTheseService()->getRepository()->fetchThesesByCoEncadrant($coencadrant->getIndividu()); - $logos = []; + $vars = [ + 'acteur' => $coencadrant, + ]; + + $listing = "<ul>"; + foreach ($theses as $these) { + //todo macro ou formateur ... + $listing .= "<li>"; + + $listing .= $these->getTitre(); + $listing .= " (" . $these->getAnneeUniv1ereInscription() . ")"; + + $listing .= "<br>"; + + $listing .= $these->getDoctorant()->getIndividu()->getPrenom1() . " " . $these->getDoctorant()->getIndividu()->getNomUsuel(); + $listing .= " - "; + $listing .= $these->getEtablissement()->getStructure()->getLibelle(); + $listing .= " - "; + $listing .= $these->getUniteRecherche()->getStructure()->getLibelle() . " (" . $these->getUniteRecherche()->getStructure()->getSigle() . ")"; + $listing .= "</li>"; + } + $listing .= "</ul>"; + try { - $logos['etablissement'] = $this->fichierStorageService->getFileForLogoStructure($coencadrant->getEtablissement()->getStructure()); + $logoCOMUE = $this->etablissementService->fetchEtablissementComue() ? $this->fichierStorageService->getFileForLogoStructure($this->etablissementService->fetchEtablissementComue()->getStructure()) : null; + $logoETAB = $coencadrant->getEtablissement() ? $this->fichierStorageService->getFileForLogoStructure($coencadrant->getEtablissement()->getStructure()) : null; } catch (StorageAdapterException $e) { - $logos['etablissement'] = null; + throw new RuntimeException("Un problème est survenu lors de la récupération de logo.", 0, $e); } + $logos = [ + "COMUE" => $logoCOMUE, + "ETAB" => $logoETAB, + ]; - //exporter - $export = new JustificatifCoencadrementPdfExporter($this->renderer, 'A4'); - $export->setVars([ - 'coencadrant' => $coencadrant, - 'theses' => $theses, - 'logos' => $logos, - ]); - $export->export('justificatif_coencadrement_' . $coencadrant->getIndividu()->getId() . ".pdf"); + $rendu = $this->getRenduService()->generateRenduByTemplateCode(PdfTemplates::COENCADREMENTS_JUSTIFICATIF, $vars); + $corps = str_replace("###LISTING_THESE###", $listing, $rendu->getCorps()); + $filename = 'justificatif_coencadrement_' . $coencadrant->getIndividu()->getId() . ".pdf"; + + $export = new PdfExporter(); + + try { + $export->getMpdf()->SetMargins(0, 0, 60); + //todo passer un header exploitant les logo +// $export->setHeaderScript('pdf/header.phtml', null, $logos); + $export->setHeaderScriptToNone(); + $export->setFooterScriptToNone(); + $export->addBodyHtml($corps); + return $export->export($filename); + } catch (MpdfException $e) { + throw new RuntimeException("Un problème est survenu lors de la génération du PDF", 0 , $e); + } } public function genererExportCsvAction(): CsvModel diff --git a/module/These/src/These/Controller/Factory/CoEncadrantControllerFactory.php b/module/These/src/These/Controller/Factory/CoEncadrantControllerFactory.php index 868c53facdfdd351645922223230e0da40a2defb..cc14777adf3e992d26e19bc384aff948e97f6d71 100644 --- a/module/These/src/These/Controller/Factory/CoEncadrantControllerFactory.php +++ b/module/These/src/These/Controller/Factory/CoEncadrantControllerFactory.php @@ -16,6 +16,7 @@ use These\Form\CoEncadrant\RechercherCoEncadrantForm; use These\Service\Acteur\ActeurService; use These\Service\CoEncadrant\CoEncadrantService; use These\Service\These\TheseService; +use UnicaenRenderer\Service\Rendu\RenduService; class CoEncadrantControllerFactory { @@ -35,15 +36,17 @@ class CoEncadrantControllerFactory * @var EtablissementService $etablissementService * @var IndividuService $individuService * @var FichierStorageService $fileService + * @var RenduService $renduService * @var TheseService $theseService * @var UniteRechercheService $uniteRechercheService - */ + */ $acteurService = $container->get(ActeurService::class); $coEncadrantService = $container->get(CoEncadrantService::class); $ecoleDoctoraleService = $container->get(EcoleDoctoraleService::class); $etablissementService = $container->get(EtablissementService::class); $individuService = $container->get(IndividuService::class); $fileService = $container->get(FichierStorageService::class); + $renduService = $container->get(RenduService::class); $theseService = $container->get('TheseService'); $uniteRechercheService = $container->get(UniteRechercheService::class); @@ -62,6 +65,7 @@ class CoEncadrantControllerFactory $controller->setEtablissementService($etablissementService); $controller->setIndividuService($individuService); $controller->setFichierStorageService($fileService); + $controller->setRenduService($renduService); $controller->setTheseService($theseService); $controller->setUniteRechercheService($uniteRechercheService); $controller->setRechercherCoEncadrantForm($rechercheCoEncadrantForm); diff --git a/module/These/src/These/Entity/Db/Acteur.php b/module/These/src/These/Entity/Db/Acteur.php index 0c9a0d6dd5ee3c08a3512743203f7739f793a439..840f995372762067d5d85f5be297e6f79a520eac 100644 --- a/module/These/src/These/Entity/Db/Acteur.php +++ b/module/These/src/These/Entity/Db/Acteur.php @@ -278,7 +278,7 @@ class Acteur implements HistoriqueAwareInterface, ResourceInterface, IndividuRol /** * @return string qualite */ - public function getQualite() + public function getQualite(): string { if ($this->qualite === null) { return " "; @@ -366,4 +366,18 @@ class Acteur implements HistoriqueAwareInterface, ResourceInterface, IndividuRol { return $this->membre; } + + /** FONCTION POUR LES MACROS **************************************************************************************/ + + /** @noinspection PhpUnused */ + public function getDenomination(): string + { + return $this->getIndividu()->getNomComplet(false, false, false, true); + } + + /** @noinspection PhpUnused */ + public function getEtablissementAsLibelle(): string + { + return ($this->getEtablissement())?$this->getEtablissement()->getStructure()->getLibelle():"<span style='background:darkred;'>Aucun établissement</span>"; + } } diff --git a/module/These/src/These/Entity/Db/Repository/TheseRepository.php b/module/These/src/These/Entity/Db/Repository/TheseRepository.php index 83c3f9baba0866e50418e6ea877697d76659496d..f7b731101231f2ca835aa3a700a8a0a26bc9c2b8 100644 --- a/module/These/src/These/Entity/Db/Repository/TheseRepository.php +++ b/module/These/src/These/Entity/Db/Repository/TheseRepository.php @@ -196,7 +196,7 @@ class TheseRepository extends DefaultEntityRepository * @param Individu $individu * @return These[] */ - public function fetchThesesByCoEncadrant($individu) + public function fetchThesesByCoEncadrant(Individu $individu): array { $qb = $this->createQueryBuilder('t') ->join('t.acteurs', 'a') diff --git a/module/These/src/These/Form/CoEncadrant/RechercherCoEncadrantForm.php b/module/These/src/These/Form/CoEncadrant/RechercherCoEncadrantForm.php index 58a18d815cfe282fe93f0243e33d7e7b0d3c7148..1863c44ff1d1063f227caea3ddae07d52bfe7d80 100644 --- a/module/These/src/These/Form/CoEncadrant/RechercherCoEncadrantForm.php +++ b/module/These/src/These/Form/CoEncadrant/RechercherCoEncadrantForm.php @@ -7,7 +7,8 @@ use Laminas\Form\Form; use Laminas\InputFilter\Factory; use UnicaenApp\Form\Element\SearchAndSelect; -class RechercherCoEncadrantForm extends Form { +class RechercherCoEncadrantForm extends Form +{ private ?string $urlCoEncadrant = null; private ?string $urlEtablissement = null; @@ -17,6 +18,7 @@ class RechercherCoEncadrantForm extends Form { $this->urlCoEncadrant = $urlCoEncadrant; $this->get('co-encadrant')->setAutocompleteSource($this->urlCoEncadrant); } + public function setUrlEtablisssement(string $urlEtablissement): void { $this->urlEtablissement = $urlEtablissement; @@ -64,8 +66,8 @@ class RechercherCoEncadrantForm extends Form { ]); $this->setInputFilter((new Factory())->createInputFilter([ - 'co-encadrant' => [ 'required' => true ], - 'etablissement' => [ 'required' => false ], + 'co-encadrant' => ['required' => true], + 'etablissement' => ['required' => false], ])); } } \ No newline at end of file diff --git a/module/These/src/These/Provider/Template/PdfTemplates.php b/module/These/src/These/Provider/Template/PdfTemplates.php new file mode 100644 index 0000000000000000000000000000000000000000..ae5053b528e99ce543defc55896dc47b8c3b4852 --- /dev/null +++ b/module/These/src/These/Provider/Template/PdfTemplates.php @@ -0,0 +1,8 @@ +<?php + +namespace These\Provider\Template; + +class PdfTemplates { + const COENCADREMENTS_JUSTIFICATIF = "COENCADREMENTS_JUSTIFICATIF"; + +} diff --git a/module/These/src/These/Service/CoEncadrant/CoEncadrantServiceFactory.php b/module/These/src/These/Service/CoEncadrant/CoEncadrantServiceFactory.php index 2a66439963db9b032e6271853b372030ffa0fdab..d9084f081c5fa23fe89e15c0b33c2f3aa47cdbec 100644 --- a/module/These/src/These/Service/CoEncadrant/CoEncadrantServiceFactory.php +++ b/module/These/src/These/Service/CoEncadrant/CoEncadrantServiceFactory.php @@ -7,7 +7,8 @@ use Interop\Container\ContainerInterface; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; -class CoEncadrantServiceFactory { +class CoEncadrantServiceFactory +{ /** * @param ContainerInterface $container @@ -15,7 +16,7 @@ class CoEncadrantServiceFactory { * @throws ContainerExceptionInterface * @throws NotFoundExceptionInterface */ - public function __invoke(ContainerInterface $container) : CoEncadrantService + public function __invoke(ContainerInterface $container): CoEncadrantService { /** * @var EntityManager $entityManager diff --git a/module/These/src/These/Service/CoEncadrant/Exporter/JustificatifCoencadrements/JustificatifCoencadrementPdfExporter.php b/module/These/src/These/Service/CoEncadrant/Exporter/JustificatifCoencadrements/JustificatifCoencadrementPdfExporter.php deleted file mode 100644 index 92440a6d91a359390aa1f68a5c2c7e6c6e6ea15c..0000000000000000000000000000000000000000 --- a/module/These/src/These/Service/CoEncadrant/Exporter/JustificatifCoencadrements/JustificatifCoencadrementPdfExporter.php +++ /dev/null @@ -1,36 +0,0 @@ -<?php - -namespace These\Service\CoEncadrant\Exporter\JustificatifCoencadrements; - -use Laminas\View\Renderer\PhpRenderer; -use Laminas\View\Resolver\TemplatePathStack; -use UnicaenApp\Exporter\Pdf as PdfExporter; - -class JustificatifCoencadrementPdfExporter extends PdfExporter -{ - private $vars; - - public function setVars(array $vars) - { - $this->vars = $vars; - $this->vars['exporter'] = $this; - - return $this; - } - - public function __construct(PhpRenderer $renderer = null, $format = 'A4', $orientationPaysage = false, $defaultFontSize = 10) - { - parent::__construct($renderer, $format, $orientationPaysage, $defaultFontSize); - $resolver = $renderer->resolver(); - $resolver->attach(new TemplatePathStack(['script_paths' => [__DIR__]])); - } - - public function export($filename = null, $destination = self::DESTINATION_BROWSER, $memoryLimit = null) - { -// $this->addBodyHtml('<style>' . file_get_contents(APPLICATION_DIR . '/public/css/page-unicaen.css') . '</style>'); - $this->setHeaderScript('empty.phtml'); - $this->setFooterScript('footer.phtml'); - $this->addBodyScript('justificatif-coencadrements.phtml', false, $this->vars); - return PdfExporter::export($filename, $destination, $memoryLimit); - } -} \ No newline at end of file diff --git a/module/These/src/These/Service/CoEncadrant/Exporter/JustificatifCoencadrements/empty.phtml b/module/These/src/These/Service/CoEncadrant/Exporter/JustificatifCoencadrements/empty.phtml deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/module/These/src/These/Service/CoEncadrant/Exporter/JustificatifCoencadrements/footer.phtml b/module/These/src/These/Service/CoEncadrant/Exporter/JustificatifCoencadrements/footer.phtml deleted file mode 100644 index 50210cd1dd15d930b1c606f86504cd2b9de0e436..0000000000000000000000000000000000000000 --- a/module/These/src/These/Service/CoEncadrant/Exporter/JustificatifCoencadrements/footer.phtml +++ /dev/null @@ -1,22 +0,0 @@ -<?php - -$date = new DateTime(); -$lieu = "l'Université de Caen Normandie"; -?> - - -<table> - <tr> - <td> -<!-- Direction de la recherche et de l'innovation - Pôle formation doctorale<br/>--> -<!-- Maison du doctorat de --><?php //echo $lieu; ?> - </td> - <td> - - </td> - <td style="text-align:right;"> - Généré par <?php echo $this->appInfos()->nom ?> <br/> - Le <?php echo $date->format('d/m/Y à H:i:s'); ?> - </td> - </tr> -</table> diff --git a/module/These/src/These/Service/CoEncadrant/Exporter/JustificatifCoencadrements/justificatif-coencadrements.phtml b/module/These/src/These/Service/CoEncadrant/Exporter/JustificatifCoencadrements/justificatif-coencadrements.phtml deleted file mode 100644 index 6ee4521bbcf1547bb846d9b18708cbd8d88b7f36..0000000000000000000000000000000000000000 --- a/module/These/src/These/Service/CoEncadrant/Exporter/JustificatifCoencadrements/justificatif-coencadrements.phtml +++ /dev/null @@ -1,337 +0,0 @@ -<?php - -use Application\View\Renderer\PhpRenderer; -use These\Entity\Db\Acteur; -use These\Entity\Db\These; - -/** - * @see \These\Service\CoEncadrant\Exporter\JustificatifCoencadrements\JustificatifCoencadrementPdfExporter - * @var PhpRenderer $this - * @var Acteur $coencadrant - * @var These[] $theses - * @var array $logos - */ -?> - -<style> - body { - font-size: 9pt; - } - - span.warning { - font-weight: bold; - color: darkred; - } - - img { - height:2.5cm; - } - - h1 { - font-size: x-large; - } - h2 { - font-size: large; - } - table { - width:100%; - } - - table.recapitulatif { - border:solid 1px black; - } - - table.recapitulatif td.head { - font-weight: bold; - width: 33.3% - } - - table.composition { - border-collapse: collapse; - } - - table.composition th{ - border-bottom:solid 2px black; - } - - table.composition td{ - border-bottom:solid 1px gray; - } - - table.composition tbody tr { - border-bottom: 1px gray solid ; - } - - table.informations { - } - - table.informations td.head { - width: 50% - } - - table.informations td.info { - text-align: right; - } - - table.validation { - border-collapse: collapse; - } - - table.validation th{ - border-bottom:solid 2px black; - } - - table.validation td{ - border-bottom:solid 1px gray; - margin: 1rem; - } - - span.to-complete { - background-color: pink; - color: darkred; - } - - div.signature { - position:relative; - /*top: 80%;*/ - left:500px; - } - -</style> - -<!-- SECTION DU LOGO DE LA COMUE --------------------------------------------------------------------------------------> - -<div> - <div style="width:25%; position:absolute; top: 20px; left: 20px "> - <?php if ($logos['etablissement'] !== null): ?> - <img src="<?php echo $logos['etablissement']; ?>" /> - <?php else : ?> - <span style='background-color:red;'> - Logo ETAB manquant - </span> - <?php endif; ?> - </div> - - <h1 style="text-align:center; position:absolute; top: 60px; left: 30%" > - Justificatif de co-encadrements - </h1> -</div> - -<!-- Presentation du co-encdrant --------------------------------------------------------------------------------------> - -<p> - Ce document certifie que <?php echo $coencadrant->getIndividu()->getPrenom1(); ?> <?php echo $coencadrant->getIndividu()->getNomUsuel(); ?>, - actuellement <?php echo ($coencadrant->getQualite() !== " ")?$coencadrant->getQualite():""; ?> à - <?php echo ($coencadrant->getEtablissement())?$coencadrant->getEtablissement()->getStructure()->getLibelle():"<span style='color:darkred;'>établissement manquant</span>"; ?>, - a assuré la fonction de co-encadrant sur pour les thèses suivantes : -</p> - -<ul> -<?php foreach ($theses as $these) : ?> - <li> - <?php echo $these->getTitre(); ?> - (<?php echo $these->getAnneeUniv1ereInscription(); ?>) - <br/> - <?php echo $these->getDoctorant()->getIndividu()->getPrenom1(); ?> - <?php echo $these->getDoctorant()->getIndividu()->getNomUsuel(); ?> - - - <?php echo $these->getEtablissement()->getStructure()->getLibelle(); ?> - - - <?php echo $these->getUniteRecherche()->getStructure()->getLibelle(); ?> (<?php echo $these->getUniteRecherche()->getStructure()->getSigle(); ?>) - </li> -<?php endforeach; ?> -</ul> - -<!--<br/>--> -<!--<br/>--> -<!--<br/>--> -<!--<br/>--> -<!----> -<!--<h2 style="text-align:center;">--> -<!-- Désignation des rapporteurs et des membres du jury--> -<!-- <br/>--> -<!-- Autorisation de soutenance de doctorat--> -<!-- <br/>--> -<!-- Avis de soutenance--> -<!--</h2>--> -<!----> -<!-- <br/>--> -<!-- <br/>--> -<!----> -<!--<p>--> -<!-- <strong>--> -<!-- --><?php //if ($informations->getDoctorant() !== null): ?> -<!-- --><?php //echo $informations->getDoctorant(); ?> -<!-- --><?php //else : ?> -<!-- <span style='background-color:red;'>--> -<!-- Doctorant manquant--> -<!-- </span>--> -<!-- --><?php //endif; ?> -<!-- </strong>--> -<!-- présente ses travaux en soutenance le--> -<!-- <strong>--> -<!-- --><?php //if ($informations->getDate() !== null): ?> -<!-- --><?php //echo $informations->getDate(); ?> -<!-- --><?php //else : ?> -<!-- <span style='background-color:red;'>--> -<!-- Date manquante--> -<!-- </span>--> -<!-- --><?php //endif; ?> -<!-- </strong>--> -<!-- à l'adresse suivante : <br/>--> -<!-- --><?php //if ($proposition->getAdresse() !== null): ?> -<!-- --><?php //echo $proposition->getAdresse(); ?> -<!-- --><?php //else : ?> -<!-- <span style='background-color:red;'>--> -<!-- Adresse manquante--> -<!-- </span>--> -<!-- <br/>--> -<!-- --><?php //endif; ?> -<!-- en vue de l'obtention du diplôme de <strong>Doctorat spécialité--> -<!----> -<!-- --><?php //if ($informations->getSpecialite() !== null): ?> -<!-- --><?php //echo $informations->getSpecialite(); ?><!--.--> -<!-- --><?php //else: ?> -<!-- <span style='background-color:red;'> Spécialité manquante. </span>--> -<!-- --><?php //endif; ?> -<!-- </strong>--> -<!--</p>--> -<!----> -<!--<p>--> -<!-- La soutenance--> -<!-- --><?php //if ($proposition && $proposition->isHuitClos() !== null): ?> -<!-- --><?php //if ($proposition->isHuitClos()) : ?> -<!-- se déroulera en huis clos.--> -<!-- --><?php //else : ?> -<!-- est public.--> -<!-- --><?php //endif ; ?> -<!-- --><?php //else: ?> -<!-- <span style='background-color:red;'> information sur l'aspect public manquante </span>--> -<!-- --><?php //endif; ?> -<!--</p>--> -<!----> -<!--<br/>--> -<!--<br/>--> -<!----> -<!-- <table class='jury'>--> -<!-- <tr>--> -<!-- <th colspan='3'>--> -<!-- Information sur la thèse--> -<!-- </th>--> -<!-- </tr>--> -<!-- <tr>--> -<!-- <td>Titre :</td>--> -<!-- <td>--> -<!-- --><?php //if ($informations->getTitre() !== null): ?> -<!-- --><?php //echo $informations->getTitre(); ?> -<!-- --><?php //else: ?> -<!-- <span style='background-color:red;'> Aucun titre </span>--> -<!-- --><?php //endif; ?> -<!-- </td>--> -<!-- </tr>--> -<!-- <tr>--> -<!-- <td>École doctorale </td>--> -<!-- <td>--> -<!-- --><?php //if ($informations->getEcoleDoctorale() !== null): ?> -<!-- --><?php //echo $informations->getEcoleDoctorale(); ?> -<!-- --><?php //else: ?> -<!-- <span style='background-color:red;'> École doctorale manquante</span>--> -<!-- --><?php //endif; ?> -<!-- </td>--> -<!-- </tr>--> -<!-- <tr>--> -<!-- <td>Unité de recherche </td>--> -<!-- <td>--> -<!-- --><?php //if ($informations->getUniteRecherche() !== null): ?> -<!-- --><?php //echo $informations->getUniteRecherche(); ?> -<!-- --><?php //else: ?> -<!-- <span style='background-color:red;'> Unité de recherche manquante</span>--> -<!-- --><?php //endif; ?> -<!-- </td>--> -<!-- </tr>--> -<!-- --><?php -// /** -// * @var Acteur[] $directeurs -// * @var Acteur[] $codirecteurs -// */ -// $directeurs = $informations->getDirecteurs(); -// $codirecteurs = $informations->getCodirecteurs(); -// ?> -<!----> -<!-- <tr>--> -<!-- <td>Directeur :</td>--> -<!-- <td>--> -<!-- --><?php //$first = true; ?> -<!-- --><?php //foreach ($directeurs as $directeur) : ?> -<!-- --><?php //if (!$first): ?> -<!-- <br/>--> -<!-- --><?php //endif; ?> -<!-- --><?php -// $first = false; -// $denomination = $directeur->getIndividu()->getNomComplet(true, true, false, true); -// $qualite = $directeur->getQualite(); -// ?> -<!-- --><?php //echo $denomination . ", ".$qualite; ?> -<!-- --><?php //endforeach; ?> -<!-- </td>--> -<!-- </tr>--> -<!-- --><?php //if (!empty($informations->getCodirecteurs())) : ?> -<!-- <tr>--> -<!-- <td>Co-directeur(s) :</td>--> -<!-- <td>--> -<!-- --><?php //$first = true; ?> -<!-- --><?php //foreach ($codirecteurs as $directeur) : ?> -<!-- --><?php //if (!$first): ?> -<!-- <br/>--> -<!-- --><?php //endif; ?> -<!-- --><?php -// $first = false; -// $denomination = $directeur->getIndividu()->getNomComplet(true, true, false, true); -// $qualite = $directeur->getQualite(); -// ?> -<!-- --><?php //echo $denomination . ", ".$qualite; ?> -<!-- --><?php //endforeach; ?> -<!-- </td>--> -<!-- </tr>--> -<!-- --><?php //endif; ?> -<!--</table>--> -<!----> -<!--<br/>--> -<!--<br/>--> - - <!-- SECTION JURY -----------------------------------------------------------------------------------------------------> - -<!-- <table class='jury'>--> -<!-- <tr>--> -<!-- <th colspan='3'>--> -<!-- Composition du jury--> -<!-- </th>--> -<!-- </tr>--> -<!----> -<!-- --><?php //foreach ($informations->getActeursEnCouverture() as $acteur) : ?> -<!-- <tr>--> -<!-- <td> --><?php //echo $acteur->getDenomination(); ?><!-- </td>--> -<!-- <td> --><?php //echo trim($acteur->getQualite()); ?><!--, --><?php //echo $acteur->getEtablissement(); ?><!--</td>--> -<!-- <td> --><?php //echo $acteur->getRole(); ?><!-- </td>--> -<!-- </tr>--> -<!-- --><?php //endforeach; ?> -<!----> -<!-- </table>--> -<!----> -<!----> -<!--<br/>--> -<!--<br/>--> - - <!-- Signature ----------------------------------------------------------------------------------------------------> - -<!--<table>--> -<!-- <tr>--> -<!-- <td width="60%"></td>--> -<!-- <td>--> -<!-- Fait à ................., le ........................<br/>--> -<!-- Pour le Président et p.o.<br/>--> -<!-- Le Vice-Président Recherche--> -<!-- </td>--> -<!-- </tr>--> -<!--</table>--> - diff --git a/module/These/view/these/co-encadrant/partial/table-these.phtml b/module/These/view/these/co-encadrant/partial/table-these.phtml index 0f3e273eaa21d91cbbfe51f1b06a0562396f81f6..342601632b2632ea26b3f67affc7eda1f0b1c5aa 100644 --- a/module/These/view/these/co-encadrant/partial/table-these.phtml +++ b/module/These/view/these/co-encadrant/partial/table-these.phtml @@ -43,6 +43,7 @@ use These\Entity\Db\These; <?php echo $these->getAnneeUniv1ereInscription(); ?> </td> <td> + <?php /** @see \These\Controller\TheseController::detailIdentiteAction() */ ?> <a href="<?php echo $this->url('these/identite', ['these' => $these->getId()], [], true); ?>"> <span class="icon icon-voir"></span> </a> diff --git a/module/These/view/these/pdf/header.phtml b/module/These/view/these/pdf/header.phtml new file mode 100644 index 0000000000000000000000000000000000000000..fc66f87f14dad5930c8cb6f42c9711747626483e --- /dev/null +++ b/module/These/view/these/pdf/header.phtml @@ -0,0 +1 @@ +Choucroute \ No newline at end of file