🎬 Passer en mode présentation

Editique

Objectif :

Comprendre comment cela fonctionne pour facilité les US / DE sur l'éditique et pouvoir faire évoluer si besoin.

Shu-Ha-Ri :

  • Comprendre
  • S'approprier et critiquer
  • Faire évoluer

Historique

  • Première version d'éditique
    • Front envoie toutes les données nécessaires
    • Back construit un objet unique avec tous les champs de fusions (présent ou non dans le document à éditer)
    • Quelques documents sont implémentés avec cette version

Conception socle

  • La seconde version d'éditique :
    • le socle fournit un service pour récupérer la liste des editions
    • le socle founit un service pour récupérer une map de champs de fusion pour une liste de modèles
    • le socle ne veut uniquement que les champs de fusion nécessaire à l'édition du document

Conception DH Patient

Indépendant du document à éditer.

Le découpage favorise la modification en limitant les impactes afin d'itérer sur le remaniement de code avec la montée en complexité d'un module comme l'éditique.

Pré-requis

  • 3 modèles maximum : le premier esr le principal et les 2 autres sont des modèles secondaires contenus dans le principal
  • Un modèle d'édition === liste de champs de fusion
  • Soit on édite un objet, soit une liste d'objets
  • Limite : le principal est obligatoirement un objet, seul les modèles secondaires peuvent être des listes d'objets. Besoin d'une évolution si le besoin existe.

Moteur de fusion

  • recherche les modèles par uuid
  • recherche les champs de fusion par uuid
  • récupération des métadonnées de champs de fusion
  • récupération des valeurs des champs de fusion
  • Création de l'objet de retour
DonneesEditionGetterEditiquePourModeDegradeEditiquePourRegistreNaissanceEditiqueProxyEditiqueServiceGestionEditionAS«interface»IGestionEditionASDemandeEditionUnitaireDTOASReponseEditionDTOASFactorygestion des données dans un cachemise en relation de la demande avec le cachepour construire la réponsec'est le moteur de génération du modèlede donnée attendue pour éditer le documentuseuseuseuseuseuseuse
DonneesEditionGetterEditiquePourModeDegradeEditiquePourRegistreNaissanceEditiqueProxyEditiqueServiceGestionEditionAS«interface»IGestionEditionASDemandeEditionUnitaireDTOASReponseEditionDTOASFactorygestion des données dans un cachemise en relation de la demande avec le cachepour construire la réponsec'est le moteur de génération du modèlede donnée attendue pour éditer le documentuseuseuseuseuseuseuse

La factory

