Commit 584a3a4f authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

Module Substitutions : amélioration de fonctions pgsql du moteur de substitutions.

parent 39a905de
Loading
Loading
Loading
Loading
+1 −0
Changes for CHANGELOG.md: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ Journal des modifications
- Rapports d'activité : initialisation du formulaire de création d'un nouveau rapport avec les formations suivies (module Formation).
- Stockage de fichier S3/Filesystem : plus de copie sur disque dans le cas d'une demande d'un fichier issu du Filesystem.
- Inclusion au script de purge des fichiers temporaires ceux générés par le FichierStorageService.
- Module Substitutions : amélioration de fonctions pgsql du moteur de substitutions.
- [FIX] Module Substitutions : plantage de la page consacrée aux doublons (substitutions possibles). 
- [FIX] Page Assistance : plantage de la page lorsque le rôle de l'utilisateur est structure-dépendant.

+112 −0
Changes for data/SQL/substitutions.sql: 112 added lines, 0 removed lines.
Original line number Diff line number Diff line
--======================================================================================================================
--                  MODIFICATION DU FONCTIONNEMENT DE LA SUBSTITUTION D'INDIVIDU ET DE DOCTORANT
------------------------------------------------------------------------------------------------------------------------
-- On ne veut plus que soit possible la substitution de 2 individus dont les doctorants liés
-- ne sont pas eux-mêmes substitués.
--======================================================================================================================


-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
--                                     ! Idée abandonnée !
--
-- Ça a quand même du sens que les individus soient substitués indépendemment du fait qu'ils
-- soient des individus "purs" (acteur) ou des doctorants ou les 2. On peut même imaginer que
-- ça soit utile utile de savoir qu'un acteur donné a été doctorant.
-- Pour régler le "pb" des 2 doctorants non substitués (car INE différents) alors que leurs
-- individus respectifs le sont (car même nom,prénom,ddn) qui faisait couiner la recherche de
-- doctorant par individu_id (car 2 doctorants liés au même individu substituant), on ne lève
-- plus d'exception et on prend le doctorant le plus "récent". Sachant que :
--   - 1/ ce cas de doctroants non substitués alors que leurs individus respectifs le sont, est
--     aberrant donc improbable (et pour s'en sortir, on a forcé ne NPD d'un des doctorants).
--   - 2/ il faudrait s'arranger pour ne plus avoir à faire de recherche de doctorant par individu_id,
--     en s'assurant que l'on référence là où il faut un doctorant et pas un individu.
--
-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!


--
-- Suppression de toutes les substitutions de doctorants, en forçant le NPD.
--
update doctorant d set npd_force = substit_npd_doctorant(d)||'-zzz-'||d.id
from substit_doctorant sub
where d.id = sub.from_id
  and npd_force is null
; ---------------> 12min

--
-- Verif absence de substitutions de doctorants.
--
select * from substit_doctorant order by npd ;

--
-- Modif manuelle du "NPD forcé" *s'il est null* pour retirer des substitutions d'individus les individus étant
-- des doctorants.
--
update individu i set npd_force = substit_npd_individu(i)||'-zzz-'||i.id
where npd_force IS NULL and id in (
    select i.id from individu i
                         join substit_individu sub on i.id = sub.from_id
    where type = 'doctorant'
); ---------------> 24min (sur bdd locale)

--
-- Verif absence de substitutions d'individus étant aussi des doctorants.
--
select * from substit_individu sub join individu i on sub.from_id = i.id and i.type = 'doctorant';

--
-- Impossibilités de supprimer des substituants car ils sont référencés dans d'autres tables (ex: validation, acteur) ?
--
select * from substit_log where type = 'doctorant' and operation = 'SUBSTITUANT_SUPPR_PROBLEM';
select * from substit_log where type = 'individu' and operation = 'SUBSTITUANT_SUPPR_PROBLEM';


--
-- recherche de cobayes : individus à la fois acteur et doctorant
--
select nom_patronymique, prenom1, sum(count_doctorant) as count_doctorant, sum(count_acteur) as count_acteur
from (
         select nom_patronymique, prenom1, type, 0 as count_doctorant, count(*) count_acteur from individu where type = 'acteur' and source_id <> 1 group by nom_patronymique, prenom1, type union
         select nom_patronymique, prenom1, type, count(*) count_doctorant, 0 as count_acteur from individu where type = 'doctorant' and source_id <> 1 group by nom_patronymique, prenom1, type
     ) tmp
group by nom_patronymique, prenom1
having sum(count_doctorant) > 0 and sum(count_acteur) > 0 and sum(count_doctorant) + sum(count_acteur) > 2;

--
-- cobaye 1
--
select substit_npd_individu(i)npd,id,type,nom_patronymique,prenom1,date_naissance,source_code,email,npd_force
    from individu i where nom_patronymique = 'XXXXX' and prenom1 ilike '%Yyyyy%' order by type;
alter table individu disable trigger substit_trigger_individu;
alter table substit_individu disable trigger substit_trigger_on_substit_individu;
update individu set npd_force = null where id = 1122;
update individu set npd_force = null where id = 1011; -------------------------------> ça fonctionne : les individu-doctrants 1122 et 1011 ne sont pas substitués
select * from v_individu_doublon where npd = 'bentahar_omar_19831007'; -- 37995
update individu set npd_force = 'lsdfjlmsdqjfmlqsdjfqsldkfj' where id in (1198707);
select * from v_individu_doublon where nom_patronymique = 'XXXXX';
alter table individu enable trigger substit_trigger_individu;
alter table substit_individu enable trigger substit_trigger_on_substit_individu;