ReponseEditionDTOASFactory+ReponseEditionDTOASFactory(EditiqueProxy):+creerReponseEditionEnMasseDTOAS(List<String>, List<DonneesEditionGetter>, DemandeEditionCommun): ReponseEditionDTOAS+creerReponseEditionDTOAS(List<String>, DonneesEditionGetter, DemandeEditionUnitaireDTOAS): ReponseEditionDTOAS-getMergeFieldNames(String[]): Map<String, Set<String>>-extraireChampsFusion(List<String>, Map<String, Set<String>>, List<String>, Set<ChampFusionEdition>, Map<String, Set<ChampFusionEdition>>, Boolean): void-getValues(DonneesEditionGetter, Set<ChampFusionEdition>, Map<String, Set<ChampFusionEdition>>, Boolean): Map<String, Object>- Moteur --recupererChampsFusionEditique(Set<String>, List<String>, Boolean): Set<ChampFusionEdition>-chargerChampFusion(String, boolean): ChampFusionEdition?-recupererModeleParUuid(String): ModeleDTO-removeExtension(String): String- champs de fusion --extraireCritereTri(String, ParametrageEditionPreadmission, EditionDTOAS): List<ChampFusionEdition>-extractValeursPourModele(Set<ChampFusionEdition>, DonneesEditionGetter): Map<String, Object>-extractValeursPourSousModele(ChampFusionEdition, Set<ChampFusionEdition>, DonneesEditionGetter): List<Object>-constructionListeJsonObject(List<DonneesEditionGetter>, Map<String, Set<ChampFusionEdition>>, Set<ChampFusionEdition>, boolean): List<JsonObject>- Extraction des données --creerReponseEditionDTOAS(DemandeEditionCommun, String[], Map<String, Object>): ReponseEditionDTOAS-creerReponseEditionPartieCommune(DemandeEditionCommun, String[]): ReponseEditionDTOAS-creerReponseEditionEnMasse(DemandeEditionCommun, String[], MJsonArray): ReponseEditionDTOAS- Construction Reponse --getNbCopiePourEdition(DemandeEditionCommun): Integer- utilitaire -
ReponseEditionDTOASFactory+ReponseEditionDTOASFactory(EditiqueProxy):+creerReponseEditionEnMasseDTOAS(List<String>, List<DonneesEditionGetter>, DemandeEditionCommun): ReponseEditionDTOAS+creerReponseEditionDTOAS(List<String>, DonneesEditionGetter, DemandeEditionUnitaireDTOAS): ReponseEditionDTOAS-getMergeFieldNames(String[]): Map<String, Set<String>>-extraireChampsFusion(List<String>, Map<String, Set<String>>, List<String>, Set<ChampFusionEdition>, Map<String, Set<ChampFusionEdition>>, Boolean): void-getValues(DonneesEditionGetter, Set<ChampFusionEdition>, Map<String, Set<ChampFusionEdition>>, Boolean): Map<String, Object>- Moteur --recupererChampsFusionEditique(Set<String>, List<String>, Boolean): Set<ChampFusionEdition>-chargerChampFusion(String, boolean): ChampFusionEdition?-recupererModeleParUuid(String): ModeleDTO-removeExtension(String): String- champs de fusion --extraireCritereTri(String, ParametrageEditionPreadmission, EditionDTOAS): List<ChampFusionEdition>-extractValeursPourModele(Set<ChampFusionEdition>, DonneesEditionGetter): Map<String, Object>-extractValeursPourSousModele(ChampFusionEdition, Set<ChampFusionEdition>, DonneesEditionGetter): List<Object>-constructionListeJsonObject(List<DonneesEditionGetter>, Map<String, Set<ChampFusionEdition>>, Set<ChampFusionEdition>, boolean): List<JsonObject>- Extraction des données --creerReponseEditionDTOAS(DemandeEditionCommun, String[], Map<String, Object>): ReponseEditionDTOAS-creerReponseEditionPartieCommune(DemandeEditionCommun, String[]): ReponseEditionDTOAS-creerReponseEditionEnMasse(DemandeEditionCommun, String[], MJsonArray): ReponseEditionDTOAS- Construction Reponse --getNbCopiePourEdition(DemandeEditionCommun): Integer- utilitaire -

Métadonnée de champs de fusion

un champs de fusion === [ un nom,un objet contenant la valeur, un accesseur vers la valeur,un formateur ]

«enumeration»ChampFusionCouverture«interface»ChampFusionEdition«enumeration»ChampFusionEncaissement«enumeration»ChampFusionList«enumeration»ChampFusionNouveauNe«enumeration»ChampFusionPatient«enumeration»ChampFusionVenue
«enumeration»ChampFusionCouverture«interface»ChampFusionEdition«enumeration»ChampFusionEncaissement«enumeration»ChampFusionList«enumeration»ChampFusionNouveauNe«enumeration»ChampFusionPatient«enumeration»ChampFusionVenue

Récupérateur de valeurs

  • récupération directe d'une valeur dans un objet métier
  • récupération d'une valeur conditionné par une valeur
  • récupération d'une valeur calculé par plusieurs champs
  • formatage de la valeur pour affichage dans le document
public interface ChampFusionEdition {
    default String getValue(DonneesEditionGetter donneesEditique) throws EditiqueException  {
        try {
            Object donnee = donneesEditique.getDonnee(this); // récupération de l'instance 
            if (donnee == null || getMethod() == null)
            {
                return "";
            }
            Object value = getMethod().invoke(donnee); // Invocation de la méthode
            return getFormatter().apply(value); // Application du formatage de la valeur
        }
        catch (Exception e) {
            // Dans ce cas là, on envoie vide et on log en debug l'info, on bloque pas la génération.
            getLogger().debug(String.format("Les données %s nécessaires à la génération du document n'ont pas été transmises", getEntite().getSourceClass()
                    .getSimpleName().concat(".").concat(getMethod().getName())));
            return "";
        }
    }