--
-- cobaye 2
--
select substit_npd_individu(i)npd,id,type,nom_patronymique,prenom1,date_naissance,source_code,email,npd_force
    from individu i where nom_patronymique = 'XXXXX' and prenom1 ilike '%Yyyyyy%' order by type;
select * from individu where id = 1200286; -- substituait les individus 37995,18879
select * from acteur where individu_id = 1200286;
select * from acteur where individu_id in (37995,18879); -- substituait les individus 37995,18879

select i.* from individu i join substit_individu sub on i.id = sub.from_id where to_id = 1199128;

alter table individu disable trigger substit_trigger_individu;
alter table substit_individu disable trigger substit_trigger_on_substit_individu;
update individu set date_naissance = '1975-11-19 00:00:00.000000' where id = 1187822;
update individu set npd_force = null where id = 18879;
select * from v_individu_doublon where nom_patronymique = 'XXXXX'; -- 37995
update individu set npd_force = 'lsdfjlmsdqjfmlqsdjfqsldkfj' where id in (18879);
select * from v_individu_doublon where nom_patronymique = 'XXXXX';
alter table individu enable trigger substit_trigger_individu;
alter table substit_individu enable trigger substit_trigger_on_substit_individu;


select * from substit_individu sub join individu i on sub.from_id = i.id and i.type = 'doctorant';
+68 −0
Changes for doc/release-notes/v7.1.0.md: 68 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -18,6 +18,10 @@
## 2. Dans la base de données

```postgresql
--
-- Restauration des valeurs originales de clés étrangères :
-- modif pour n'afficher une notice qu'en cas de remplacements faits (et pas systématiquement).
--
create or replace function substit_restore_foreign_key_value(p_type varchar, p_tab_name varchar, p_col_name varchar, p_from_id bigint, p_to_id bigint) returns int
    language plpgsql
as
@@ -54,4 +58,68 @@ begin
    return v_count;
end
$$;

--
-- Modification de la fonction de suppression d'une substitution 'individu' :
-- en cas d'échec de la suppression du substituant à cause d'une contrainte d'intégrité (i.e. il est référencé
-- dans d'autres tables) :
--   - dans le cas où il ne reste qu'1 substitué dans la substitution on remplace partout l'id du substituant
--     par celui du dernier substitué, ce qui nous permettra ensuite de procéder à la suppression prévue.
--   - sinon, on logue simplement le problème.
--
create or replace function substit_delete_substitution(type character varying, p_substituant_id bigint) returns void
  language plpgsql
as
$$declare
  v_count int;
  v_message text;
  v_stack text;
  v_substit record;
begin
  --
  -- Supprime une substitution, spécifiée par l'enregistrement substituant.
  --

  raise notice 'Suppression du substituant % et de la substitution associée...', p_substituant_id;

  execute format('select count(*) from substit_%s where to_id = %s', type, p_substituant_id) into v_count;

  begin
    -- NB : la suppression déclenche le trigger de la table 'substit_%s'
    execute format('delete from substit_%s where to_id = %s', type, p_substituant_id);
    perform substit_insert_log(type, 'SUBSTITUTION_SUPPR', null, p_substituant_id, null,
                               format('Suppression des %s substitutions par %s', v_count, p_substituant_id));

    execute format('delete from %I where id = %s', type, p_substituant_id);
    perform substit_insert_log(type, 'SUBSTITUANT_SUPPR', null, p_substituant_id, null,
                               format('Suppression du substituant %s', p_substituant_id));

  exception WHEN integrity_constraint_violation THEN
    -- échec de la suppression du substituant à cause d'une contrainte d'intégrité (i.e. il est référencé
    -- dans d'autres tables) : cela annule tout ce qui est entre `begin` et `exception`.
    v_message = format('Suppression du substituant %s impossible car il est utilisé dans au moins une table ' ||
                       '(contrainte d''intégrité) : %L', p_substituant_id, v_stack);
    raise notice '%', v_message;

    if v_count = 1 then
      -- dans le cas où il ne reste qu'1 substitué dans la substitution on remplace partout l'id du substituant
      -- par celui du dernier substitué, ce qui nous permettra ensuite de procéder à la suppression prévue.
      raise notice 'Un seul substitué restant donc remplacement de l''id du substituant par l''id du substitué...';
      -- remplacement de l'id du substituant par l'id du dernier substitué restant
      execute format('select * from substit_%s where to_id = %s limit 1', type, p_substituant_id) into v_substit;
      select substit_replace_foreign_keys_values(type, p_substituant_id, v_substit.from_id) into v_count;
      -- ensuite on peut supprimer le substituant
      perform substit_delete_substitution(type, p_substituant_id);
    else
      -- sinon, on logue simplement le problème.
      GET STACKED DIAGNOSTICS v_stack = MESSAGE_TEXT;
      perform substit_insert_log(type, 'SUBSTITUANT_SUPPR_PROBLEM', null, p_substituant_id, null, v_message);
    end if;
  end;

  raise notice '=> Terminé.';
end
$$;


```