    boolean isListe();
    String getNomChamp();
    EntiteEdition getEntite();
    Method getMethod();
    Function<Object, String> getFormatter();
    Logger getLogger();
}

cache de donnée

structure«interface»CacheT«interface»CacheListTDefaultCacheUDefaultCacheListUDefaultResettableCacheUDefaultResettableCacheListU«interface»ResettableNouveauNeCacheListUDonneeEditionFacadeDonneesEditionDonneesEditionExtendsDonneesEditionGetter«interface»ThrowingSupplierT, EEditiqueProxyuseuseuseuseuseuse
structure«interface»CacheT«interface»CacheListTDefaultCacheUDefaultCacheListUDefaultResettableCacheUDefaultResettableCacheListU«interface»ResettableNouveauNeCacheListUDonneeEditionFacadeDonneesEditionDonneesEditionExtendsDonneesEditionGetter«interface»ThrowingSupplierT, EEditiqueProxyuseuseuseuseuseuse

Implémentation d'une edition

Danger

Il ne faut surtout pas impacter le comportement actuel du getter sauf si c'est l'objectif de la modification suite à un DE

modification du cache

Info

Aujourd'hui les données sont transférées via le front et peu de données sont géré en lazy.

Définition d'un cache sur une donnée

Donnée simple

public class DonneesEdition
{
    DonneesEdition(DonneesEditiqueBuilder donneesEditiqueBuilder, DonneesEditionExtends donneesEditionExtends) throws EditiqueException
    {
        editiqueCache.put(EntiteEdition.PATIENT, new DefaultResettableCache<>(() -> donneesEditiqueBuilder.patient));
        editiqueCache.put(EntiteEdition.DOSSIER_DECES, new DefaultCacheList<>(() -> dossiersDeces));
            registerDependent(EntiteEdition.DOSSIER_DECES,
                    Arrays.asList(EntiteEdition.PATIENT_GHT, EntiteEdition.TRAIT_COMPLEMENTAIRE, EntiteEdition.ADRESSE_PRINCIPALE, EntiteEdition.CONTACT,
                            EntiteEdition.CONJOINT, EntiteEdition.PERE, EntiteEdition.MERE, EntiteEdition.VENUE));
    }
}


Modification des champs de fusion

public enum ChampFusionPatient implements ChampFusionEdition
{
    IPP("IPP", PATIENT_GHT, "getIppGht", ChampsFusionUtils::defaultFormatter),
    MT_FDV_HT("MT_FDV_HT", CALCULE, "getMontantHorsTaxeFraisDivers", ChampsFusionUtils::formaterMontant),
    ...
}

Modification des getters

// DonneeEditionGetter
public BigDecimal getMontantHorsTaxeFraisDivers() throws EditiqueException
    {
        FraisDiversDTO fraisDiversDTO = donneeEditionFacade.getFraisDivers();
        BigDecimal montantTva = fraisDiversDTO.getMontantTva();
        BigDecimal totalFacture = fraisDiversDTO.getTotalFacture();
        BigDecimal montantHorsTaxe = totalFacture.subtract(montantTva);
        return montantHorsTaxe;
    }


public String getNom() throws EditiqueException
    {
        return donneeEditionFacade.isNouveauNe() ? donneeEditionFacade.getNouveauNe()
                .getNom() : donneeEditionFacade.getPatient().getNomNaissance();
    }

Evolutions

  • Le nombre de champs de fusion est important ==> remplacer les enums par une table en BDD si nécessaire
  • Le front envoie une uniquement les id et le cache se charge de récupérer les données en mode lazy.
  • Problème historique : un champs de fusion != une donnée déterminée (un attribut unique de BDD sans condition)

Terminé