diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ed7dd7c123262a8fa4106caad58c8e178758bbb..ea92694a7e72c744800163af1971b2ee44a652ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ Tous les changements de ce projet seront documentés dans ce document. ## [Non livré] +- Pouvoir charger et lancer un calcul sur les opérations non IT -> [Issue3](https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/numecoeval/-/issues/3) + ## [1.3.0] - 2024-03-05 diff --git a/docs/DonneeEntree.plantuml b/docs/DonneeEntree.plantuml index 3c99b1cc885096047b4f106b9022c7934752ed0a..31f11aef4a526fb91739c26d0fb74d1c15dd6fb4 100644 --- a/docs/DonneeEntree.plantuml +++ b/docs/DonneeEntree.plantuml @@ -13,6 +13,7 @@ LocalDate dateLot List<String> criteresDemandees ' le paramètre suivant est facultatif. Il liste les codes des étapes souhaitées dans le calcul, en cohérence avec la table ref_EtapeACV. Son absence déclenchera le caclul sur l'ensemble des étapes présentes dans la table de référence ref_EtapeACV. List<String> etapesDemandees +List<en_OperationNonIT> operationsNonIT List<en_EqP> equipementsPhysiques List<en_DC> dataCenters List<en_Messagerie> messageries @@ -28,6 +29,22 @@ String responsableEntite String responsableNumeriqueDurable } +'Operation Non IT +class en_OperationNonIT { +*String nomItemNonIT +Double quantite +String type +Double dureeDeVie +String localisation +'Nom de l'entité responsable du datacenter +String nomEntite +String nomSourceDonnee +' Référence au data center = en_DC.nomCourtDataCenter +- String nomCourtDatacenter +String description +Double consoElecAnnuelle +} + 'Equipement Physique class en_EqP { * String nomEquipementPhysique @@ -119,6 +136,7 @@ String nomSourceDonnee } en_DonneesEntree "1"--- "0-*" en_DC : peut contenir > +en_DonneesEntree "1"--- "0-*" en_OperationNonIT : peut contenir > en_DonneesEntree "1"--- "0-*" en_EqP : peut contenir > en_DonneesEntree "1"--- "0-*" en_Messagerie : peut contenir > en_DonneesEntree "1"--- "0-*" en_Entite : peut contenir > diff --git a/docs/Indicateurs.plantuml b/docs/Indicateurs.plantuml index bf16d9f5bb0525e7743c050e283fecf943c21cf3..2df5cb5f607227e2a17431d81170384cdb4cee8c 100644 --- a/docs/Indicateurs.plantuml +++ b/docs/Indicateurs.plantuml @@ -4,6 +4,8 @@ abstract class ind_Impact { 'La date du lot permet d’agréger les données provenant de différentes sources et d'en faire un suivi temporel LocalDate dateLot +'Nom du lot +String nomLot 'Date et Heure du calcul, même valeur pour tous les indicateurs créés avec le même lot d'objets d'entrées LocalDateTime dateCalcul 'Version de l'application ayant réalisé le calcul @@ -19,7 +21,7 @@ String etapeACV 'Nom du critère associé à l'indicateur String critere String source -String referentielsSources +String nomSourceDonnee 'Unite du critère String unite 'Nom de l'organisation - Metadata @@ -28,6 +30,19 @@ String nomOrganisation String nomEntite } +'Indicateurs d'empreinte environnemtale d'une opération non IT +class ind_ImpactOperationNonIT { +' Nom de l'opération non IT présente dans les données d'entrée en_OperationNonIT +String nomItemNonIT +'le type présent dans les données d'entrée (en_OperationNonIT.type) +String typeItem +'Quantité de l'item non IT associé à l'indicateur +Integer quantite +'Impact unitaire, le champ est null en cas d'erreur lors du calcul de l'indicateur +Double impactUnitaire +Double consoElecMoyenne +} + 'Indicateurs d'empreinte environnemtale d'un équipement physique class ind_ImpactEquipementPhysique { ' Nom de l'équipement physique présent dans les données d'entrée en_EqP @@ -69,14 +84,6 @@ Double impactUnitaire Double consoElecMoyenne } - -'Indicateur Impact Réseau -class ind_ImpactReseau { -' Nom de l'équipement physique ou de la VM -*String reference -Double impactUnitaire -} - 'Indicateur d'impact pour la messagerie 'Le champ etapeACV n'est pas utilisé pour cet indicateur class ind_ImpactMessagerie { @@ -91,6 +98,7 @@ Double nombreMailEmis ind_Impact <|-- "hérite de" ind_ImpactReseau ind_Impact <|-- "hérite de" ind_ImpactApplicatif +ind_Impact <|-- "hérite de" ind_ImpactOperationNonIT ind_Impact <|-- "hérite de" ind_ImpactEquipementPhysique ind_Impact <|-- "hérite de" ind_ImpactEquipementVirtuel ind_Impact <|-- "hérite de" ind_ImpactMessagerie diff --git a/docs/MoteurDeCalculG4IT_V1.1.adoc b/docs/MoteurDeCalculG4IT_V1.1.adoc index d1e1e3a38c6139745bc4677cf58b644c3732c5b3..95ff08188f2a6e65be01c54e39339170733dd267 100644 --- a/docs/MoteurDeCalculG4IT_V1.1.adoc +++ b/docs/MoteurDeCalculG4IT_V1.1.adoc @@ -10,6 +10,9 @@ |majeur|Avril 2023|Ouverture en Open Source |majeur|01/02/2023|Partage des équipements entre les contextes personnels et professionnels (changement règles de calculs avec le tauxUtilisation & modeUtilisation) |majeur|22/02/2023|Intégrer des nouveaux impact au référentiel(déplacements collaborateurs, bâtiments) -> Création d'une nouvelle API facteurscaracterisation +|majeur|02/05/2023|Charger et lancer un calcul sur les nouveaux impacts (réseau, déplacements, bâtiments, maintenance) -> import de nouveaux csv OperationNonIT puis création d'indicateurs associés +|majeur|17/05/2023|Inclure dans l'évaluation d'impact des informations sur la qualité des données -> ajout d'un champ qualité à l'import puis transmission de la qualité jusqu'aux indicateurs en sortie + |=== [#_documents_de_reference] @@ -29,14 +32,14 @@ l’affichage environnemental des produits de grande consommation NumEcoEval est une solution permettant, à partir de données de dimensionnement du SI et de données de références, de calculer l’empreinte environnementale d'un système d'information. Cet outil open source a été initialisé à partir des travaux de Sopra Steria [1], de l’ADEME [2], de l’INR [3], de BOAVIZTA [4] (cf.Documents de référence), avec la contribution d'IJO. Cet outil vise à déployer massivement le calcul de l'empreinte environnementale d'un système d'information au sein d'une organisation, en connectant NumEcoEval directement aux sources de données standard de celle-ci (notamment ses CMDB). -Le volume de données pouvant être important, une attention particlière a donc été apportée à la performance de l'outil et explique certains choix d'architecture (notamment l'utilisation de l'asynchronisme). +Le volume de données pouvant être important, une attention particulière a donc été apportée à la performance de l'outil et explique certains choix d'architecture (notamment l'utilisation de l'asynchronisme). == Description des principaux concepts [#_analyse_de_cycle_de_vie] === Analyse de cycle de vie -Notre approche s’inspire des méthodes d'Analyse de Cycle de Vie (ACV), cadrées par les normes ISO 14040 et 14044. Ces normes structurent l’analyse d’impact tout au long du cycle de vie d’un produit ou d'un service.L’application de ces normes à un service numérique est encore jeune mais est à ce jour l’approche la plus poussée et celle retenue par les groupes de travail liés à la règlementation (AGEC). -NumEcoEval a été conçu pour pouvoir intégrer d'autres étapes du cycle de vie des produits selon les besoins des organisations, sous réserve que les donnéées disponilbles et/ou les standards évoluent dans ce sens. +Notre approche s’inspire des méthodes d'Analyse de Cycle de Vie (ACV), cadrées par les normes ISO 14040 et 14044. Ces normes structurent l’analyse d’impact tout au long du cycle de vie d’un produit ou d'un service. L’application de ces normes à un service numérique est encore jeune mais est à ce jour l’approche la plus poussée et celle retenue par les groupes de travail liés à la règlementation (AGEC). +NumEcoEval a été conçu pour pouvoir intégrer d'autres étapes du cycle de vie des produits selon les besoins des organisations, sous réserve que les données disponilbles et/ou les standards évoluent dans ce sens. 4 étapes du cycle de vie d'un produit sont retenues actuellement : @@ -94,9 +97,9 @@ Comme indiqué dans le schéma d'architecture fonctionnel simplifié ci-dessus, [#_donnees_de_reference] ==== Données de référence -Les données de références correspondent aux données qui ne proviennent pas directement de l'organisation (<<_Organisation>>)souhaitant utiliser NumEcoEval. Ces données peuvent être issue de la littérature scientifique, de bases de données de références externes et reconnues (NegaOctet, Base IMPACT de l'ADEME, bases de données BOAVIZTA...), ou issue de travaux empiriques. Ces données doivent nécesairement être sourcées pour assurer la traçabilité des calculs. +Les données de références correspondent aux données qui ne proviennent pas directement de l'organisation (<<_Organisation>>) souhaitant utiliser NumEcoEval. Ces données peuvent être issues de la littérature scientifique, de bases de données de références externes et reconnues (NegaOctet, Base IMPACT de l'ADEME, bases de données BOAVIZTA...), ou issues de travaux empiriques. Ces données doivent nécessairement être sourcées pour assurer la traçabilité des calculs. -Le tableau suivant permet de connaitre les données de référence utilisées dans les différentes règles de calcul.Ces données seront précédées du préfixe "ref_" suivi d'une suite de lettre permettant d'identifier la table concernée. +Le tableau suivant permet de connaitre les données de référence utilisées dans les différentes règles de calcul. Ces données seront précédées du préfixe "ref_" suivi d'une suite de lettre permettant d'identifier la table concernée. exemple : |=== @@ -104,15 +107,15 @@ exemple : |ref_Critere|Précise les critères pris en charges par l'outil, leur unité et d'autres informations qui leurs sont associées. |ref_Etape|Précise les étapes du cycle de vie prises en charge par l'outil. |ref_Hypothese |Précise les hypothèses nécessaires à certains calculs des indicateurs (par exemple les données par défaut) -|ref_TypeEquipement |Précise les types d'équipements autorisés et leur durée de vie par defaut -|ref_CorrespondanceRefEqP|Donne la correspondance entre les équipements présents dans les données d'entrées et les équipements de références présents dans la table ref_impactEquipement +|ref_TypeItem |Précise les types d'items autorisés et leur durée de vie par défaut +|ref_CorrespondanceRefEqP|Donne la correspondance entre les équipements présents dans les données d'entrées et les équipements de références présents dans la table Ref_FacteurCaracterisation |ref_FacteursCaracterisation|Donne l'impact environnemental de différents items selon le critère (<<_criteres_dimpacts_environnementaux>>) et l'étape du cycle de vie (<<_analyse_de_cycle_de_vie>>). Par exemple, il peut s'agir de l'impact sur le changement climatique d'une certaine configuration de serveur à la fabrication. |=== **Pour chaque type d'objet, des endpoints de CRUD (Create/Read/Update/Delete) sont disponibles** -le format de ces références est contraint pour garantir la capacité du moteur de calul (cf.<<_moteur_de_calcul>>) à produire les indicateurs. +Le format de ces références est contraint pour garantir la capacité du moteur de calul (cf.<<_moteur_de_calcul>>) à produire les indicateurs. link:./References.plantuml[Diagramme de classe des référentiels] @@ -138,8 +141,8 @@ Elles sont uniques pour une clé donnée. .Exemple d'hypothèses : |=== -|clé|valeur|source -|dureeVieParDefaut|1| dans le cas où la durée de vie d'un type d'équipement ne serait pas renseigner on considère une hypothèse majorante d'une mise a rebut de l'équipement au bout de 1 an. +|clé|valeur|source | description +|dureeVieParDefaut|1| dans le cas où la durée de vie d'un type d'équipement ne serait pas renseignée, on considère une hypothèse majorante d'une mise a rebut de l'équipement au bout de 1 an.| |=== [#_api_donnees_dentrees] @@ -147,7 +150,7 @@ Elles sont uniques pour une clé donnée. L'API pour les données d'entrées permet d'importer des données dans le système NumEcoEval via des endpoints REST. -Toutes les informations reçues sont envoyés simultanément : +Toutes les informations reçues sont envoyées simultanément : - Au bloc Données d'entrées pour historisation des données reçues si le module est activé - Au bloc Calcul afin de produire les indicateurs issus des règles de calculs décrites dans ce document. @@ -168,14 +171,15 @@ Ce bloc est optionnel, il n'est pas nécessaire au calcul des indicateurs mais i Les données d'entrée du sytème se trouvent dans la base "Entree". Dans la spécification, les objets représentant des données d'entrées sont précédées du préfixe "en_" -et sont classées en 4 catégories : +et sont classées en 5 catégories : -* en_EqP: liste des équipements physiques (type, d'équipement) +* en_EqP: liste des équipements physiques (type d'équipement) * en_EqV : liste des équipements virtuels (vCPU, équipement physique sous jacent...) * en_DC : liste des datacenters (identification, PUE) * en_App : liste des applications +* en_OperationsNonIT: liste des opérationsNonIT (réseau, déplacements, bâtiments, maintenance) -Tous ces objets sont groupées dans un objet en_DonneesEntree avant d'être envoyé dans l'outil. +Tous ces objets sont groupés dans un objet en_DonneesEntree avant d'être envoyés dans l'outil. Dans un premier temps, il est possible d'envoyer les objets par groupes. le format de ces données d'entrée est contraint pour garantir la capacité du moteur de calul (cf.<<_moteur_de_calcul>>) à produire les indicateurs/ @@ -186,7 +190,7 @@ link:./DonneeEntree.plantuml[Diagramme de classe des entrées] Ce bloc représente le coeur de métier de la solution NumEcoEval. Il permet de produire des indicateurs en se basant sur : -* Les référentiels exposés par le bloc Références (comprenant les critères, les étapes AVC, les hypothèses,... cf. <<_donnees_de_reference>>) +* Les référentiels exposés par le bloc Références (comprenant les critères, les étapes ACV, les hypothèses,... cf. <<_donnees_de_reference>>) * Les données d'entrées reçues via un objet en_DonneesEntree : cf <<_donnees_dentrees>> Le moteur de calcul permet d'intégrer toutes les règles de calcul (<<_regles_de_calcul>>) qui se basent sur les données de références et les données d'entrées. @@ -228,14 +232,14 @@ Le bloc Indicateurs expose les points suivants : ** Exemples: *** `ref_Hypothese(dureeVieParDefaut)` correspond à utiliser l'API GET /referentiels/hypotheses?cle={cle} avec la clé `dureeVieParDefaut` (cf.<<GET_Hypotheses>>) pour obtenir l'objet ref_Hypothese correspondant -*** `ref_ImpactReseau(etape,critere,refReseau)` (cf.<<GET_ImpactsReseaux>>) correspond à utiliser l'API GET /referentiels/impactreseaux?etape={etape}&critere={critere}&reseau={refReseau} avec les paramètres `Etape`,`Critere` et `refReseau` correspondant +*** `ref_facteurCaracterisation(nom,etape,critere)` (cf.<<GET_FacteursCaracterisation>>) correspond à utiliser l'API GET /referentiels/facteursCaracterisation?nom={nomFacteurCaracterisation}&etapeacv={etapeacv}&critere={critere}& avec les paramètres `Etape`,`Critere` et `Nom` correspondants * Le "." derrière un objet (déclaré ou obtenu après une méthode d'exposition) indique l'accès à un attribut de l'objet. ** Exemples : *** `ref_Hypothese(dureeVieParDefaut).valeur` correspond au champ valeur de l'objet ref_Hypothese de clé `dureeVieParDefaut` -*** `ref_ImpactReseau(Etape,Critere,refReseau).valeur` correspond au champ valeur de l'objet ref_ImpactReseau correspondant à `Etape`,`Critere` et `refReseau` +*** `ref_facteurCaracterisation(nom,etape,critere).valeur` correspond au champ valeur de l'objet ref_FacteurCaracterisation correspondant à `Etape`,`Critere` et `Nom` -* Toutes les règles qui calculent des indicateurs l'enregistre en base de donnée grâce à la methode sauvegarder_impact(ImpactUnitaireReseau) : cf.<<sauvegarder_impact>> +* Tous les indicateurs créés sont enregistrés en base de données grâce à la méthode sauvegarder_impact(ImpactUnitaire) : cf.<<sauvegarder_impact>> [#_moteur_de_calcul] @@ -268,11 +272,11 @@ CalculDesIndicateurs(en_DonneesEntree) { initialisation d'un compteur d'impact applicatif - BOUCLE SUR CHAQUE en_EqP DE en_DonneesEntree + BOUCLE SUR CHAQUE en_EqP de en_DonneesEntree // Exécutions des règles sur les équipements physiques calculIndicateurImpactEquipementPhysique(etape, critere, en_DonneesEntree.nomOrganisation, en_EqP, en_DC, ind_ImpactEquipementPhysique) - SI en_EqP.type est un serveur (ref_TypeEquipement.serveur est vrai) + SI en_EqP.type est un serveur (ref_TypeItem.serveur est vrai) ALORS initialisation de la variable NbvCPU correspondant à la SOMME des vCPU de tous les équipements virtuels de l'équipement physique si ce dernier est renseigné ou à l'équipement physique dans le cas contraire ET initialisation de la variable stockageTotalVirtuel correspondant à la SOMME des capaciteStockage de tous les équipements virtuels de l'équipement physique si ce dernier est renseigné ou à l'équipement physique dans le cas contraire ET initialisation de la variable nbEqV correspondant au nombre de équipements virtuels de l'équipement physique si ce dernier est renseigné ou à l'équipement physique dans le cas contraire @@ -303,6 +307,11 @@ CalculDesIndicateurs(en_DonneesEntree) { FIN BOUCLE + BOUCLE SUR CHAQUE en_OpNIT de en_DonneesEntree + // Exécutions des règles sur les opérations non IT + calculIndicateurImpactOperationNonIT(etape, critere, en_DonneesEntree.nomOrganisation, en_OpNIT, ind_ImpactOperationNonIT) + FIN BOUCLE + FIN BOUCLE FIN BOUCLE @@ -327,7 +336,8 @@ Liens vers les principaux éléments de cet algorithme * <<_regles_de_calcul>> ** <<_calcul_impact_EqP_unitaire>> ** <<_calcul_impact_EqV_unitaire>> -** <<_calculImpactReseau>> +** <<_calculIndicateurImpactApplicatif>> +** <<_calcul_impact_OperationNonIT_unitaire>> ** <<_calculImpactMessagerie>> @@ -357,9 +367,10 @@ Les champs concernés sont les suivants : |=== |Nom du champ|Obligatoire|Objet Source|Objet de Sortie|Description et usage -|dateLot|Obligatoire|en_DonneesEntree|Tous les objets indicateurs|Date du lot de rattachement des données, permet de regrouper les données d'indicateurs. Définit une seule fois pour tous les objets. +|dateLot|Facultatif|en_DonneesEntree|Tous les objets indicateurs|Date du lot de rattachement des données, permet de regrouper les données d'indicateurs. Définit une seule fois pour tous les objets. |nomOrganisation|Obligatoire|en_DonneesEntree|Tous les objets indicateurs|Nom de l'organisation rattachée aux données, permet de regrouper les données d'indicateurs. Définit une seule fois pour tous les objets. |nomEntite|Facultatif|Tous les objets d'entrées|Objets indicateurs du même niveau|Nom de l'entité responsable pouvant agir sur l'objet. Elle est définie dans les données d'entrées et alimente les indicateurs associés. +|qualité|Facultatif|en_DonneesEntree|Tous les objets indicateurs|Qualité des données d'inventaire afin de connaître la précision du cadre de l'étude et les hypothèses prises. |=== @@ -372,8 +383,8 @@ le moteur de calcul produit une trace représentée par un objet d'une des class - TraceCalculImpactEquipementPhysique : la trace du calcul d'impact d'équipement physique cf. <<_calcul_impact_EqP_unitaire>> - TraceCalculImpactEquipementVirtuel : la trace du calcul d'impact d'équipement virtuel cf. <<_calcul_impact_EqV_unitaire>> +- TraceCalculOperationNonIT : la trace du calcul d'une opération non IT cf. <<_calcul_impact_OperationNonIT_unitaire>> - TraceCalculImpactMessagerie : la trace du calcul d'impact de la messagerie cf. <<_calculImpactMessagerie>> -- TraceCalculImpactReseau : la trace du calcul d'impact du réseau cf. <<_calculImpactReseau>> Tous les objets de trace de calcul possèdent un champ "formule" permettant de vérifier le calcul de l'impact. La formule se présente comme un calcul mathématique avec le nom des variables et leurs valeurs entre parenthèses. @@ -388,75 +399,86 @@ En fonction des règles concernées, des champs supplémentaires sont alimentés link:./Traces.plantuml[Diagramme de classes des objets relatifs aux traces] -[#_rg_dureevieeqp] -==== RG_DureeVieEqP : durée de vie d'un équipement physique +[#_rg_dureevieitem] +==== RG_DureeVieItem : durée de vie d'un item (équipement physique, bâtiment...) |=== |Version|Type de changement|Description |V1|création|Initialisation de la règle à dire d'expert |=== -La durée de vie d'un équipement détermine la manière dont est amortie l'impact de sa fabrication. -Elle est exprimée en année et autorise les décimales. +La durée de vie d'un item détermine la manière dont est amortie l'impact de sa fabrication. +Elle est exprimée en années et autorise les décimales. |=== |parametre|entree/sortie|Description -|equipementPhysique|entrée|L'équipement physique dont on cherche à calculer la durée de Vie -|dureeVieEqP|sortie|La durée de vie de l'équipement physique +|item|entrée|L'item dont on cherche à calculer la durée de vie +|dureeVieItem|sortie|La durée de vie de l'item |=== [pseudocode] ---- -Règle RG_DureeVieEqP(equipementPhysique,dureeVieEqP) { +Règle RG_DureeVieItem(equipementPhysique,dureeVieItem) { - 'dans le cas où il est possible de calculer l'age réel de l'équipement, ce dernier fait foi + 'dans le cas où il est possible de calculer l'age réel de l'item, ce dernier fait foi SI equipementPhysique.DateAchat est correcte et renseignée ET equipementPhysique.DateRetrait est correcte et renseignée ALORS SI (equipementPhysique.DateRetrait - equipementPhysique.DateAchat) < 1 ALORS RENVOYER 1 SINON RENVOYER ((equipementPhysique.DateRetrait - equipementPhysique.DateAchat) / 365) - 'dans le cas où seul la date d'achat est disponible, la règle du "Pseudo-amortissement" prévaut (impact de 100% sur l'année d'achat, 50% l'année 2, 33% l'année 3, etc... ) SINON SI equipementPhysique.DateAchat est correcte et equipementPhysique.DateRetrait non reseignée ALORS RENVOYER ((equipementPhysique.DateAchat - date du jour) / 365) 'dans les autres cas, une durée de vie moyenne de l'équipement est déduite SINON - RENVOYER RG_DureeVieEqP_Defaut(equipementPhysique) + RENVOYER RG_DureeVieEqP_Defaut(equipementPhysique) + FIN SI +} + +Règle RG_DureeVieItem(operationNonIT,dureeVieItem) { + + 'dans le cas où il est possible de calculer l'age réel de l'item, ce dernier fait foi + SI operationNonIT.dureeDeVie est correcte et renseignée + ALORS + RENVOYER operationNonIT.dureeDeVie + 'dans les autres cas, une durée de vie moyenne de l'équipement est déduite + SINON + RENVOYER RG_DureeVieItem_Defaut(operationNonIT) FIN SI } ---- -cf.<<_rg_dureevieeqp_defaut>> +cf.<<_rg_dureevieitem_defaut>> -[#_rg_dureevieeqp_defaut] -==== RG_DureeVieEqP_Defaut : durée de vie des équipements par défaut +[#_rg_dureevieitem_defaut] +==== RG_DureeVieItem_Defaut : durée de vie des items par défaut |=== |Version|Type de changement|Description |V1|création|Initialisation de la règle à dire d'expert |=== -La durée de vie des équipements peut être déterminée par défaut dans le cas où la date d'acquisition ne serait pas renseignée. Elle est alors calculée sur la base suivante +La durée de vie des items peut être déterminée par défaut dans le cas où l'âge réel ne serait pas renseigné. Elle est alors calculée sur la base suivante : |=== |paramètre|entree/sortie|Description -|equipementPhysique|entrée|L'équipement physique dont on cherche à calculer la durée de Vie par défaut -|dureeVieEqP_Defaut|sortie|La durée de vie par défaut de l'équipement physique +|item|entrée|L'item dont on cherche à calculer la durée de Vie par défaut +|dureeVieItem_Defaut|sortie|La durée de vie par défaut de l'item |=== [pseudocode] ---- -Règle RG_DureeVieEqP_Defaut(equipementPhysique, dureeVieEqP_Defaut) { - 'la durée de vie par défaut des équipements est celle renseignée dans la table des types d'équipements - SI l'équipement physique en entrée est présent dans la table des références d'équipement (ref_TypeEquipement.type) - ALORS dureeVieEqP_Defaut = ref_TypeEquipement.dureeVieDefaut - 'on retient l hypothèse d'une durée de vie par défaut des équipements égale à la durée de vie des équipements enregistrée dans les hypothèses +Règle RG_DureeVieItem_Defaut(Item, dureeVieItem_Defaut) { + 'la durée de vie par défaut des items est celle renseignée dans la table des types d'items + SI l'item en entrée est présent dans la table des références d'items (si Item.type = ref_TypeItem.nom) + ALORS dureeVieItem_Defaut = ref_TypeItem.dureeVieDefaut + 'on retient l hypothèse d'une durée de vie par défaut des items égale à la durée de vie des items enregistrée dans les hypothèses SINON SI ref_Hypothese(dureeVieParDefaut) existe - ALORS dureeVieEqP_Defaut = ref_Hypothese(dureeVieParDefaut).valeur + ALORS dureeVieItem_Defaut = ref_Hypothese(dureeVieParDefaut).valeur SINON - ErrCalcul("la durée de vie par défaut de l'équipement n'a pas pu être déterminée") + ErrCalcul("la durée de vie par défaut de l'item n'a pas pu être déterminée") FIN SI } ---- @@ -469,7 +491,7 @@ Règle RG_DureeVieEqP_Defaut(equipementPhysique, dureeVieEqP_Defaut) { |V1|création|Initialisation de la règle |=== -Cette règle permet de retrouver l'équipement de référence, c'est à dire celui dont les facteurs d'impact seront utilisés afin d'évaluer l'impact de l'équipement en court de traitement. +Cette règle permet de retrouver l'équipement de référence, c'est à dire celui dont les facteurs d'impact seront utilisés afin d'évaluer l'impact de l'équipement en cours de traitement. |=== |paramètre|entree/sortie|Description @@ -484,8 +506,8 @@ Règle RG_correspondanceRefEquipement(nomOrganisation, equipement, refEquipement SI ref_CorrespondanceRefEqP(nomOrganisation, equipement.modele) existe RENVOYER refEquipementretenu = ref_CorrespondanceRefEqP(nomOrganisation, equipement.modele).refEquipementCible - SINON SI ref_TypeEquipement(equipement.type).refEquipementParDefaut existe - RENVOYER refEquipementretenu = ref_TypeEquipement(equipement.type).refEquipementParDefaut + SINON SI ref_TypeItem(equipement.type).refEquipementParDefaut existe + RENVOYER refEquipementretenu = ref_TypeItem(equipement.type).refEquipementParDefaut SINON ErrCalcul("aucune correspondance avec un équipement de référence n'a pu être déterminée") FIN SI @@ -493,9 +515,37 @@ Règle RG_correspondanceRefEquipement(nomOrganisation, equipement, refEquipement } ---- -=== Calculs d'impacts unitaires +[#_rg_correspondance_RefOperationNonIT] +==== RG Correspondance entre les opérations Non IT et leur références : +|=== +|Version|Type de changement|Description +|V1|création|Initialisation de la règle +|=== +Cette règle permet de retrouver l'item de référence, c'est à dire celui dont les facteurs d'impact seront utilisés afin d'évaluer l'impact de l'opération non IT en cours de traitement. + +|=== +|paramètre|entree/sortie|Description +|organisation|entrée|l'organisation en cours de traitement +|item|entrée|l'item dont on cherche la référence +|refItemParDefaut|sortie|l'item dont l'impact servira de référence +|=== + +[pseudocode] +---- +Règle RG_correspondanceRefItem(nomOrganisation, item, refItemRetenu) { + + SI ref_TypeItem(item.type).refItemParDefaut existe + RENVOYER refItemRetenu = ref_TypeItem(equipement.type).refItemParDefaut + SINON + ErrCalcul("aucune correspondance avec un item de référence n'a pu être déterminée") + FIN SI + +} +---- + +=== Calculs d'impacts unitaires [#_calcul_impact_EqP_unitaire] ==== Calcul impact unitaire équipement physique @@ -524,6 +574,8 @@ Cette règle permet le calcul de l'impact moyen d'un équipement physique sur un |ind_ImpactEquipementPhysique.modeUtilisation|sortie|le mode d'utilisation de l'équipement, il n'est utilisé que si le taux d'utilisation n'est pas renseigné. Les deux modes possibles sont (COPE & BYOD), les taux d'utilisation correspondants son enregistrés dans la table ref_hypotheses |ind_ImpactEquipementPhysique.unite|sortie|l'unité présente dans le référentiel correspondant au critère en cours |ind_ImpactEquipementPhysique.consoElecMoyenne|sortie|la consommation électrique déterminée par la règle suivante +|ind_ImpactEquipementPhysique.qualite|sortie|la qualité de la donnée d'inventaire + |=== [pseudocode] @@ -546,9 +598,9 @@ refEquipementRetenu = RG_correspondanceRefEquipement(nomOrganisation, equipement ind_ImpactEquipementPhysique.consoElecMoyenne = EqP.consoElecAnnuelle SINON SI 'récupération de la consommation électrique de la référence de l'équipement retenue - x Ref_ImpactEquipement(refEquipementRetenu, EtapeACV, Critere).consoElecAnMoyenne + x Ref_FacteurCaracterisation(refEquipementRetenu, EtapeACV, Critere).consoElecAnMoyenne 'enregistrement de la consommation electrique retenue - ind_ImpactEquipementPhysique.consoElecMoyenne = Ref_ImpactEquipement(refEquipementRetenu, EtapeACV, Critere).consoElecAnMoyenne + ind_ImpactEquipementPhysique.consoElecMoyenne = Ref_FacteurCaracterisation(refEquipementRetenu, EtapeACV, Critere).consoElecAnMoyenne SINON ErrCalcFonc("donnée de consommation electrique manquante") Arret du calcul @@ -565,9 +617,10 @@ refEquipementRetenu = RG_correspondanceRefEquipement(nomOrganisation, equipement Arret du calcul FIN SI - x ref_MixElec(PaysDUtilisation = en_DC(NomCourtDatacenter).localisation).valeur + x ref_FacteurCaracterisation(EtapeACV, Critere, Categorie=electricity-mix, Localisation = en_DC(NomCourtDatacenter).localisation).valeur SINON - x ref_MixElec(PaysDUtilisation = EqP.PaysDUtilisation).valeur + x ref_FacteurCaracterisation(EtapeACV, Critere, Categorie=electricity-mix, Localisation = EqP.PaysDUtilisation).valeur + FIN SI SI EqP.tauxUtilisation est renseigné @@ -602,7 +655,7 @@ refEquipementRetenu = RG_correspondanceRefEquipement(nomOrganisation, equipement FIN SI 'récupération de l'impact pour le critère et l'étape ACV en cours, de la référence de l'équipement retenue - x Ref_ImpactEquipement(refEquipementretenu, EtapeACV, Critere).value + x Ref_FacteurCaracterisation(refEquipementretenu, EtapeACV, Critere).valeur / RG_DureeVieEqP @@ -621,14 +674,14 @@ EqP.quantité = 1 x en_EqP.ConsoElecAnMoyenne= 1000 kWh x en_EqP.tauxUtilisation = 0,85 x en_DC(NomCourtDatacenter = "googleCloud").PUE = 1,13 -x ref_MixElec("France","Changement Climatique").valeur = 0,0813225 +x ref_FacteurCaracterisation("Changement Climatique", "FABRICATION", Categorie=electricity-mix, Localisation = "France").valeur = 0,0813225 ImpactUnitaireEqP = 78,11 kg CO2eq /an ==== [#_calcul_impact_EqV_unitaire] -==== Calcul d'impact d'une machine virtuel +==== Calcul d'impact d'une machine virtuelle |=== |Version|Type de changement|Description @@ -654,7 +707,9 @@ L'impact alloué à la machine virtuelle correspond à une part de l'impact de l |ind_ImpactEquipementVirtuel.cluster|sortie|le cluster présent dans les données d'entrée pour cette équipements virtuels |ind_ImpactEquipementVirtuel.impactUnitaire|sortie|l'impact calculé pour le critère et l'étape ACV |ind_ImpactEquipementVirtuel.unite|sortie|l'unité présente dans le référentiel correspondant au critère en cours -|ind_ImpactEquipementVirtuel.consoElecMoyenne|sortie|la consommation électrique renseignée en entrée +|ind_ImpactEquipementVirtuel.consoElecMoyenne|sortie|la consommation électrique renseignée en entrée +|ind_ImpactEquipementVirtuel.qualite|sortie|la qualité de la donnée d'inventaire + |=== @@ -711,61 +766,116 @@ Il est calculé *directement dans le moteur de calcul* <<_moteur_de_calcul>> et |ind_ImpactApplicatif.sousDomaine|sortie|en_App.sousDomaine |ind_ImpactApplicatif.unite|sortie|l'unité présente dans le référentiel correspondant au critère en cours |ind_ImpactApplicatif.consoElecMoyenne|sortie|la consomation électrique calculée (correspondant à la somme des consommations éléctriques des équipements virtuels sous-jacentes) -|=== +|ind_ImpactApplicatif.qualite|sortie|la qualité de la donnée d'inventaire +|=== -[#_calculImpactReseau] -==== Calcul impact lié à la sollicitation du réseau +[#_calcul_impact_OperationNonIT_unitaire] +==== Calcul impact unitaire d'une opérationNonIT |=== -|version|type de changement|description +|Version|Type de changement|Description |V1|création|Initialisation de la règle à dire d'expert |=== -*Note importante* : cette règle de calcul ne fait pas l'objet d'un consensus -Cette règle permet le calcul de l'impact lié à la sollicitation des différents type de réseaux permettant l'interconnexion des utilisateurs et des équipements. Il peut s'agir de flux internet mais on peut aussi considérer les données transitant entre deux sites par exemple client via une liaison louée par exemple, ou même au sein d'un datacenter. +Cette règle permet le calcul de l'impact moyen d'une opération Non IT sur une année. Elle possède 3 paramètres : l'opération/l'item dont on cherche à déterminer l'impact, l'étapeACV qui permet de déterminer quelle étape du cycle de vie de l'item est regardée et le critère d'impact que l'on souhaite extraire. |=== |parametre|entree/sortie|Description -|equipementPhysique|entrée|l'équipement physique pour lequel l'impact réseau est calculé -|critere|entrée|le critere dont on cherche à calculer la durée de Vie par defaut -|etapeACV|entrée|l'étape ACV dont on cherche à calculer la durée de Vie par defaut -|ind_ImpactReseau.reference|sortie|type d'impact réseau -|ind_ImpactReseau.ImpactUnitaire|sortie|impact calculé -|ind_ImpactReseau.critere|sortie|critere calculé -|ind_ImpactReseau.etapeACV|sortie|etape ACV calculé -|ind_ImpactReseau.unite|sortie|l'unité présente dans le référentiel correspondant au critere en cours +|critere|entrée|le critere dont on cherche à calculer la durée de Vie par défaut +|etapeACV|entrée|l'étape ACV dont on cherche à calculer la durée de Vie par défaut +|nomOrganisation|entrée|le nom de l'organisation en cours de traitement +|operationNonIT|entrée|l'opération non IT dont on cherche à calculer l'impact environnemental +|ind_ImpactOperationNonIT.nomItemNonIT|sortie|le nom de l'item dont on a calculé l'impact +|ind_ImpactOperationNonIT.critere|sortie|le critere calculé +|ind_ImpactOperationNonIT.etapeACV|sortie|l'étape ACV calculée +|ind_ImpactOperationNonIT.type|sortie|le type d'item +|ind_ImpactOperationNonIT.impactUnitaire|sortie|l'impact calculé pour le critère et l'étape ACV, vaut null en cas d'erreur +|ind_ImpactOperationNonIT.quantite|sortie|la quantité d'items +|ind_ImpactOperationNonIT.unite|sortie|l'unité présente dans le référentiel correspondant au critère en cours +|ind_ImpactOperationNonIT.consoElecMoyenne|sortie|la consommation électrique +|ind_ImpactOperationNonIT.qualite|sortie|la qualité de la donnée d'inventaire |=== [pseudocode] ---- -Règle calculImpactReseau(equipementPhysique, critere, etape, ind_ImpactReseau) { - - SI equipementPhysique.goTelecharge est renseigné ET ref_ImpactReseau(etape, critere, equipementPhysique) existe - - ALORS - - impactReseau = - equipementPhysique.goTelecharge - x ref_ImpactReseau(etape, critere, equipementPhysique).valeur +soit en_OperatioNonIT(Operation) = OpNIT + +Règle calculIndicateurImpactOperationNonIT(critere, etape, nomOrganisation, OpNIT, ind_ImpactOperationNonIT) { + + 'Récupération de la correspondance de refItem + refItemRetenu = RG_correspondanceRefOperationNonIT(nomOrganisation, OpNIT) + ind_ImpactOperationNonIT(Item, EtapeACV, Critere) = + SI OpNIT.categorie = "RESEAU_MOBILE" OU "RESEAU_FIXE" OU "MAINTENANCE" OU "BATIMENT" + SI EtapeACV.code = "UTILISATION" + OpNIT.quantité + + SI OpNIT.consoElecAnnuelle est renseigné + x OpNIT.consoElecAnnuelle + 'enregistrement de la consommation electrique retenue + ind_ImpactOperationNonIT.consoElecMoyenne = OpNIT.consoElecAnnuelle + SINON SI + 'récupération de la consommation électrique de la référence de l'équipement retenue + x Ref_FacteurCaracterisation(refItemRetenu, EtapeACV, Critere).consoElecAnMoyenne + 'enregistrement de la consommation electrique retenue + ind_ImpactOperationNonIT.consoElecMoyenne = Ref_FacteurCaracterisation(refItemRetenu, EtapeACV, Critere).consoElecAnMoyenne + SINON + ErrCalcFonc("donnée de consommation electrique manquante") + Arret du calcul + FIN SI - RENVOYER ImpactUnitaireReseau - - SINON SI ref_ImpactReseau("impactReseauMobileMoyen") n'existe pas ou ref_ImpactReseau("impactReseauMobileMoyen").valeur n'est pas renseigné + x ref_FacteurCaracterisation(EtapeACV, Critere, Categorie=electricity-mix, Localisation = OpNIT.Localisation).valeur + + SINON SI EtapeACV.code != "UTILISATION" + OpNIT.quantité + + 'récupération de l'impact pour le critère et l'étape ACV en cours, de la référence de l'item retenu + x Ref_FacteurCaracterisation(refItemRetenu, EtapeACV, Critere).valeur + + SI OpNIT.categorie = "RESEAU_FIXE" + / ref_Hypothese.valeur(CAPACITE_LIGNE_FIXE_LOCALISATION) + + SINON SI OpNIT.categorie = "BATIMENT" + / dureeDeVie + FIN SI + + SINON SI OpNIT.categorie = "DEPLACEMENT_ELECTRIQUE" OU "DEPLACEMENT_ESSENCE" OU DEPLACEMENT_HYBRIDE + 'nombre de kilomètres parcourus dans le véhicule + OpNIT.quantité + + 'récupération de la consommation moyenne pour le véhicule choisi, valeur récupérée dans ref_hypothèses + x ref_Hypothese.valeur(OpNIT.refHypothese) - ErrCalcFonc("la référence impactReseauMobileMoyen n'existe pas") + SI OpNIT.categorie = "DEPLACEMENT_ELECTRIQUE" + 'récupération du mix électrique pour le critère de Fabrication et pour l'étape ACV en cours + x ref_FacteurCaracterisation.valeur(FABRICATION, Critère, mix elec, OpNIT.Localisation)) + SINON SI OpNIT.categorie = "DEPLACEMENT_ESSENCE" + 'récupération de l'impact de la production d'essence pour le critère de Fabrication et pour l'étape ACV en cours + x ref_FacteurCaracterisation.valeur(FABRICATION, Critère, Production essence )) + + SINON SI OpNIT.categorie = "DEPLACEMENT_HYBRIDE" + 'récupération de l'impact de la production d'essence pour le critère de Fabrication et pour l'étape ACV en cours + x ref_FacteurCaracterisation.valeur(FABRICATION, Critère, Production essence )) + 'récupération du taux utile pour le calcul d'impact des véhicules hybrides, valeur récupérée dans ref_hypothèses + x ref_Hypothese.valeur('taux_vehicule_hybride') + + FIN SI FIN SI } ---- -Références: - -* ref_ImpactReseau(etape, critere, equipementPhysique) : cf.<<GET_ImpactsReseaux>> -* sauvegarder_impact(impact) : cf.<<sauvegarder_impact>> - +.Calcul de l'impact "moyen" en CO2 lié à l'utilisation d'un réseau fixe sur 1 an +==== +Item = exemple d'un réseau fixe localisé en France +OpNIT.quantité = 400 +x ref_FacteurCaracterisation(reseau-fixe, UTILISATION, Changement Climatique).ConsoElecAnMoyenne = 180 kWh +x ref_FacteurCaracterisation( UTILISATION, Changement Climatique,mixelec,France).valeur = 0.0813225 +/ ref_Hypothese(CAPACITE_LIGNE_FIXE_FR) = 2640 +ImpactUnitaireOpNIT = 2,21788 kg CO2eq /an +==== [#_calculImpactMessagerie] ==== Calcul impact lié à la Messagerie @@ -804,6 +914,7 @@ Règle calculImpactMessagerie(en_Messagerie, ref_Critere, ref_ImpactMessagerie, } ---- + == Gestion des erreurs === ErrCalcFonc @@ -812,7 +923,7 @@ Au déclenchement de ce type d'erreur, une ligne s'affiche dans les logs, avec l .Erreur de calcul de l'impact réseau ==== - "ErrCalcFonc : ImpactUnitaireReseau(equipement, etapeACV, critere) ; la référence "impactReseauMobileMoyen" n'existe pas" + "ErrCalcFonc : ImpactUnitaireOperationNonIT(item, etapeACV, critere) ; la référence "impactReseauMobileMoyen" n'existe pas" ==== === ErrCalcTech diff --git a/docs/References.plantuml b/docs/References.plantuml index 7c2296aa23d9a9f9c36ae24065e1b075ee49d5a2..52d234c61d99ce24ce2a264ceba0f62bc7292bc2 100644 --- a/docs/References.plantuml +++ b/docs/References.plantuml @@ -1,23 +1,26 @@ @startuml -'les hypotheses generique regroupe les hypothèses permettant le calcul de certains indicateurs +'les hypothèses permettant le calcul de certains indicateurs class ref_Hypothese{ *String clé String valeur String source } -'liste des types d'équipements autorisés et de leur durée de vie par défaut -class ref_TypeEquipement{ +'liste des types d'items autorisés +class ref_TypeItem{ *String type +String categorie 'le booléen "serveur" permet de distinguer les équipements inclus dans le calcul de l'impact d'un serveur applicatif à l'utilisation boolean serveur 'le commentaire permet notamment de détailler les catégories équipements contenues dans un même type String commentaire Double dureeVieDefaut -' la référence de l'équipement par defaut doit exister dans la table ref_ImpactEquipement.refEquipement -String refEquipementParDefaut +' la référence de l'hypothese doit exister dans la table ref_Hypothese.cle +String refHypothese String source +' la référence de l'item par defaut doit exister dans la table ref_FacteurCaracterisation.nom +String refItemParDefaut } 'Impact environnementaux de référence @@ -51,7 +54,7 @@ String unité String description } -' étapes du cycle de vie des équipements pris en compte dans les calculs +' étapes du cycle de vie des items pris en compte dans les calculs class ref_EtapeACV { * String code String libelle diff --git a/docs/Traces.plantuml b/docs/Traces.plantuml index 6798e03448ca8487a7aafeebf3ec8c423d921855..a85ed6426340c60d839ecf1e7f518ff0c5c97e78 100644 --- a/docs/Traces.plantuml +++ b/docs/Traces.plantuml @@ -19,14 +19,32 @@ class TraceCalculImpactEquipementPhysique { Double valeurReferentielImpactEquipement String sourceReferentielImpactEquipement DureeDeVie dureeDeVie + String erreur +} + +class TraceCalculOperationNonIT { + String formule + ConsoElecAnMoyenne consoElecAnMoyenne + MixElectrique mixElectrique + Double valeurReferentielFacteurCaracterisation + String valeurReferentielFacteurCaracterisation + Hypothese hypothese; + DureeDeVie dureeDeVie + String erreur } class TraceCalculImpactEquipementVirtuel { String formule - boolean vCPUok - Integer vCPU - Integer nbvCPU - Integer nbVM + Integer nbEquipementsVirtuels + Integer nbTotalVCPU + Double stockageTotalVirtuel + String erreur +} + +class TraceCalculImpactApplication { + String formule + Integer nbApplications + String erreur } class TraceCalculImpactMessagerie { @@ -41,16 +59,6 @@ class TraceCalculImpactMessagerie { Double nombreMailEmisXDestinataires } -class TraceCalculImpactReseau { - String formule - String critere - String etapeACV - String sourceReferentielReseau - String equipementPhysique - String impactReseauMobileMoyen - String goTelecharge -} - ' Classes des objets associées aux calculs class ConsoElecAnMoyenne { @@ -96,11 +104,14 @@ DureeDeVie "0-1" -up- "1" TraceCalculImpactEquipementPhysique : peut contenir > MixElectrique "0-1" -up- "1" TraceCalculImpactEquipementPhysique : peut contenir > NbJourUtiliseAn "0-1" -up- "1" TraceCalculImpactEquipementPhysique : peut contenir > -DureeDeVieParDefaut "0-1" -up- "1" DureeDeVie : peut contenir > +ConsoElecAnMoyenne "0-1" -up- "1" TraceCalculOperationNonIT : peut contenir > +DureeDeVie "0-1" -up- "1" TraceCalculOperationNonIT : peut contenir > +MixElectrique "0-1" -up- "1" TraceCalculOperationNonIT : peut contenir > +DureeDeVieParDefaut "0-1" -up- "1" DureeDeVie : peut contenir > -TraceCalculImpact <|-- "hérite de" TraceCalculImpactReseau TraceCalculImpact <|-- "hérite de" TraceCalculImpactMessagerie +TraceCalculImpact <|-- "hérite de" TraceCalculOperationNonIT TraceCalculImpact <|-- "hérite de" TraceCalculImpactEquipementVirtuel TraceCalculImpact <|-- "hérite de" TraceCalculImpactEquipementPhysique diff --git a/e2e/1_load_ref.sh b/e2e/1_load_ref.sh index 36093c58c4752b8517893b58a491a250b4a8f02e..04a1b4fcac52ef1b9a375ad5e41dac06bc1275b2 100644 --- a/e2e/1_load_ref.sh +++ b/e2e/1_load_ref.sh @@ -1,7 +1,7 @@ #!/bin/bash # CONTANTS -REFERENTIELS="criteres etapes hypotheses typeEquipement correspondanceRefEquipement facteursCaracterisation" +REFERENTIELS="criteres etapes hypotheses correspondanceRefEquipement facteursCaracterisation typeItem" E2E_LOCAL_PATH=. diff --git a/e2e/2_generate_dataset.sh b/e2e/2_generate_dataset.sh index 54aac7a1f44f419535bb7cfde3ef06b235907c51..5fafb28a04e5036fe75f62f246f1c0550407e7c3 100644 --- a/e2e/2_generate_dataset.sh +++ b/e2e/2_generate_dataset.sh @@ -8,7 +8,7 @@ NB_APP_PAR_VM=${4:-2} . ./.env . ./utils.sh -# CONTANTS +# CONSTANTS NB_CSV_HORS_SRV=100 NB_CSV_SRV=100 @@ -64,6 +64,10 @@ for ((i = 1; i <= $(($NB_EQ_PH_SRV / $NB_CSV_SRV)); i++)); do done >>data/EquipementVirtuel.csv done +# *** OperationNonIT.csv *** +log "Generate input data : OperationNonIT.csv" +cp -f input_template/OperationNonIT.csv data/ + # *** Application.csv *** log "Generate input data : Application.csv" head -n1 input_template/Application.csv >data/Application.csv diff --git a/e2e/3_load_input.sh b/e2e/3_load_input.sh index 1368dc3a89bf526dacead1cd8370ee43cc705d0d..bcbfa86c53d0c8ad3103893c5adeabafd3206bd6 100644 --- a/e2e/3_load_input.sh +++ b/e2e/3_load_input.sh @@ -13,11 +13,12 @@ rm -f progress.log log_n "$ORGANISATION - $NOM_LOT - $DATE_LOT - Load Input - " | tee -a progress.log curl -s -XPOST "$ENTREE_URL/entrees/csv?nomLot=${NOM_LOT}&dateLot=${DATE_LOT}&nomOrganisation=${ORGANISATION}" \ - --form csvDataCenter=@data/DataCenter.csv \ - --form csvEquipementPhysique=@data/EquipementPhysique.csv \ - --form csvEquipementVirtuel=@data/EquipementVirtuel.csv \ - --form csvApplication=@data/Application.csv | tee -a progress.log -echo "" | tee -a progress.log + --form csvDataCenter=@data/DataCenter.csv \ + --form csvEquipementPhysique=@data/EquipementPhysique.csv \ + --form csvEquipementVirtuel=@data/EquipementVirtuel.csv \ + --form csvApplication=@data/Application.csv \ + --form csvOperationNonIT=@data/OperationNonIT.csv | tee -a progress.log + echo "" | tee -a progress.log sleep 2 diff --git a/e2e/5_assert.sh b/e2e/5_assert.sh index 86b42ab20104dca5f01850385463a90a8ff13f5c..87adfefbe9d1aa61fd11b1e8a6b8ab5c05cd19f1 100644 --- a/e2e/5_assert.sh +++ b/e2e/5_assert.sh @@ -19,6 +19,8 @@ export_table equipementPhysique conso_elec_moyenne,critere,etapeacv,impact_unita export_table equipementVirtuel cluster,conso_elec_moyenne,critere,etapeacv,impact_unitaire,nom_entite,nom_entite_discriminator,nom_equipement,nom_equipement_virtuel,nom_source_donnee,nom_source_donnee_discriminator,source,statut_indicateur,trace,unite,version_calcul export_table application conso_elec_moyenne,critere,domaine,etapeacv,impact_unitaire,nom_application,nom_entite,nom_entite_discriminator,nom_equipement_physique,nom_equipement_virtuel,nom_source_donnee,nom_source_donnee_discriminator,source,sous_domaine,statut_indicateur,trace,type_environnement,unite,version_calcul export_table reseau etapeacv,critere,source,statut_indicateur,trace,version_calcul,impact_unitaire,unite,nom_entite,nom_equipement +export_table operationNonIT conso_elec_moyenne,critere,etapeacv,impact_unitaire,nom_entite,nom_entite_discriminator,nom_item_non_it,nom_source_donnee,nom_source_donnee_discriminator,quantite,source,statut_indicateur,trace,type_item,unite,version_calcul + ALL_OK=true for file in $(ls actual/); do echo -n "Check file $file : " diff --git a/e2e/e2e.iml b/e2e/e2e.iml index 885ffe64a60205bdd9858b06a69d8c16c57e1497..8021953ed9f8cc6cd6d71c79462bad4cd2b5394c 100644 --- a/e2e/e2e.iml +++ b/e2e/e2e.iml @@ -1,6 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> -<module version="4"> - <component name="SonarLintModuleSettings"> - <option name="uniqueId" value="3533810f-e57c-45f5-bdb3-84fc26316012" /> +<module type="WEB_MODULE" version="4"> + <component name="NewModuleRootManager" inherit-compiler-output="true"> + <exclude-output /> + <content url="file://$MODULE_DIR$" /> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> </component> </module> \ No newline at end of file diff --git a/e2e/input_template/OperationNonIT.csv b/e2e/input_template/OperationNonIT.csv new file mode 100644 index 0000000000000000000000000000000000000000..ae3e4ec355e54531751d3d4d0d9e32d18bc60826 --- /dev/null +++ b/e2e/input_template/OperationNonIT.csv @@ -0,0 +1,21 @@ +nomItemNonIT;quantite;type;dureeDeVie;localisation;nomEntite;nomSourceDonnee;nomCourtDatacenter;description;consoElecAnnuelle +reseau-fixe-1;100.0;Fixed Line FR ;;France;SSG;sourceTest;;description; +reseau-fixe-2;20.0;Fixed Line EU;;Hungary;Entite;sourceTest2;;description; +reseau-fixe-error;20.0;Fixed Line;;Hungary;Entite;sourceTest2;;description; +reseau-mobile-1;445.0;Mobile Line;;France;EntiteTest;sourceTest3;;description; +batiment-dsi-stMalo;1000.0;Batiment 1;45.0;France;EntiteTest;sourceTest4;;description; +batiment-dsi-Rennes;1200.0;Batiment 1;;France;EntiteTest;sourceTest5;;description; +batiment-dsi-Cesson;1060.0;Batiment 2;;France;EntiteTest;sourceTest6;;description; +batiment-dc-stMalo;836.0;Batiment DC;25.0;France;EntiteTest;sourceTest7;fakeName;description; +batiment-dc-Cesson;590.0;Batiment DC;;France;EntiteTest;sourceTest8;G1;description; +maintenance-1;30.0;Maintenance 1;;France;EntiteTest;sourceTest9;;description; +deplacement-velo;1230.0;Deplacement Velo;;France;EntiteTest;sourceTest10;;description; +deplacement-trotinette;60.0;Deplacement Trotinette;;France;EntiteTest;sourceTest11;;description; +deplacement-voiture-electrique;156.0;Deplacement Voiture Electrique;;France;EntiteTest;sourceTest12;;description; +deplacement-voiture-hybride;3457.0;Deplacement Voiture Hybride;;France;EntiteTest;sourceTest13;;description; +deplacement-voiture-essence;24678.0;Deplacement Voiture Essence;;France;EntiteTest;sourceTest14;;description; +deplacement-voiture-diesel;2355.0;Deplacement Voiture Diesel;;France;EntiteTest;sourceTest15;;description; +deplacement-avion;23000.0;Deplacement Avion;;France;EntiteTest;sourceTest16;;description; +deplacement-train;27000.0;Deplacement Train;;France;EntiteTest;sourceTest17;;description; +deplacement-bus-essence;352.0;Deplacement Bus Essence;;France;EntiteTest;sourceTest18;;description; +deplacement-bus-electrique;352.0;Deplacement Bus Electrique;;France;EntiteTest;sourceTest18;;description; diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/model/CalculOperationNonIT.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/model/CalculOperationNonIT.java new file mode 100644 index 0000000000000000000000000000000000000000..df37017aa0c58067e6b6e07ec7c846372954edbe --- /dev/null +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/model/CalculOperationNonIT.java @@ -0,0 +1,21 @@ +package org.mte.numecoeval.calculs.domain.model; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.mte.numecoeval.calculs.referentiels.generated.api.model.*; +import org.mte.numecoeval.topic.data.OperationNonITDTO; + +import java.util.List; + +@NoArgsConstructor +@Getter +@Setter +public class CalculOperationNonIT { + private List<EtapeDTO> etapes; + private List<CritereDTO> criteres; + private List<HypotheseDTO> hypotheses; + private OperationNonITDTO operationNonIT; + private TypeItemDTO typeItem; + private List<FacteurCaracterisationDTO> facteurCaracterisations; +} \ No newline at end of file diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/model/CalculSizes.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/model/CalculSizes.java index bd90d22d26ce0924e171aee5bad07cbfd30d997a..89f9b8984ef5da314d27f76577b7e9c9d724509e 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/model/CalculSizes.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/domain/model/CalculSizes.java @@ -7,10 +7,12 @@ public class CalculSizes { private long nbEquipementPhysique; private long nbEquipementVirtuel; private long nbApplication; + private long nbOperationNonIT; private long nbMessagerie; private long nbIndicateurEquipementPhysique; private long nbIndicateurEquipementVirtuel; private long nbIndicateurApplication; private long nbIndicateurReseau; + private long nbIndicateurOperationNonIT; private long nbIndicateurMessagerie; } diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/client/ReferentielClient.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/client/ReferentielClient.java index 92f1d225ca88f9bfc4996c7ead8aec7a343267a5..ba9e0e067caab98e089fc87f604ee06f38919ffb 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/client/ReferentielClient.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/client/ReferentielClient.java @@ -3,6 +3,7 @@ package org.mte.numecoeval.calculs.infrastructure.client; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.mte.numecoeval.calculs.domain.exception.ExternalApiException; +import org.mte.numecoeval.calculs.domain.utils.Constants; import org.mte.numecoeval.calculs.referentiels.generated.api.client.InterneNumEcoEvalApi; import org.mte.numecoeval.calculs.referentiels.generated.api.model.*; import org.springframework.cache.annotation.Cacheable; @@ -82,6 +83,18 @@ public class ReferentielClient { return null; } + @Cacheable(value = "TypeItem") + public TypeItemDTO getTypeItem(String type) { + try { + return interneNumEcoEvalApi.getTypeItem(type).block(); + } catch (WebClientResponseException e) { + if (e.getStatusCode() != HttpStatusCode.valueOf(404)) { + throw new ExternalApiException(e); + } + } + return null; + } + @Cacheable(value = "ImpactEquipement") public ImpactEquipementDTO getImpactEquipement(String refEquipement, String critere, String etape) { try { @@ -119,6 +132,30 @@ public class ReferentielClient { return null; } + @Cacheable(value = "FacteurCaracterisationMixElec") + public FacteurCaracterisationDTO getMixElectriqueFromFacteurCaracterisation(String critere, String localisation) { + try { + return interneNumEcoEvalApi.getFacteurCaracterisation(critere, null, null, localisation, Constants.ELECTRICITY_MIX_CATEGORY).blockFirst(); + } catch (WebClientResponseException e) { + if (e.getStatusCode() != HttpStatusCode.valueOf(404)) { + throw new ExternalApiException(e); + } + } + return null; + } + + @Cacheable(value = "FacteurCaracterisation") + public FacteurCaracterisationDTO getFacteurCaracterisationByCritereAndEtapeAndNom(String critere, String etape, String nom) { + try { + return interneNumEcoEvalApi.getFacteurCaracterisation(critere, etape, nom, null, null).blockFirst(); + } catch (WebClientResponseException e) { + if (e.getStatusCode() != HttpStatusCode.valueOf(404)) { + throw new ExternalApiException(e); + } + } + return null; + } + @Cacheable(value = "ImpactMessagerie") public ImpactMessagerieDTO getMessagerie(String critere) { try { diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/CacheConfig.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/CacheConfig.java index ab24eb9dae3b196dd930f13184bd9d683861350f..16e83d1ad4b0f1dd0fb23068c444a44871a39643 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/CacheConfig.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/CacheConfig.java @@ -22,10 +22,14 @@ public class CacheConfig { "Criteres", "Hypothese", "TypeEquipement", + "TypeItem", "CorrespondanceRefEquipement", + "FacteurCaracterisationMixElec", + "FacteurCaracterisation", "ImpactEquipement", "ImpactReseau", "MixElectrique", + "ImpactOperationNonIT", "ImpactMessagerie", }, allEntries = true) @Scheduled(fixedRateString = "${numecoeval.cache.ttl}", timeUnit = TimeUnit.MINUTES) diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/DomainConfiguration.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/DomainConfiguration.java index 0986a1d432c9c31a0044b6d0794c73a835021b1a..d41eaae9ae9a7359c783b2853d15e3b6d9f88d6e 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/DomainConfiguration.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/config/DomainConfiguration.java @@ -15,34 +15,35 @@ public class DomainConfiguration { } @Bean - public CalculImpactEquipementPhysiqueService calculImpactEquipementPhysiqueService(DureeDeVieEquipementPhysiqueService dureeDeVieEquipementPhysiqueService, ObjectMapper objectMapper) { + public CalculImpactEquipementPhysiqueService calculImpactEquipementPhysiqueService(DureeDeVieEquipementPhysiqueService dureeDeVieEquipementPhysiqueService) { return new CalculImpactEquipementPhysiqueServiceImpl( - dureeDeVieEquipementPhysiqueService, - objectMapper - ); + dureeDeVieEquipementPhysiqueService); } @Bean - CalculImpactEquipementVirtuelService calculImpactEquipementVirtuelService(ObjectMapper objectMapper) { - return new CalculImpactEquipementVirtuelServiceImpl(objectMapper); + CalculImpactEquipementVirtuelService calculImpactEquipementVirtuelService() { + return new CalculImpactEquipementVirtuelServiceImpl(); } @Bean - CalculImpactApplicationService calculImpactApplicationService(ObjectMapper objectMapper) { - return new CalculImpactApplicationServiceImpl(objectMapper); + CalculImpactApplicationService calculImpactApplicationService() { + return new CalculImpactApplicationServiceImpl(); } @Bean - public CalculImpactReseauService calculImpactReseauService(ObjectMapper objectMapper) { - return new CalculImpactReseauServiceImpl( - objectMapper - ); + public CalculImpactReseauService calculImpactReseauService() { + return new CalculImpactReseauServiceImpl(); + } + + @Bean + public CalculImpactOperationNonITService calculImpactOperationNonITService() { + return new CalculImpactOperationNonITServiceImpl(); } @Bean CalculImpactMessagerieService calculImpactMessagerieService(ObjectMapper objectMapper) { - return new CalculImpactMessagerieServiceImpl(objectMapper); + return new CalculImpactMessagerieServiceImpl(); } } diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/export/IndicateurController.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/export/IndicateurController.java index f3b51d7325945f1397e17058fbe5199df32975de..e3338c81897cc42f2a03e3fa013405415ab9aaf8 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/export/IndicateurController.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/export/IndicateurController.java @@ -16,6 +16,9 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +/** + * Création d'API utilisées uniquement pour les tests e2e + */ @RestController @Slf4j @Profile("!prod & !test") @@ -127,6 +130,31 @@ public class IndicateurController { } } + @GetMapping("/operationNonITCsv") + public String getOperationNonITList( + @RequestParam String nomLot, + @RequestParam String nomOrganisation, + @RequestParam String fields + ) { + + try (Connection conn = dataSource.getConnection()) { + try (var ps = conn.prepareStatement(String.format(""" + SELECT %s + FROM ind_indicateur_impact_operation_non_it + WHERE nom_lot = ? AND nom_organisation = ? + ORDER BY nom_item_non_it, critere, etapeacv; + """, fields))) { + + ps.setString(1, nomLot); + ps.setString(2, nomOrganisation); + return resultSetToCsv(ps.executeQuery()); + } + } catch (SQLException e) { + log.error("SQl exception", e); + throw new RuntimeException(e); + } + } + private String resultSetToCsv(ResultSet rs) throws SQLException { List<String> lines = new ArrayList<>(); diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsApplicationController.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsApplicationController.java index f4b664a9246facabff8596ee11db75cca923a299..aaf3b2652ad73f43dd7a53bbd6a3dd425d2db14a 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsApplicationController.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsApplicationController.java @@ -31,9 +31,7 @@ public class CalculsApplicationController implements CalculsApplicationApi { public ResponseEntity<IndicateurImpactApplicationRest> calculerImpactApplication(DemandeCalculApplicationRest demandeCalculApplicationRest) { var demandeCalcul = domainMapper.toDomain(demandeCalculApplicationRest); - var indicateur = new CalculImpactApplicationServiceImpl( - objectMapper - ).calculImpactApplicatif(demandeCalcul); + var indicateur = new CalculImpactApplicationServiceImpl().calculImpactApplicatif(demandeCalcul); return checkIndicateurService.isOk(indicateur.getStatutIndicateur()) ? ResponseEntity.ok(domainMapper.toRest(indicateur)) : diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsEquipementPhysiqueController.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsEquipementPhysiqueController.java index a74e53bba840542455b3c7bc349c8003cd49adfd..83230222193895b1fd129ac3a9b13d9e556879a5 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsEquipementPhysiqueController.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsEquipementPhysiqueController.java @@ -25,7 +25,7 @@ public class CalculsEquipementPhysiqueController implements CalculsEquipementPhy DureeDeVieEquipementPhysiqueService dureeDeVieEquipementPhysiqueService; CheckIndicateurService checkIndicateurService; - + /** * POST /calculs/equipementPhysique * @@ -37,8 +37,7 @@ public class CalculsEquipementPhysiqueController implements CalculsEquipementPhy var demandeCalcul = domainMapper.toDomain(demandeCalculImpactEquipementPhysiqueRest); var indicateur = new CalculImpactEquipementPhysiqueServiceImpl( - dureeDeVieEquipementPhysiqueService, - objectMapper + dureeDeVieEquipementPhysiqueService ).calculerImpactEquipementPhysique(demandeCalcul); return checkIndicateurService.isOk(indicateur.getStatutIndicateur()) ? diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsEquipementVirtuelController.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsEquipementVirtuelController.java index 66ee73ecc2cfa991cd242b33b5ae2914be564567..089c1a897de3450164f25674c6908bde6f863387 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsEquipementVirtuelController.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsEquipementVirtuelController.java @@ -20,7 +20,7 @@ public class CalculsEquipementVirtuelController implements CalculsEquipementVirt ObjectMapper objectMapper; CheckIndicateurService checkIndicateurService; - + /** * POST /calculs/equipementVirtuel * @@ -31,9 +31,7 @@ public class CalculsEquipementVirtuelController implements CalculsEquipementVirt public ResponseEntity<IndicateurImpactEquipementVirtuelRest> calculerImpactEquipementVirtuel(DemandeCalculEquipementVirtuelRest demandeCalculEquipementVirtuelRest) { var demandeCalcul = domainMapper.toDomain(demandeCalculEquipementVirtuelRest); - var indicateur = new CalculImpactEquipementVirtuelServiceImpl( - objectMapper - ).calculerImpactEquipementVirtuel(demandeCalcul); + var indicateur = new CalculImpactEquipementVirtuelServiceImpl().calculerImpactEquipementVirtuel(demandeCalcul); return checkIndicateurService.isOk(indicateur.getStatutIndicateur()) ? ResponseEntity.ok(domainMapper.toRest(indicateur)) : diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsMessagerieController.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsMessagerieController.java index 79ad2e4b542d225c16ee84ab94ea42efec0949a0..dfcf986486d41cf1a38f9aeefa04ff710fa9ba4f 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsMessagerieController.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsMessagerieController.java @@ -31,9 +31,7 @@ public class CalculsMessagerieController implements CalculsMessagerieApi { public ResponseEntity<IndicateurImpactMessagerieRest> calculerImpactMessagerie(DemandeCalculMessagerieRest demandeCalculMessagerieRest) { var demandeCalcul = domainMapper.toDomain(demandeCalculMessagerieRest); - var indicateur = new CalculImpactMessagerieServiceImpl( - objectMapper - ).calculerImpactMessagerie(demandeCalcul); + var indicateur = new CalculImpactMessagerieServiceImpl().calculerImpactMessagerie(demandeCalcul); return checkIndicateurService.isOk(indicateur.getStatutIndicateur()) ? ResponseEntity.ok(domainMapper.toRest(indicateur)) : diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsOperationNonITController.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsOperationNonITController.java new file mode 100644 index 0000000000000000000000000000000000000000..df0e0561e3fbdf06716a7625b14df9cc09c83645 --- /dev/null +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsOperationNonITController.java @@ -0,0 +1,39 @@ +package org.mte.numecoeval.calculs.infrastructure.controller.rest.calculs; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactOperationNonITServiceImpl; +import org.mte.numecoeval.calculs.infrastructure.mapper.DomainMapper; +import org.mte.numecoeval.calculs.infrastructure.service.rest.calculs.CheckIndicateurService; +import org.mte.numecoeval.calculs.rest.generated.api.model.DemandeCalculImpactOperationNonITRest; +import org.mte.numecoeval.calculs.rest.generated.api.model.IndicateurImpactOperationNonITRest; +import org.mte.numecoeval.calculs.rest.generated.api.server.CalculsOperationNonItApi; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Slf4j +@AllArgsConstructor +public class CalculsOperationNonITController implements CalculsOperationNonItApi { + + DomainMapper domainMapper; + + CheckIndicateurService checkIndicateurService; + + /** + * POST /calculs/operationNonIT + * + * @param demandeCalculImpactOperationNonITRest (required) + * @return la liste d'indicateurs calcules + */ + @Override + public ResponseEntity<IndicateurImpactOperationNonITRest> calculerImpactOperationNonIT(DemandeCalculImpactOperationNonITRest demandeCalculImpactOperationNonITRest) { + var demandeCalcul = domainMapper.toDomain(demandeCalculImpactOperationNonITRest); + + var indicateur = new CalculImpactOperationNonITServiceImpl().calculerImpactOperationNonIT(demandeCalcul); + + return checkIndicateurService.isOk(indicateur.getStatutIndicateur()) ? + ResponseEntity.ok(domainMapper.toRest(indicateur)) : + ResponseEntity.badRequest().body(domainMapper.toRest(indicateur)); + } +} diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsReseauController.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsReseauController.java index 0e7f8f8912cb2b3736076b48c4279ea85620bd03..f859f33038835b82a3cd1f3af166e2af340eddf0 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsReseauController.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/rest/calculs/CalculsReseauController.java @@ -20,7 +20,7 @@ public class CalculsReseauController implements CalculsReseauApi { ObjectMapper objectMapper; CheckIndicateurService checkIndicateurService; - + /** * POST /calculs/reseau/equipementPhysique * @@ -31,9 +31,7 @@ public class CalculsReseauController implements CalculsReseauApi { public ResponseEntity<IndicateurImpactReseauRest> calculerImpactReseau(DemandeCalculImpactReseauEquipementPhysiqueRest demandeCalculImpactReseauEquipementPhysiqueRest) { var demandeCalcul = domainMapper.toDomain(demandeCalculImpactReseauEquipementPhysiqueRest); - var indicateur = new CalculImpactReseauServiceImpl( - objectMapper - ).calculerImpactReseau(demandeCalcul); + var indicateur = new CalculImpactReseauServiceImpl().calculerImpactReseau(demandeCalcul); return checkIndicateurService.isOk(indicateur.getStatutIndicateur()) ? ResponseEntity.ok(domainMapper.toRest(indicateur)) : diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/sync/calculs/SyncCalculsController.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/sync/calculs/SyncCalculsController.java index 4b1df0092404ef452c172c5602d5ec849c33c5d9..327e85e39a178f701f61365807f64f39066a77ff 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/sync/calculs/SyncCalculsController.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/controller/sync/calculs/SyncCalculsController.java @@ -4,13 +4,13 @@ import lombok.AllArgsConstructor; import org.mte.numecoeval.calculs.infrastructure.service.sync.calculs.SyncCalculService; import org.mte.numecoeval.calculs.sync.generated.api.model.ReponseCalculRest; import org.mte.numecoeval.calculs.sync.generated.api.model.SyncCalculRest; -import org.mte.numecoeval.calculs.sync.generated.api.server.CalculsEquipementPhysiqueEtMessagerieApi; +import org.mte.numecoeval.calculs.sync.generated.api.server.CalculsEquipementPhysiqueEtOperationNonItEtMessagerieApi; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RestController; @RestController @AllArgsConstructor -public class SyncCalculsController implements CalculsEquipementPhysiqueEtMessagerieApi { +public class SyncCalculsController implements CalculsEquipementPhysiqueEtOperationNonItEtMessagerieApi { SyncCalculService syncCalculService; diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/kafkalistener/ListenOperationNonIT.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/kafkalistener/ListenOperationNonIT.java new file mode 100644 index 0000000000000000000000000000000000000000..61b4e1c079b589448125f98653e40ab651990e3e --- /dev/null +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/kafkalistener/ListenOperationNonIT.java @@ -0,0 +1,21 @@ +package org.mte.numecoeval.calculs.infrastructure.kafkalistener; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.mte.numecoeval.calculs.infrastructure.service.calcul.MainOperationNonITService; +import org.mte.numecoeval.topic.data.OperationNonITDTO; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@AllArgsConstructor +public class ListenOperationNonIT { + + private MainOperationNonITService mainOperationNonITService; + + @KafkaListener(topics = "${numecoeval.topic.operationNonIT}", concurrency = "${numecoeval.topic.partition}") + public void consume(OperationNonITDTO OperationNonITDTO) { + mainOperationNonITService.calcul(OperationNonITDTO); + } +} \ No newline at end of file diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/DomainMapper.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/DomainMapper.java index a5c6c049c9ec4b54b8de7e4e5b7475ec65e687dd..47ef6c1b8ad71bac48517f30bbf97ce2815951a8 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/DomainMapper.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/DomainMapper.java @@ -22,7 +22,9 @@ public interface DomainMapper { Messagerie toDomain(MessagerieRest rest); - /*Référentiels*/ + OperationNonIT toDomain(OperationNonITRest rest); + + /* Référentiels */ ReferentielTypeEquipement toDomain(TypeEquipementRest rest); @@ -58,6 +60,8 @@ public interface DomainMapper { IndicateurImpactReseauRest toRest(ImpactReseau domain); + IndicateurImpactOperationNonITRest toRest(ImpactOperationNonIT domain); + IndicateurImpactMessagerieRest toRest(ImpactMessagerie domain); /*Demandes*/ @@ -66,13 +70,16 @@ public interface DomainMapper { @Mapping(target = "dateCalcul", expression = "java(java.time.LocalDateTime.now())") DemandeCalculImpactReseau toDomain(DemandeCalculImpactReseauEquipementPhysiqueRest rest); - + @Mapping(target = "dateCalcul", expression = "java(java.time.LocalDateTime.now())") DemandeCalculImpactEquipementVirtuel toDomain(DemandeCalculEquipementVirtuelRest rest); @Mapping(target = "dateCalcul", expression = "java(java.time.LocalDateTime.now())") DemandeCalculImpactApplication toDomain(DemandeCalculApplicationRest rest); + @Mapping(target = "dateCalcul", expression = "java(java.time.LocalDateTime.now())") + DemandeCalculImpactOperationNonIT toDomain(DemandeCalculImpactOperationNonITRest rest); + @Mapping(target = "dateCalcul", expression = "java(java.time.LocalDateTime.now())") DemandeCalculImpactMessagerie toDomain(DemandeCalculMessagerieRest rest); } diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/EntreesMapper.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/EntreesMapper.java index be2c6c0b8abde8a9f04c54f6d5109218c17f355c..7041fe496b8c6332aaf000a02c8702c45478ebac 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/EntreesMapper.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/EntreesMapper.java @@ -4,9 +4,11 @@ import org.mapstruct.Mapper; import org.mte.numecoeval.calculs.domain.data.entree.DataCenter; import org.mte.numecoeval.calculs.domain.data.entree.EquipementPhysique; import org.mte.numecoeval.calculs.domain.data.entree.Messagerie; +import org.mte.numecoeval.calculs.domain.data.entree.OperationNonIT; import org.mte.numecoeval.topic.data.DataCenterDTO; import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO; import org.mte.numecoeval.topic.data.MessagerieDTO; +import org.mte.numecoeval.topic.data.OperationNonITDTO; @Mapper(componentModel = "spring") public interface EntreesMapper { @@ -15,6 +17,8 @@ public interface EntreesMapper { DataCenter toDomain(DataCenterDTO dto); + OperationNonIT toDomain(OperationNonITDTO dto); + Messagerie toDomain(MessagerieDTO messagerieDTO); } diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/ReferentielMapper.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/ReferentielMapper.java index b6937550fd7a1828959e8792c1c29fe90ff8ba3d..6624cc54ba6c58c9e158af0f77cba530a80f1e06 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/ReferentielMapper.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/mapper/ReferentielMapper.java @@ -23,6 +23,10 @@ public interface ReferentielMapper { List<ReferentielHypothese> toListHypothese(List<HypotheseDTO> hypotheseDTO); + ReferentielFacteurCaracterisation toFacteurCaracterisation(FacteurCaracterisationDTO facteurCaracterisationDTO); + + List<ReferentielFacteurCaracterisation> toListFacteurCaracterisation(List<FacteurCaracterisationDTO> facteurCaracterisationDTO); + ReferentielImpactEquipement toImpactEquipement(ImpactEquipementDTO impactEquipementDTO); List<ReferentielImpactEquipement> toListImpactEquipement(List<ImpactEquipementDTO> impactEquipementDTO); @@ -38,4 +42,6 @@ public interface ReferentielMapper { ReferentielCorrespondanceRefEquipement toCorrespondanceRefEquipement(CorrespondanceRefEquipementDTO dto); ReferentielTypeEquipement toTypeEquipement(TypeEquipementDTO dto); + + ReferentielTypeItem toTypeItem(TypeItemDTO dto); } diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/IndicateurRepository.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/IndicateurRepository.java index 388d866fb95fbd6ececfd17160af9fd1a51f0faf..aa07000348378e9c0c1e6734ffb29e87d237f4e7 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/IndicateurRepository.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/IndicateurRepository.java @@ -31,7 +31,7 @@ public class IndicateurRepository { statut_indicateur, trace, version_calcul, conso_elec_moyenne, impact_unitaire, quantite, type_equipement, unite, statut_equipement_physique, nom_lot, nom_source_donnee, nom_source_donnee_discriminator) - VALUES (?, ?, ?, ?, ?, ?,?, ?, ?, ?, ?,?, ?, ?, ?,?, ?, ?, ?,?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?) """; private static final String INSERT_EQUIPEMENT_VIRTUEL_QUERY = """ @@ -50,16 +50,25 @@ public class IndicateurRepository { nom_equipement_virtuel, nom_entite, nom_entite_discriminator, source, statut_indicateur, trace, version_calcul, domaine, sous_domaine, impact_unitaire, unite, conso_elec_moyenne, nom_lot, nom_source_donnee, nom_source_donnee_discriminator) - VALUES (?, ?, ?, ?,?, ?, ?, ?,?, ?, ?, ?,?, ?, ?, ?,?, ?, ?, ?,?,?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """; + private static final String INSERT_OPERATION_NON_IT_QUERY = """ + INSERT INTO ind_indicateur_impact_operation_non_it + (date_calcul, date_lot, date_lot_discriminator, nom_organisation, nom_organisation_discriminator, etapeacv, + critere, nom_item_non_it, nom_entite, nom_entite_discriminator, source, + statut_indicateur, trace, version_calcul, conso_elec_moyenne, + impact_unitaire, quantite, type_item, unite, + nom_lot, nom_source_donnee, nom_source_donnee_discriminator) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ,? ,?) + """; private static final String INSERT_MESSAGERIE_QUERY = """ INSERT INTO ind_indicateur_impact_messagerie (date_calcul, date_lot, date_lot_discriminator, nom_organisation, nom_organisation_discriminator, critere, mois_annee, nom_entite, nom_entite_discriminator, source, statut_indicateur, trace, version_calcul, impact_mensuel, unite, nombre_mail_emis, volume_total_mail_emis, nom_lot, nom_source_donnee, nom_source_donnee_discriminator) - VALUES (?, ?, ?, ?,?, ?, ?, ?,?, ?, ?, ?,?, ?, ?, ?,?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """; private static final String INSERT_RESEAU_QUERY = """ @@ -216,6 +225,55 @@ public class IndicateurRepository { } } + /** + * Sauvegarde tous les indicateurs 'OperationNonIT' en base de données + * + * @param impactOperationNonITs liste indicateurs des Opérations non IT + */ + public void saveIndicateursOperationNonIT(List<ImpactOperationNonIT> impactOperationNonITs) { + if (impactOperationNonITs.isEmpty()) return; + + try (Connection conn = dataSource.getConnection()) { + conn.setAutoCommit(false); + + try (var ps = conn.prepareStatement(INSERT_OPERATION_NON_IT_QUERY)) { + + for (ImpactOperationNonIT indicateur : impactOperationNonITs) { + ps.setTimestamp(1, PreparedStatementUtils.getTimestampFromLocalDateTime(indicateur.getDateCalcul())); + ps.setDate(2, PreparedStatementUtils.getDateFromLocalDate(indicateur.getDateLot())); + ps.setDate(3, PreparedStatementUtils.getDateFromLocalDate(Optional.ofNullable(indicateur.getDateLot()).orElse(LocalDate.EPOCH))); + ps.setString(4, indicateur.getNomOrganisation()); + ps.setString(5, StringUtils.defaultString(indicateur.getNomOrganisation())); + ps.setString(6, indicateur.getEtapeACV()); + ps.setString(7, indicateur.getCritere()); + ps.setString(8, indicateur.getNomItemNonIT()); + ps.setString(9, indicateur.getNomEntite()); + ps.setString(10, StringUtils.defaultString(indicateur.getNomEntite())); + ps.setString(11, indicateur.getSource()); + ps.setString(12, indicateur.getStatutIndicateur()); + ps.setString(13, indicateur.getTrace()); + ps.setString(14, indicateur.getVersionCalcul()); + PreparedStatementUtils.setDoubleValue(ps, 15, indicateur.getConsoElecMoyenne()); + PreparedStatementUtils.setDoubleValue(ps, 16, indicateur.getImpactUnitaire()); + PreparedStatementUtils.setIntValue(ps, 17, indicateur.getQuantite().intValue()); + ps.setString(18, indicateur.getTypeItem()); + ps.setString(19, indicateur.getUnite()); + ps.setString(20, indicateur.getNomLot()); + ps.setString(21, indicateur.getNomSourceDonnee()); + ps.setString(22, StringUtils.defaultString(indicateur.getNomSourceDonnee())); + ps.addBatch(); + } + + ps.executeBatch(); + } + + conn.commit(); + } catch (SQLException e) { + log.error("Une erreur s'est produite lors de l'insertion dans PostgreSQL. Exception: ", e); + throw new DatabaseException(e); + } + } + /** * Sauvegarde tous les indicateurs 'messagerie' en base de données * @@ -278,7 +336,7 @@ public class IndicateurRepository { * @param nomEquipementPhysique le nom de l'equipement physique * @param nomLot le nomLot */ - public void clearIndicateurs(String nomEquipementPhysique, String nomLot) { + public void clearIndicateursEquipement(String nomEquipementPhysique, String nomLot) { try (Connection conn = dataSource.getConnection()) { conn.setAutoCommit(false); @@ -324,4 +382,24 @@ public class IndicateurRepository { throw new DatabaseException(e); } } + + public void clearIndicateursOperation(String nomOperationNonIT, String nomLot) { + + try (Connection conn = dataSource.getConnection()) { + conn.setAutoCommit(false); + + try (var ps = conn.prepareStatement(""" + DELETE FROM ind_indicateur_impact_operation_non_it + WHERE nom_lot = ? AND nom_item_non_it = ? + """)) { + ps.setString(1, nomLot); + ps.setString(2, nomOperationNonIT); + ps.execute(); + } + conn.commit(); + } catch (SQLException e) { + log.error("Une erreur s'est produite lors de l'insertion dans PostgreSQL. Exception: ", e); + throw new DatabaseException(e); + } + } } diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/OperationNonITRepository.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/OperationNonITRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..a267c358571d7739fe72f09264be379fc16b9d64 --- /dev/null +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/repository/OperationNonITRepository.java @@ -0,0 +1,80 @@ +package org.mte.numecoeval.calculs.infrastructure.repository; + +import lombok.extern.slf4j.Slf4j; +import org.mte.numecoeval.calculs.domain.exception.DatabaseException; +import org.mte.numecoeval.common.utils.ResultSetUtils; +import org.mte.numecoeval.topic.data.OperationNonITDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +@Component +@Slf4j +public class OperationNonITRepository { + + @Autowired + private DataSource dataSource; + + private static final String COLUMN_NAME_NOM_COURT_DATACENTER = "nom_court_datacenter"; + + public List<OperationNonITDTO> findOperationNonITDTOs(List<Long> ids) { + List<OperationNonITDTO> result = new ArrayList<>(); + + try (Connection conn = dataSource.getConnection()) { + try (var ps = conn.prepareStatement(""" + SELECT * + FROM en_operation_non_it opnit + WHERE id = ANY (?) + """)) { + + ps.setArray(1, conn.createArrayOf("long", ids.toArray(new Long[0]))); + + var rs = ps.executeQuery(); + while (rs.next()) { + result.add(OperationNonITDTO.builder() + .id(rs.getLong("id")) + .nomLot(rs.getString("nom_lot")) + .dateLot(ResultSetUtils.getLocalDate(rs, "date_lot")) + .nomOrganisation(rs.getString("nom_organisation")) + .nomItemNonIT(rs.getString("nom_item_non_it")) + .quantite(ResultSetUtils.getDouble(rs, "quantite")) + .type(rs.getString("type")) + .dureeDeVie(ResultSetUtils.getDouble(rs, "duree_de_vie")) + .localisation(rs.getString("localisation")) + .nomEntite(rs.getString("nom_entite")) + .nomSourceDonnee(rs.getString("nom_source_donnee")) + .nomCourtDatacenter(rs.getString(COLUMN_NAME_NOM_COURT_DATACENTER)) + .description(rs.getString("description")) + .consoElecAnnuelle(ResultSetUtils.getDouble(rs, "conso_elec_annuelle")) + .build()); + } + } + } catch (SQLException e) { + log.error("Une erreur s'est produite lors de la selection dans PostgreSQL. Exception: ", e); + throw new DatabaseException(e); + } + + return result; + } + + public void setStatutToTraite(Long id) { + try (Connection conn = dataSource.getConnection()) { + try (var ps = conn.prepareStatement(""" + UPDATE en_operation_non_it + SET statut_traitement = 'TRAITE', date_update = now() + WHERE id = ? + """)) { + ps.setLong(1, id); + ps.execute(); + } + } catch (SQLException e) { + log.error("Une erreur s'est produite lors de la selection dans PostgreSQL. Exception: ", e); + throw new DatabaseException(e); + } + } +} diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculOperationNonITService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculOperationNonITService.java new file mode 100644 index 0000000000000000000000000000000000000000..a99aa3fde5f8be27613ab718021c875baffaa297 --- /dev/null +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/CalculOperationNonITService.java @@ -0,0 +1,62 @@ +package org.mte.numecoeval.calculs.infrastructure.service.calcul; + +import lombok.AllArgsConstructor; +import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactOperationNonIT; +import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactOperationNonIT; +import org.mte.numecoeval.calculs.domain.model.CalculOperationNonIT; +import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactOperationNonITService; +import org.mte.numecoeval.calculs.infrastructure.mapper.EntreesMapper; +import org.mte.numecoeval.calculs.infrastructure.mapper.ReferentielMapper; +import org.mte.numecoeval.calculs.referentiels.generated.api.model.CritereDTO; +import org.mte.numecoeval.calculs.referentiels.generated.api.model.EtapeDTO; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +@Service +@AllArgsConstructor +public class CalculOperationNonITService { + + EntreesMapper entreesMapper; + + ReferentielMapper referentielMapper; + + CalculImpactOperationNonITService calculImpactOperationNonITService; + + /** + * Calcule les impacts d'une opération non IT + * Returne la liste d'impacts en iterant par (etape, critere) + * + * @param calculOperationNonIT l'opération non IT enrichi + * @return la liste d'impacts + */ + public List<ImpactOperationNonIT> calculImpactOperationNonIT(CalculOperationNonIT calculOperationNonIT) { + + LocalDateTime dateCalcul = LocalDateTime.now(); + + List<ImpactOperationNonIT> impactOperationNonITList = new ArrayList<>(); + + for (EtapeDTO etapeDTO : calculOperationNonIT.getEtapes()) { + for (CritereDTO critereDTO : calculOperationNonIT.getCriteres()) { + + DemandeCalculImpactOperationNonIT demandeCalculImpactOperationNonIT = DemandeCalculImpactOperationNonIT.builder() + .dateCalcul(dateCalcul) + .operationNonIT(entreesMapper.toDomain(calculOperationNonIT.getOperationNonIT())) + .etape(referentielMapper.toEtape(etapeDTO)) + .critere(referentielMapper.toCritere(critereDTO)) + .typeItem(referentielMapper.toTypeItem(calculOperationNonIT.getTypeItem())) + .hypotheses(referentielMapper.toListHypothese(calculOperationNonIT.getHypotheses())) + .facteurCaracterisations(referentielMapper.toListFacteurCaracterisation(calculOperationNonIT.getFacteurCaracterisations())) + .build(); + var impact = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalculImpactOperationNonIT); + if (impact != null) { + impactOperationNonITList.add(impact); + } + } + } + return impactOperationNonITList; + + } +} diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/IntegrationCalculEquipementsService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/IntegrationCalculEquipementsService.java index 28a5d72b2d11c71c07aadd6f5a36c906ae47a2a2..1eff91ae2f216ca92e67cdea259a994cde814312 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/IntegrationCalculEquipementsService.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/IntegrationCalculEquipementsService.java @@ -57,7 +57,7 @@ public class IntegrationCalculEquipementsService { String nomEquipementPhysique = equipementPhysiqueDTO.getNomEquipementPhysique(); // delete existing indicateurs - indicateurRepository.clearIndicateurs(nomEquipementPhysique, nomLot); + indicateurRepository.clearIndicateursEquipement(nomEquipementPhysique, nomLot); var ttAfterClear = System.currentTimeMillis(); @@ -111,11 +111,11 @@ public class IntegrationCalculEquipementsService { totalNbApplication, ttAfterSaveStatus - ttStart, ttAfterClear - ttStart, - ttAfterFindEqV -ttAfterClear, + ttAfterFindEqV - ttAfterClear, ttAfterEqVAndApp - ttAfterFindEqV, ttAfterSave - ttAfterEqVAndApp, ttAfterSaveStatus - ttAfterSave - ); + ); CalculSizes result = new CalculSizes(); result.setNbEquipementPhysique(1); diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/IntegrationCalculOperationNonITService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/IntegrationCalculOperationNonITService.java new file mode 100644 index 0000000000000000000000000000000000000000..6d6986738d273ea1ce0e1701c113b4d2af90e945 --- /dev/null +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/IntegrationCalculOperationNonITService.java @@ -0,0 +1,60 @@ +package org.mte.numecoeval.calculs.infrastructure.service.calcul; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactOperationNonIT; +import org.mte.numecoeval.calculs.domain.model.CalculOperationNonIT; +import org.mte.numecoeval.calculs.domain.model.CalculSizes; +import org.mte.numecoeval.calculs.infrastructure.repository.IndicateurRepository; +import org.mte.numecoeval.calculs.infrastructure.repository.OperationNonITRepository; +import org.mte.numecoeval.topic.data.OperationNonITDTO; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Slf4j +@Service +@AllArgsConstructor +public class IntegrationCalculOperationNonITService { + + IndicateurRepository indicateurRepository; + OperationNonITRepository operationNonITRepository; + CalculOperationNonITService calculOperationNonITService; + + /** + * Calcul les impacts d'une opération non IT + * + * @param calculOperationNonIT l'opération Non IT + * @return le nombre d'elements traites sous forme CalculSizes + */ + public CalculSizes calculImpactOperationNonIT(CalculOperationNonIT calculOperationNonIT) { + + if (calculOperationNonIT == null) return null; + + OperationNonITDTO operationNonITDTO = calculOperationNonIT.getOperationNonIT(); + String nomLot = operationNonITDTO.getNomLot(); + String nomOrganisation = operationNonITDTO.getNomOrganisation(); + String nomOperationNonIT = operationNonITDTO.getNomItemNonIT(); + + // delete existing indicateurs + indicateurRepository.clearIndicateursOperation(nomOperationNonIT, nomLot); + + List<ImpactOperationNonIT> impactOperationNonITList = calculOperationNonITService.calculImpactOperationNonIT(calculOperationNonIT); + + // save impacts into db + indicateurRepository.saveIndicateursOperationNonIT(impactOperationNonITList); + + // set statut of the operation to TRAITE + operationNonITRepository.setStatutToTraite(operationNonITDTO.getId()); + + log.info("{} - {} - {} : Calcul impacts opérations non IT: {}", + nomOrganisation, nomLot, operationNonITDTO.getDateLot(), + nomOperationNonIT + ); + + CalculSizes result = new CalculSizes(); + result.setNbOperationNonIT(1); + result.setNbIndicateurOperationNonIT(impactOperationNonITList.size()); + return result; + } +} \ No newline at end of file diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/MainOperationNonITService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/MainOperationNonITService.java new file mode 100644 index 0000000000000000000000000000000000000000..8c042810a92758a9f4861b1fbdde180823c9a5c6 --- /dev/null +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/MainOperationNonITService.java @@ -0,0 +1,23 @@ +package org.mte.numecoeval.calculs.infrastructure.service.calcul; + +import lombok.AllArgsConstructor; +import org.mte.numecoeval.calculs.domain.model.CalculSizes; +import org.mte.numecoeval.calculs.infrastructure.service.enrichissement.EnrichissementOperationNonITService; +import org.mte.numecoeval.topic.data.OperationNonITDTO; +import org.springframework.stereotype.Service; + +@Service +@AllArgsConstructor +public class MainOperationNonITService { + + private EnrichissementOperationNonITService enrichissementOperationNonITService; + private IntegrationCalculOperationNonITService integrationCalculOperationNonITService; + + public CalculSizes calcul(OperationNonITDTO operationNonITDTO) { + + var eqPhEnrichi = enrichissementOperationNonITService.serviceEnrichissementOperationNonIT(operationNonITDTO); + return integrationCalculOperationNonITService.calculImpactOperationNonIT(eqPhEnrichi); + + } + +} diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/enrichissement/EnrichissementEquipementPhysiqueService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/enrichissement/EnrichissementEquipementPhysiqueService.java index 1a23d86f413e12af269fa25a1b424d6a11af2520..73114e06370b5685d071933d6f88c5572e1d1ff1 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/enrichissement/EnrichissementEquipementPhysiqueService.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/enrichissement/EnrichissementEquipementPhysiqueService.java @@ -1,21 +1,26 @@ package org.mte.numecoeval.calculs.infrastructure.service.enrichissement; -import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.mte.numecoeval.calculs.domain.model.CalculEquipementPhysique; import org.mte.numecoeval.calculs.infrastructure.client.ReferentielClient; import org.mte.numecoeval.calculs.referentiels.generated.api.model.HypotheseDTO; import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import java.util.ArrayList; +import java.util.Arrays; @Slf4j @Service -@AllArgsConstructor public class EnrichissementEquipementPhysiqueService { + @Value("${numecoeval.hypotheses.equipementPhysique}") + private String hypothesesEquipementPhysique; + + @Autowired private ReferentielClient referentielClient; public CalculEquipementPhysique serviceEnrichissementEquipementPhysique(EquipementPhysiqueDTO equipementPhysiqueDTO) { @@ -33,15 +38,12 @@ public class EnrichissementEquipementPhysiqueService { calculEquipementPhysique.setCriteres(referentielClient.getCriteres()); var hypotheses = new ArrayList<HypotheseDTO>(); - var hDuree = referentielClient.getHypothese("dureeVieParDefaut"); - var hPue = referentielClient.getHypothese("PUEParDefaut"); - var tuBYOD = referentielClient.getHypothese("taux_utilisation_BYOD"); - var tuCOPE = referentielClient.getHypothese("taux_utilisation_COPE"); - - if (hDuree != null) hypotheses.add(hDuree); - if (hPue != null) hypotheses.add(hPue); - if (tuBYOD != null) hypotheses.add(tuBYOD); - if (tuCOPE != null) hypotheses.add(tuCOPE); + + Arrays.stream(hypothesesEquipementPhysique.replaceAll(" +", "").split(",")) + .forEach(hypothese -> { + var h = referentielClient.getHypothese(hypothese); + if (h != null) hypotheses.add(h); + }); calculEquipementPhysique.setHypotheses(hypotheses); diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/enrichissement/EnrichissementOperationNonITService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/enrichissement/EnrichissementOperationNonITService.java new file mode 100644 index 0000000000000000000000000000000000000000..e386fc9d020ed927499a789c258a4a12b9fd8a65 --- /dev/null +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/enrichissement/EnrichissementOperationNonITService.java @@ -0,0 +1,71 @@ +package org.mte.numecoeval.calculs.infrastructure.service.enrichissement; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.mte.numecoeval.calculs.domain.model.CalculOperationNonIT; +import org.mte.numecoeval.calculs.infrastructure.client.ReferentielClient; +import org.mte.numecoeval.calculs.referentiels.generated.api.model.HypotheseDTO; +import org.mte.numecoeval.topic.data.OperationNonITDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Arrays; + +@Slf4j +@Service +public class EnrichissementOperationNonITService { + + @Value("${numecoeval.hypotheses.operationNonIt}") + private String hypothesesOperationNonIt; + + @Autowired + private ReferentielClient referentielClient; + + public CalculOperationNonIT serviceEnrichissementOperationNonIT(OperationNonITDTO operationNonITDTO) { + if (operationNonITDTO == null) return null; + + log.debug("{} - {} - {} : Enrichissement d'une opération non IT : Nom Item: {}, Type: {}", + operationNonITDTO.getNomOrganisation(), operationNonITDTO.getNomLot(), operationNonITDTO.getDateLot(), + operationNonITDTO.getNomItemNonIT(), operationNonITDTO.getType()); + + CalculOperationNonIT calculOperationNonIT = new CalculOperationNonIT(); + + calculOperationNonIT.setOperationNonIT(operationNonITDTO); + + calculOperationNonIT.setEtapes(referentielClient.getEtapes()); + calculOperationNonIT.setCriteres(referentielClient.getCriteres()); + calculOperationNonIT.setTypeItem(referentielClient.getTypeItem(operationNonITDTO.getType())); + + var hypotheses = new ArrayList<HypotheseDTO>(); + var hTypeItem = referentielClient.getHypothese(referentielClient.getTypeItem(operationNonITDTO.getType()).getRefHypothese()); + if (hTypeItem != null) hypotheses.add(hTypeItem); + + Arrays.stream(hypothesesOperationNonIt.replaceAll(" +", "").split(",")) + .forEach(hypothese -> { + var h = referentielClient.getHypothese(hypothese); + if (h != null) hypotheses.add(h); + }); + + calculOperationNonIT.setHypotheses(hypotheses); + calculOperationNonIT.setFacteurCaracterisations(new ArrayList<>()); + + for (var critere : calculOperationNonIT.getCriteres()) { + for (var etape : calculOperationNonIT.getEtapes()) { + if (calculOperationNonIT.getTypeItem() != null && StringUtils.isNotBlank(calculOperationNonIT.getTypeItem().getRefItemParDefaut())) { + calculOperationNonIT.getFacteurCaracterisations().add( + referentielClient.getFacteurCaracterisationByCritereAndEtapeAndNom( + critere.getNomCritere(), + etape.getCode(), + calculOperationNonIT.getTypeItem().getRefItemParDefaut() + ) + ); + } + } + var mixElec = referentielClient.getMixElectriqueFromFacteurCaracterisation(critere.getNomCritere(), operationNonITDTO.getLocalisation()); + if (mixElec != null) calculOperationNonIT.getFacteurCaracterisations().add(mixElec); + } + return calculOperationNonIT; + } +} diff --git a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/sync/calculs/SyncCalculService.java b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/sync/calculs/SyncCalculService.java index 7afd35344fd1abee4707a2d308cf521b332fc464..5a84a5dcce49c707df48f0a6d6e2b8a701b85629 100644 --- a/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/sync/calculs/SyncCalculService.java +++ b/services/api-event-calculs/src/main/java/org/mte/numecoeval/calculs/infrastructure/service/sync/calculs/SyncCalculService.java @@ -4,8 +4,10 @@ import lombok.AllArgsConstructor; import org.mte.numecoeval.calculs.domain.model.CalculSizes; import org.mte.numecoeval.calculs.infrastructure.repository.EquipementPhysiqueRepository; import org.mte.numecoeval.calculs.infrastructure.repository.MessagerieRepository; +import org.mte.numecoeval.calculs.infrastructure.repository.OperationNonITRepository; import org.mte.numecoeval.calculs.infrastructure.service.calcul.MainEquipementPhysiqueService; import org.mte.numecoeval.calculs.infrastructure.service.calcul.MainMessagerieService; +import org.mte.numecoeval.calculs.infrastructure.service.calcul.MainOperationNonITService; import org.mte.numecoeval.calculs.sync.generated.api.model.ReponseCalculRest; import org.mte.numecoeval.calculs.sync.generated.api.model.SyncCalculRest; import org.springframework.stereotype.Service; @@ -18,11 +20,12 @@ import java.util.Objects; public class SyncCalculService { private EquipementPhysiqueRepository equipementPhysiqueRepository; + private OperationNonITRepository operationNonITRepository; private MessagerieRepository messagerieRepository; private MainEquipementPhysiqueService mainEquipementPhysiqueService; + private MainOperationNonITService mainOperationNonITService; private MainMessagerieService mainMessagerieService; - public ReponseCalculRest calcul(SyncCalculRest syncCalculRest) { var result = new ReponseCalculRest(); @@ -36,16 +39,20 @@ public class SyncCalculService { result.setNbrEquipementVirtuel(calculSizesList.stream().map(CalculSizes::getNbEquipementVirtuel).reduce(0L, Long::sum)); result.setNbrApplication(calculSizesList.stream().map(CalculSizes::getNbApplication).reduce(0L, Long::sum)); } - + if (syncCalculRest.getOperationNonITIds() != null && !syncCalculRest.getOperationNonITIds().isEmpty()) { + List<CalculSizes> calculSizesOperationNonITList = operationNonITRepository.findOperationNonITDTOs(syncCalculRest.getOperationNonITIds()).stream() + .map(operationNonITDTO -> mainOperationNonITService.calcul(operationNonITDTO)) + .filter(Objects::nonNull) + .toList(); + result.setNbrOperationNonIT(calculSizesOperationNonITList.stream().map(CalculSizes::getNbOperationNonIT).reduce(0L, Long::sum)); + } if (syncCalculRest.getMessagerieIds() != null && !syncCalculRest.getMessagerieIds().isEmpty()) { List<CalculSizes> calculSizesMessagerieList = messagerieRepository.findMessagerieDTOList(syncCalculRest.getMessagerieIds()).stream() .map(messagerieDTO -> mainMessagerieService.calcul(messagerieDTO)) .filter(Objects::nonNull) .toList(); - result.setNbrMessagerie(calculSizesMessagerieList.stream().map(CalculSizes::getNbMessagerie).reduce(0L, Long::sum)); } - return result; } } diff --git a/services/api-event-calculs/src/main/resources/application.yaml b/services/api-event-calculs/src/main/resources/application.yaml index 9be26cc42717c5b2bea44eace88446a76609714d..22e10dfe982e039d484f53aecc6710e8d631002a 100644 --- a/services/api-event-calculs/src/main/resources/application.yaml +++ b/services/api-event-calculs/src/main/resources/application.yaml @@ -30,9 +30,13 @@ spring: # Application numecoeval: + hypotheses: + equipementPhysique: "dureeVieParDefaut, PUEParDefaut, taux_utilisation_BYOD, taux_utilisation_COPE" + operationNonIt: "dureeVieParDefaut, PUEParDefaut, TAUX_VEHICULE_HYBRIDE, dureeVieBatimentParDefaut" topic: partition: "4" equipementPhysique: "entree_equipementPhysique" + operationNonIT: "entree_operationNonIT" messagerie: "entree_messagerie" referentiels: url: "http://localhost:18080" diff --git a/services/api-event-calculs/src/main/resources/schema.sql b/services/api-event-calculs/src/main/resources/schema.sql index eabe8a0465eb233e2b7885d62e97974a2b6b4a22..24e2e71fcf2d0fc376fb1e0ebfe653c1199e2d54 100644 --- a/services/api-event-calculs/src/main/resources/schema.sql +++ b/services/api-event-calculs/src/main/resources/schema.sql @@ -69,6 +69,28 @@ CREATE TABLE IF NOT EXISTS ind_indicateur_impact_application conso_elec_moyenne float8 NULL ); +CREATE TABLE IF NOT EXISTS ind_indicateur_impact_operation_non_it +( + date_calcul timestamp NULL, + date_lot date NULL, + nom_lot varchar(255) NULL, + etapeacv varchar(255) NULL, + critere varchar(255) NULL, + "source" varchar(255) NULL, + statut_indicateur varchar(255) NULL, + trace text NULL, + version_calcul varchar(255) NULL, + conso_elec_moyenne float8 NULL, + impact_unitaire float8 NULL, + quantite int4 NULL, + type_item varchar(255) NULL, + unite varchar(255) NULL, + nom_entite varchar(255) NULL, + nom_organisation varchar(255) NULL, + nom_source_donnee varchar(255) NULL, + nom_item_non_it varchar(255) NULL +); + CREATE TABLE IF NOT EXISTS ind_indicateur_impact_messagerie ( date_calcul timestamp NULL, @@ -112,6 +134,7 @@ CREATE INDEX IF NOT EXISTS idx_ind_eq_p__nom_lot_nom_equipement ON ind_indicat CREATE INDEX IF NOT EXISTS idx_ind_eq_v__nom_lot_nom_equipement ON ind_indicateur_impact_equipement_virtuel (nom_lot, nom_equipement); CREATE INDEX IF NOT EXISTS idx_ind_app__nom_lot_nom_equipement ON ind_indicateur_impact_application (nom_lot, nom_equipement_physique); CREATE INDEX IF NOT EXISTS idx_ind_reseau__nom_lot_nom_equipement ON ind_indicateur_impact_reseau (nom_lot, nom_equipement); +CREATE INDEX IF NOT EXISTS idx_ind_operation_non_it__nom_lot_nom_item_non_it ON ind_indicateur_impact_operation_non_it (nom_lot, nom_item_non_it); -- Lignes a supprimer dans les futures versions ALTER TABLE ind_indicateur_impact_equipement_virtuel ADD COLUMN IF NOT EXISTS nom_equipement_virtuel VARCHAR(255); diff --git a/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/EnrichissementEquipementPhysiqueServiceTest.java b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/EnrichissementEquipementPhysiqueServiceTest.java index 9751e08259dda7214b9e85b678b2d9cd11d22e0f..791717ec07073bbad79d85554b15bb65589cf64d 100644 --- a/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/EnrichissementEquipementPhysiqueServiceTest.java +++ b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/EnrichissementEquipementPhysiqueServiceTest.java @@ -15,13 +15,19 @@ import org.mte.numecoeval.calculs.infrastructure.client.ReferentielClient; import org.mte.numecoeval.calculs.infrastructure.service.enrichissement.EnrichissementEquipementPhysiqueService; import org.mte.numecoeval.calculs.referentiels.generated.api.model.*; import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.util.ReflectionTestUtils; import java.util.Arrays; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; -@ExtendWith(MockitoExtension.class) +@ExtendWith({MockitoExtension.class, SpringExtension.class}) +@ContextConfiguration(initializers = ConfigDataApplicationContextInitializer.class) class EnrichissementEquipementPhysiqueServiceTest { private static final ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule()); @@ -32,6 +38,9 @@ class EnrichissementEquipementPhysiqueServiceTest { @Mock ReferentielClient referentielClient; + @Value("${numecoeval.hypotheses.equipementPhysique}") + private String hypothesesEquipementPhysique; + EquipementPhysiqueDTO equipementPhysiqueDTO = mapper.readValue(""" { "id": 43702, @@ -70,6 +79,8 @@ class EnrichissementEquipementPhysiqueServiceTest { @BeforeEach void initMocksReferentiel() throws JsonProcessingException { + ReflectionTestUtils.setField(enrichissementEquipementPhysiqueService, "hypothesesEquipementPhysique", hypothesesEquipementPhysique); + /* MOCK REFERENTIEL : Etapes */ Mockito.lenient().when(referentielClient.getEtapes()).thenReturn(Arrays.asList(mapper.readValue(""" [{ "code": "UTILISATION", "libelle": "Using" }] diff --git a/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/EnrichissementOperationNonITServiceTest.java b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/EnrichissementOperationNonITServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..393ff04c53cdf15d790d74e4ec07171b39a8b1fe --- /dev/null +++ b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/calcul/EnrichissementOperationNonITServiceTest.java @@ -0,0 +1,150 @@ +package org.mte.numecoeval.calculs.infrastructure.service.calcul; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mte.numecoeval.calculs.infrastructure.client.ReferentielClient; +import org.mte.numecoeval.calculs.infrastructure.service.enrichissement.EnrichissementOperationNonITService; +import org.mte.numecoeval.calculs.referentiels.generated.api.model.*; +import org.mte.numecoeval.topic.data.OperationNonITDTO; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertNull; + +@ExtendWith({MockitoExtension.class, SpringExtension.class}) +@ContextConfiguration(initializers = ConfigDataApplicationContextInitializer.class) +class EnrichissementOperationNonITServiceTest { + + private static final ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule()); + + @InjectMocks + EnrichissementOperationNonITService enrichissementOperationNonITService; + + @Mock + ReferentielClient referentielClient; + + @Value("${numecoeval.hypotheses.operationNonIt}") + private String hypothesesOperationNonIt; + + OperationNonITDTO operationNonITDTO = mapper.readValue(""" + { + "id": 43701, + "nomItemNonIT": "reseau-fixe-rennes", + "quantite": 7.0, + "type": "reseau-fixe-france", + "dureeDeVie": 27.0, + "localisation": "France", + "nomEntite": "Entite test", + "nomSourceDonnee":"RCP-SI", + "nomCourtDatacenter": "dc1", + "description": "voici une description", + "consoElecAnnuelle": null, + "nomLot": "lot1", + "dateLot": "2024-04-24", + "nomOrganisation": "org" + } + """, OperationNonITDTO.class); + + EnrichissementOperationNonITServiceTest() throws JsonProcessingException { + } + + @BeforeEach + void initMocksReferentiel() throws JsonProcessingException { + ReflectionTestUtils.setField(enrichissementOperationNonITService, "hypothesesOperationNonIt", hypothesesOperationNonIt); + + /* MOCK REFERENTIEL : Etapes */ + Mockito.lenient().when(referentielClient.getEtapes()).thenReturn(Arrays.asList(mapper.readValue(""" + [{ "code": "UTILISATION", "libelle": "Using" }] + """, EtapeDTO[].class))); + + /* MOCK REFERENTIEL : Criteres */ + Mockito.lenient().when(referentielClient.getCriteres()).thenReturn(Arrays.asList(mapper.readValue(""" + [{ + "nomCritere": "Climate change", + "unite": "kg CO2 eq", + "description": "Greenhouse gases (GHG)" + }] + """, CritereDTO[].class))); + + /* MOCK REFERENTIEL : Hypothese */ + Mockito.lenient().when(referentielClient.getHypothese("CAPACITE_LIGNE_FIXE_FR")).thenReturn(mapper.readValue(""" + { + "code": "CAPACITE_LIGNE_FIXE_FR", + "valeur": 2640, + "source": "Rapport ADEME" + } + """, HypotheseDTO.class)); + + /* MOCK REFERENTIEL : TypeItem */ + Mockito.lenient().when(referentielClient.getTypeItem("reseau-fixe-france")).thenReturn(mapper.readValue(""" + { + "type": "reseau-fixe-france", + "categorie" : "RESEAU_FIXE", + "refHypothese" : "CAPACITE_LIGNE_FIXE_FR", + "refItemParDefaut" : "reseau-fixe-1" + } + """, TypeItemDTO.class)); + + /* MOCK REFERENTIEL : FacteurCaracterisation */ + Mockito.lenient().when(referentielClient.getFacteurCaracterisationByCritereAndEtapeAndNom("Climate change", "UTILISATION", "reseau-fixe-1")).thenReturn(mapper.readValue(""" + { + "nom": "reseau-fixe-1", + "etape" : "UTILISATION", + "critere" : "Climate change", + "localisation": "France", + "consoElecMoyenne": 12.7, + "valeur" : "8.34" + } + """, FacteurCaracterisationDTO.class)); + + /* MOCK REFERENTIEL : MixElectrique */ + Mockito.lenient().when(referentielClient.getMixElectriqueFromFacteurCaracterisation("Climate change", "France")).thenReturn(mapper.readValue(""" + { + "nom": "Electricity Mix/ Production mix/ Low voltage/ CL", + "etape" : "FABRICATION", + "critere" : "Climate change", + "categorie" : "electricity-mix", + "localisation": "France", + "valeur" : "0.0813225" + } + """, FacteurCaracterisationDTO.class)); + } + + @Test + void testServiceEnrichissementOperationNonIT_null() { + assertNull(enrichissementOperationNonITService.serviceEnrichissementOperationNonIT(null)); + } + + @Test + void testServiceEnrichissementOperationNonIT_via_typeItem() throws JsonProcessingException { + + var actual = enrichissementOperationNonITService.serviceEnrichissementOperationNonIT(operationNonITDTO); + + Assertions.assertEquals(1, actual.getEtapes().size()); + Assertions.assertEquals(1, actual.getCriteres().size()); + Assertions.assertEquals(1, actual.getHypotheses().size()); + + Assertions.assertEquals(2, actual.getFacteurCaracterisations().size()); + + Assertions.assertEquals("reseau-fixe-1", actual.getFacteurCaracterisations().get(0).getNom()); + Assertions.assertEquals(12.7, actual.getFacteurCaracterisations().get(0).getConsoElecMoyenne()); + Assertions.assertEquals(8.34, actual.getFacteurCaracterisations().get(0).getValeur()); + + Assertions.assertEquals("France", actual.getFacteurCaracterisations().get(1).getLocalisation()); + Assertions.assertEquals(0.0813225, actual.getFacteurCaracterisations().get(1).getValeur()); + } +} diff --git a/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/sync/calculs/SyncCalculServiceTest.java b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/sync/calculs/SyncCalculServiceTest.java index a32cfcdff34b00a8fa1e39f917a41b16cbacde38..8e601d8f5d7d0305ecb8882f18a7f147336ec6c8 100644 --- a/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/sync/calculs/SyncCalculServiceTest.java +++ b/services/api-event-calculs/src/test/java/org/mte/numecoeval/calculs/infrastructure/service/sync/calculs/SyncCalculServiceTest.java @@ -13,11 +13,14 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.mte.numecoeval.calculs.domain.model.CalculSizes; import org.mte.numecoeval.calculs.infrastructure.repository.EquipementPhysiqueRepository; import org.mte.numecoeval.calculs.infrastructure.repository.MessagerieRepository; +import org.mte.numecoeval.calculs.infrastructure.repository.OperationNonITRepository; import org.mte.numecoeval.calculs.infrastructure.service.calcul.MainEquipementPhysiqueService; import org.mte.numecoeval.calculs.infrastructure.service.calcul.MainMessagerieService; +import org.mte.numecoeval.calculs.infrastructure.service.calcul.MainOperationNonITService; import org.mte.numecoeval.calculs.sync.generated.api.model.SyncCalculRest; import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO; import org.mte.numecoeval.topic.data.MessagerieDTO; +import org.mte.numecoeval.topic.data.OperationNonITDTO; import java.util.List; @@ -33,7 +36,10 @@ class SyncCalculServiceTest { EquipementPhysiqueRepository equipementPhysiqueRepository; @Mock MainEquipementPhysiqueService mainEquipementPhysiqueService; - + @Mock + OperationNonITRepository operationNonITRepository; + @Mock + MainOperationNonITService mainOperationNonITService; @Mock MessagerieRepository messagerieRepository; @Mock @@ -91,4 +97,29 @@ class SyncCalculServiceTest { /* ASSERT */ Assertions.assertEquals(3, actual.getNbrMessagerie()); } + + @Test + void testSyncCalculService_withListOperationNonIT() throws JsonProcessingException { + /* MOCKS */ + Mockito.when(operationNonITRepository.findOperationNonITDTOs(any())).thenReturn(List.of( + new OperationNonITDTO(), + new OperationNonITDTO() + )); + + var calculSizes = new CalculSizes(); + calculSizes.setNbOperationNonIT(1); + calculSizes.setNbEquipementVirtuel(2); + calculSizes.setNbApplication(3); + + Mockito.when(mainOperationNonITService.calcul(any())).thenReturn(calculSizes); + + var syncCalculRest = new SyncCalculRest(); + syncCalculRest.setOperationNonITIds(List.of(1L, 2L)); + + /* EXECUTE */ + var actual = syncCalculService.calcul(syncCalculRest); + + /* ASSERT */ + Assertions.assertEquals(2, actual.getNbrOperationNonIT()); + } } diff --git a/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/EquipementPhysiqueIntegrationConfig.java b/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/EquipementPhysiqueIntegrationConfig.java index d7a8dc6965bedc51fa790582d478b4c28b9099a9..f826d65e94c96e7119ab6ec8ca17aeff44da38fd 100644 --- a/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/EquipementPhysiqueIntegrationConfig.java +++ b/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/EquipementPhysiqueIntegrationConfig.java @@ -84,7 +84,7 @@ public class EquipementPhysiqueIntegrationConfig { @Bean @InboundChannelAdapter( value = "entreeEquipementPhysiqueSplitter", - poller = @Poller(fixedDelay = "5000") + poller = @Poller(fixedDelay = "1000") ) @SuppressWarnings("java:S1452") // La classe JdbcPollingChannelAdapter n'est pas compatible avec une classe fixe public MessageSource<?> getEquipementPhysiqueToProcess(DataSource dataSource) { diff --git a/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/MessagerieIntegrationConfig.java b/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/MessagerieIntegrationConfig.java index 371fa3d976269198c7f976aa0a10f2162bb97e98..8cef865fa42a97e588a289587356d6842ce18d2a 100644 --- a/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/MessagerieIntegrationConfig.java +++ b/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/MessagerieIntegrationConfig.java @@ -69,7 +69,7 @@ public class MessagerieIntegrationConfig { @Bean @InboundChannelAdapter( value = "entreeMessagerieSplitter", - poller = @Poller(fixedDelay = "5000") + poller = @Poller(fixedDelay = "1000") ) @SuppressWarnings("java:S1452") // La classe JdbcPollingChannelAdapter n'est pas compatible avec une classe fixe public MessageSource<?> getMessagerieToProcess(DataSource dataSource) { diff --git a/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/OperationNonITIntegrationConfig.java b/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/OperationNonITIntegrationConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..a27c7c0ff59f61b7dfe429db80e5571422d92704 --- /dev/null +++ b/services/api-event-donneesentrees/src/main/java/org/mte/numecoeval/donneesentrees/infrastructure/config/OperationNonITIntegrationConfig.java @@ -0,0 +1,138 @@ +package org.mte.numecoeval.donneesentrees.infrastructure.config; + +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.admin.NewTopic; +import org.mte.numecoeval.common.utils.ResultSetUtils; +import org.mte.numecoeval.donneesentrees.infrastructure.utils.Constants; +import org.mte.numecoeval.topic.data.OperationNonITDTO; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.expression.common.LiteralExpression; +import org.springframework.integration.annotation.InboundChannelAdapter; +import org.springframework.integration.annotation.Poller; +import org.springframework.integration.annotation.ServiceActivator; +import org.springframework.integration.annotation.Splitter; +import org.springframework.integration.channel.DirectChannel; +import org.springframework.integration.core.MessageSource; +import org.springframework.integration.expression.FunctionExpression; +import org.springframework.integration.expression.ValueExpression; +import org.springframework.integration.jdbc.JdbcPollingChannelAdapter; +import org.springframework.integration.kafka.outbound.KafkaProducerMessageHandler; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageChannel; +import org.springframework.messaging.MessageHandler; +import org.springframework.messaging.support.GenericMessage; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.function.Function; + +@Slf4j +@Configuration +@ConditionalOnProperty( + value = "numecoeval.features.opnit" +) +public class OperationNonITIntegrationConfig { + + private static final String COLUMN_NAME_NOM_COURT_DATACENTER = "nom_court_datacenter"; + + @Value("${numecoeval.topic.entree.operationNonIT}") + String topicEntreeOperationNonIT; + + @Value("${numecoeval.topic.partition}") + Integer topicPartition; + + /** + * Topic Kafka pour les opérationsNonIT + * + * @return Topic à créer dans Kafka + */ + @Bean + public NewTopic topicEntreeOperationNonIT() { + return new NewTopic(topicEntreeOperationNonIT, topicPartition, (short) 1); + } + + @Bean + public MessageChannel entreeOperationNonIT() { + return new DirectChannel(); + } + + @Bean + public MessageChannel entreeOperationNonITSplitter() { + return new DirectChannel(); + } + + @Bean + @ServiceActivator(inputChannel = "entreeOperationNonIT") + public MessageHandler operationNonITHandler(KafkaTemplate<String, OperationNonITDTO> kafkaTemplate) { + KafkaProducerMessageHandler<String, OperationNonITDTO> handler = + new KafkaProducerMessageHandler<>(kafkaTemplate); + handler.setMessageKeyExpression(new LiteralExpression(UUID.randomUUID().toString())); + handler.setTopicExpression(new ValueExpression<>(topicEntreeOperationNonIT)); + Function<Message<?>, Long> partitionIdRandomFn = (m) -> (long) (Math.random() * topicPartition); + handler.setPartitionIdExpression(new FunctionExpression<>(partitionIdRandomFn)); + return handler; + } + + @Bean + @InboundChannelAdapter( + value = "entreeOperationNonITSplitter", + poller = @Poller(fixedDelay = "1000") + ) + @SuppressWarnings("java:S1452") // La classe JdbcPollingChannelAdapter n'est pas compatible avec une classe fixe + public MessageSource<?> getOperationNonITToProcess(DataSource dataSource) { + JdbcPollingChannelAdapter adapter = new JdbcPollingChannelAdapter(dataSource, + """ + SELECT * + FROM en_operation_non_it + WHERE statut_traitement = 'A_INGERER' + ORDER BY nom_lot ASC, date_lot ASC, nom_organisation ASC + LIMIT 1000 + """ + ); + adapter.setUpdateSql("UPDATE en_operation_non_it SET statut_traitement = 'INGERE', date_update = now() WHERE id in (:id)"); + adapter.setRowMapper((rs, index) -> + OperationNonITDTO.builder() + .id(rs.getLong("id")) + .nomLot(rs.getString("nom_lot")) + .dateLot(ResultSetUtils.getLocalDate(rs, "date_lot")) + .nomOrganisation(rs.getString("nom_organisation")) + .nomItemNonIT(rs.getString("nom_item_non_it")) + .quantite(ResultSetUtils.getDouble(rs, "quantite")) + .type(rs.getString("type")) + .dureeDeVie(ResultSetUtils.getDouble(rs, "duree_de_vie")) + .localisation(rs.getString("localisation")) + .nomEntite(rs.getString("nom_entite")) + .nomSourceDonnee(rs.getString("nom_source_donnee")) + .nomCourtDatacenter(rs.getString(COLUMN_NAME_NOM_COURT_DATACENTER)) + .description(rs.getString("description")) + .consoElecAnnuelle(ResultSetUtils.getDouble(rs, "conso_elec_annuelle")) + .build() + ); + return adapter; + } + + @Splitter( + inputChannel = "entreeOperationNonITSplitter", + outputChannel = "entreeOperationNonIT" + ) + public List<Message<OperationNonITDTO>> splitListOperationNonIT(Message<List<OperationNonITDTO>> messageList) { + if (messageList == null) return List.of(); + + return messageList.getPayload().stream() + .map((OperationNonITDTO operationNonITDTO) -> { + var headers = new HashMap<String, Object>(); + headers.put(Constants.NOM_LOT, operationNonITDTO.getNomLot()); + headers.put(Constants.DATELOT, Objects.toString(operationNonITDTO.getDateLot(), "")); + headers.put(Constants.NOM_ORGANISATION, operationNonITDTO.getNomOrganisation()); + return (Message<OperationNonITDTO>) new GenericMessage<>(operationNonITDTO, headers); + }) + .toList(); + } +} \ No newline at end of file diff --git a/services/api-event-donneesentrees/src/main/resources/application.yaml b/services/api-event-donneesentrees/src/main/resources/application.yaml index ab6e3fc682194d83a75f141313bdea90719e4667..bcf5556dc1a621b047246946b9eebae979248248 100644 --- a/services/api-event-donneesentrees/src/main/resources/application.yaml +++ b/services/api-event-donneesentrees/src/main/resources/application.yaml @@ -29,9 +29,11 @@ numecoeval: partition: "4" entree: equipementPhysique: "entree_equipementPhysique" + operationNonIT: "entree_operationNonIT" messagerie: "entree_messagerie" features: eqp: true + opnit : true mes: true diff --git a/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/IntegrationOperationNonITTest.java b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/IntegrationOperationNonITTest.java new file mode 100644 index 0000000000000000000000000000000000000000..c205852688009ef66a5fbe314102f6326d4ef3d7 --- /dev/null +++ b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/IntegrationOperationNonITTest.java @@ -0,0 +1,72 @@ +package org.mte.numecoeval.donneesentrees; + +import io.zonky.test.db.AutoConfigureEmbeddedDatabase; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mte.numecoeval.donneesentrees.test.jdbc.ScriptUtils; +import org.mte.numecoeval.donneesentrees.test.kafka.KafkaConsumerOperationNonIT; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.kafka.test.context.EmbeddedKafka; +import org.springframework.test.context.ActiveProfiles; + +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import static org.awaitility.Awaitility.await; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles(profiles = {"test"}) +@AutoConfigureEmbeddedDatabase +@EmbeddedKafka( + bootstrapServersProperty = "spring.kafka.bootstrap-servers", + partitions = 1 +) +class IntegrationOperationNonITTest { + + @Autowired + JdbcTemplate jdbcTemplate; + + @Autowired + KafkaConsumerOperationNonIT kafkaConsumer; + + @BeforeEach + void setup() { + ScriptUtils.loadScript(jdbcTemplate.getDataSource(), "sql/schema.sql"); + jdbcTemplate.batchUpdate("DELETE FROM en_operation_non_it"); + } + + @Test + void whenDataAvailable_shouldUpdateStatusAndSendMessage() { + ScriptUtils.loadScript(jdbcTemplate.getDataSource(), "sql/operation_non_it.sql"); + + // Given + var queryResultCountEntrees = jdbcTemplate.query( + "SELECT count(*) as nbr from en_operation_non_it", + (rs, rowNum) -> rs.getInt("nbr") + ); + var nbrEntrees = queryResultCountEntrees.get(0); + + // When + jdbcTemplate.batchUpdate("UPDATE en_operation_non_it SET statut_traitement = 'A_INGERER'"); + + // Then + Assertions.assertEquals(1, nbrEntrees); + await().atMost(10, TimeUnit.SECONDS) + .until(() -> { + var queryResultCountEntreesIngerees = jdbcTemplate.query( + "SELECT count(*) as nbr from en_operation_non_it WHERE statut_traitement = 'INGERE'", + (rs, rowNum) -> rs.getInt("nbr") + ); + + return !queryResultCountEntreesIngerees.isEmpty() && Objects.equals(nbrEntrees, queryResultCountEntreesIngerees.get(0)); + }); + + await().atMost(5, TimeUnit.SECONDS) + .until(() -> nbrEntrees == kafkaConsumer.getPayloads().size()); + + } + +} diff --git a/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumerConfig.java b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumerConfig.java index 546cbec0223a5a5c62ec1b94a51879121a184904..a2a80eb2a1e40c571854836a96ed755520cac911 100644 --- a/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumerConfig.java +++ b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumerConfig.java @@ -2,6 +2,7 @@ package org.mte.numecoeval.donneesentrees.test.kafka; import org.mte.numecoeval.topic.data.EquipementPhysiqueDTO; import org.mte.numecoeval.topic.data.MessagerieDTO; +import org.mte.numecoeval.topic.data.OperationNonITDTO; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.kafka.annotation.EnableKafka; @@ -24,6 +25,18 @@ public class KafkaConsumerConfig { return new KafkaConsumerEquipementPhysique(); } + @Bean + public ConcurrentKafkaListenerContainerFactory<String, OperationNonITDTO> kafkaListenerContainerFactoryOperationNonIT(ConsumerFactory<String, OperationNonITDTO> consumerFactory) { + ConcurrentKafkaListenerContainerFactory<String, OperationNonITDTO> factory = new ConcurrentKafkaListenerContainerFactory<>(); + factory.setConsumerFactory(consumerFactory); + return factory; + } + + @Bean + public KafkaConsumer<OperationNonITDTO> kafkaConsumerOperationNonIT() { + return new KafkaConsumerOperationNonIT(); + } + @Bean public ConcurrentKafkaListenerContainerFactory<String, MessagerieDTO> kafkaListenerContainerFactoryMessagerie(ConsumerFactory<String, MessagerieDTO> consumerFactory) { ConcurrentKafkaListenerContainerFactory<String, MessagerieDTO> factory = new ConcurrentKafkaListenerContainerFactory<>(); diff --git a/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumerOperationNonIT.java b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumerOperationNonIT.java new file mode 100644 index 0000000000000000000000000000000000000000..fec39b94201e25c896b7a62168b7d5e8ad02bcca --- /dev/null +++ b/services/api-event-donneesentrees/src/test/java/org/mte/numecoeval/donneesentrees/test/kafka/KafkaConsumerOperationNonIT.java @@ -0,0 +1,17 @@ +package org.mte.numecoeval.donneesentrees.test.kafka; + +import lombok.extern.slf4j.Slf4j; +import org.mte.numecoeval.topic.data.OperationNonITDTO; +import org.springframework.kafka.annotation.KafkaListener; + +@Slf4j +public class KafkaConsumerOperationNonIT extends KafkaConsumer<OperationNonITDTO> { + + @Override + @KafkaListener(topics = "${numecoeval.topic.entree.operationNonIT}") + public void consumeMessage(OperationNonITDTO message) { + log.info("############# Playload = {}", message); + payloads.add(message); + latch.countDown(); + } +} diff --git a/services/api-event-donneesentrees/src/test/resources/sql/operation_non_it.sql b/services/api-event-donneesentrees/src/test/resources/sql/operation_non_it.sql new file mode 100644 index 0000000000000000000000000000000000000000..4960722a823f3bd71d2bd4a7de321f94322c65a1 --- /dev/null +++ b/services/api-event-donneesentrees/src/test/resources/sql/operation_non_it.sql @@ -0,0 +1,4 @@ +INSERT INTO en_operation_non_it (id, date_creation, nom_lot, date_lot, nom_organisation,nom_item_non_it, quantite, type, +duree_de_vie, localisation, nom_entite,nom_source_donnee,nom_court_datacenter,description,conso_elec_annuelle,statut_traitement,date_update) +VALUES (11002, '2023-03-23 15:53:37.073851', 'nomlot', '2022-01-01', 'nomOrga', 'nomitem', 32, 'type', 31, + 'Localisation', 'Entite', 'Source','nomCourtDatacenter','description',100,'EN_ATTENTE',NULL); diff --git a/services/api-event-donneesentrees/src/test/resources/sql/schema.sql b/services/api-event-donneesentrees/src/test/resources/sql/schema.sql index 32f7442baecbd02dcd6d646bf55c533a63c0c0e3..1460b631ad3380f75989e5887036a184020f18f1 100644 --- a/services/api-event-donneesentrees/src/test/resources/sql/schema.sql +++ b/services/api-event-donneesentrees/src/test/resources/sql/schema.sql @@ -96,6 +96,27 @@ CREATE TABLE IF NOT EXISTS en_application CONSTRAINT en_application_pkey PRIMARY KEY (id) ); +CREATE TABLE IF NOT EXISTS en_operation_non_it +( + id int8 NOT NULL, + date_creation timestamp NULL, + date_update timestamp NULL, + date_lot date NULL, + nom_lot varchar(255) NULL, + nom_organisation varchar(255) NULL, + nom_source_donnee varchar(255) NULL, + nom_item_non_it varchar(255) NULL, + quantite float8 NULL, + type varchar(255) NULL, + duree_de_vie float8 NULL, + localisation varchar(255) NULL, + nom_entite varchar(255) NULL, + nom_court_datacenter varchar(255) NULL, + description varchar(255) NULL, + conso_elec_annuelle float8 NULL, + statut_traitement varchar(255) NULL, + CONSTRAINT en_operation_non_it_pkey PRIMARY KEY (id) +); CREATE TABLE IF NOT EXISTS en_entite ( diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/DonneesEntree.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/DonneesEntree.java index b1fc6b302b4d2be80a4559bd0927dd71e7df6e77..bf79f1b0814cd1de0355fb2252d826f0a91e65e6 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/DonneesEntree.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/DonneesEntree.java @@ -27,4 +27,6 @@ public class DonneesEntree extends AbstractEntree { List<Entite> entites = new ArrayList<>(); + List<OperationNonIT> operationsNonIT = new ArrayList<>(); + } diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/OperationNonIT.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/OperationNonIT.java new file mode 100644 index 0000000000000000000000000000000000000000..60c1ab2d98337d3e03c2014fcf80f7f6e044a138 --- /dev/null +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/OperationNonIT.java @@ -0,0 +1,26 @@ +package org.mte.numecoeval.expositiondonneesentrees.domain.model; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.Accessors; +import lombok.experimental.SuperBuilder; + +@Getter +@Setter +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@SuperBuilder +@Accessors(chain = true) +public class OperationNonIT extends AbstractEntree { + String nomItemNonIT; + Double quantite; + String type; + Double dureeDeVie; + String localisation; + String nomEntite; + String nomCourtDatacenter; + String description; + Double consoElecAnnuelle; +} diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/RapportDemandeCalcul.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/RapportDemandeCalcul.java index 34dcdd17e3e5ff51a5b6822f4627ea18d2b1b324..1ca589b138af5c09f01790caef3cb047f86c15a6 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/RapportDemandeCalcul.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/model/RapportDemandeCalcul.java @@ -21,5 +21,6 @@ public class RapportDemandeCalcul { Integer nbrEquipementPhysique; Integer nbrEquipementVirtuel; Integer nbrApplication; + Integer nbrOperationNonIT; Integer nbrMessagerie; } diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/ImportDonneesEntreePort.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/ImportDonneesEntreePort.java index 60aad67f37ea07507fcf10029e705b2ce1035d92..62757fb834c7187fb77c6326305d2fde41bfbe31 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/ImportDonneesEntreePort.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/ImportDonneesEntreePort.java @@ -1,11 +1,14 @@ package org.mte.numecoeval.expositiondonneesentrees.domain.ports.input; import org.apache.commons.csv.CSVRecord; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; +import org.mte.numecoeval.expositiondonneesentrees.domain.exception.ValidationException; import org.mte.numecoeval.expositiondonneesentrees.domain.model.*; import org.springframework.web.multipart.MultipartFile; import java.time.LocalDate; +import java.util.Arrays; import java.util.List; @SuppressWarnings("java:S107") @@ -14,15 +17,16 @@ public interface ImportDonneesEntreePort { String EQUIPEMENT_PHYSIQUE_CSV_HEADER = "modele;quantite;nomEquipementPhysique;type;statut;paysDUtilisation;utilisateur;dateAchat;dateRetrait;nbCoeur;nomCourtDatacenter;goTelecharge;nbJourUtiliseAn;consoElecAnnuelle"; String CSV_SEPARATOR = ";"; String DATA_CENTER_CSV_HEADER = "nomCourtDatacenter;nomLongDatacenter;pue;localisation"; - String EQUIPEMENT_VIRTUEL_CSV_HEADER = "nomEquipementPhysique;vCPU;cluster"; - String APPLICATION_CSV_HEADER = "nomApplication;typeEnvironnement;nomEquipementPhysique;domaine;sousDomaine"; + String OPERATION_NON_IT_CSV_HEADER = "nomItemNonIT;quantite;type;localisation;dureeDeVie;nomCourtDatacenter;description;consoElecAnnuelle"; + String[] OPERATION_NON_IT_NOT_BLANK_FIELDS = {"nomItemNonIT", "quantite", "type", "localisation"}; String MESSAGERIE_CSV_HEADER = "nombreMailEmis;nombreMailEmisXDestinataires;volumeTotalMailEmis;MoisAnnee"; String ENTITE_CSV_HEADER = "nomEntite;nbCollaborateurs;responsableEntite;responsableNumeriqueDurable"; + String MESSAGE_LIGNE_INVALIDE = "La ligne n°%d est invalide : %s"; ResultatImport importCsv(String nomOrganisation, String nomLot, String dateLot, MultipartFile csvDataCenter, MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel, - MultipartFile csvApplication, MultipartFile csvMessagerie, MultipartFile csvEntite); + MultipartFile csvApplication, MultipartFile csvOperationNonIT, MultipartFile csvMessagerie, MultipartFile csvEntite); Pair<RapportImport, List<DataCenter>> importDataCenter(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvDataCenter); @@ -32,10 +36,13 @@ public interface ImportDonneesEntreePort { Pair<RapportImport, List<Application>> importApplications(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvApplication); + Pair<RapportImport, List<OperationNonIT>> importOperationsNonIT(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvOperationNonIT); + Pair<RapportImport, List<Messagerie>> importMessageries(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvMessagerie); Pair<RapportImport, List<Entite>> importEntite(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvMessagerie); + default boolean isFieldIsMappedAtLeastOnce(CSVRecord csvRecord, String mainName, String... alternativeNames) { if (csvRecord.isMapped(mainName)) { return true; @@ -48,4 +55,30 @@ public interface ImportDonneesEntreePort { } return false; } + + default String checkAllHeadersAreMapped(CSVRecord csvRecord, String[] headers) { + if (Arrays.stream(headers).allMatch(csvRecord::isMapped)) { + return null; + } + return (MESSAGE_LIGNE_INVALIDE.formatted(csvRecord.getRecordNumber() + 1, "Entêtes incohérentes")); + } + + default String checkFieldsAreMappedAndNotBlankInCSVRecord(CSVRecord csvRecord, String[] fields) throws ValidationException { + for (String field : fields) { + if (StringUtils.isBlank(csvRecord.get(field))) { + return (MESSAGE_LIGNE_INVALIDE.formatted(csvRecord.getRecordNumber() + 1, "La colonne " + field + " ne peut être vide")); + } + } + return null; + } + + default String checkCSVRecord(CSVRecord csvRecord, String[] mandatoryHeaders, String[] notBlankFields) { + if (checkAllHeadersAreMapped(csvRecord, mandatoryHeaders) != null) { + return checkAllHeadersAreMapped(csvRecord, mandatoryHeaders); + } else if (checkFieldsAreMappedAndNotBlankInCSVRecord(csvRecord, notBlankFields) != null) { + return checkFieldsAreMappedAndNotBlankInCSVRecord(csvRecord, notBlankFields); + } + return null; + } + } diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/ImportDonneesEntreePortImpl.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/ImportDonneesEntreePortImpl.java index 5a2cf1ad0b7098645e7e4a3442c728fe82ebb6ec..7e0510ef34600c5f673251601acefd1c40522181 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/ImportDonneesEntreePortImpl.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/ImportDonneesEntreePortImpl.java @@ -13,6 +13,7 @@ import org.mte.numecoeval.expositiondonneesentrees.infrastructure.helper.CSVHelp import org.mte.numecoeval.expositiondonneesentrees.infrastructure.service.DefaultValueService; import org.mte.numecoeval.expositiondonneesentrees.infrastructure.service.ErrorManagementService; import org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.model.TypeEquipementDTO; +import org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.model.TypeItemDTO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -30,21 +31,18 @@ public class ImportDonneesEntreePortImpl implements ImportDonneesEntreePort { private static final String LABEL_NOM_EQUIPEMENT_PHYSIQUE = "nomEquipementPhysique"; private static final String LABEL_NOM_VM = "nomVM"; private static final String LABEL_NOM_EQUIPEMENT_VIRTUEL = "nomEquipementVirtuel"; + private static final String LABEL_nom_item_non_it = "nomItemNonIT"; private static final String[] EQUIPEMENT_PHYSIQUE_HEADER = EQUIPEMENT_PHYSIQUE_CSV_HEADER.split(CSV_SEPARATOR); - private static final String[] DATA_CENTER_HEADER = DATA_CENTER_CSV_HEADER.split(CSV_SEPARATOR); - private static final String[] EQUIPEMENT_VIRTUEL_HEADER = EQUIPEMENT_VIRTUEL_CSV_HEADER.split(CSV_SEPARATOR); - private static final String[] APPLICATION_HEADER = APPLICATION_CSV_HEADER.split(CSV_SEPARATOR); private static final String[] MESSAGERIE_HEADER = MESSAGERIE_CSV_HEADER.split(CSV_SEPARATOR); private static final String[] ENTITE_HEADER = ENTITE_CSV_HEADER.split(CSV_SEPARATOR); + private static final String[] OPERATION_NON_IT_HEADER = OPERATION_NON_IT_CSV_HEADER.split(CSV_SEPARATOR); private static final String HEADER_NOM_ENTITE = "nomEntite"; private static final String HEADER_NOM_SOURCE_DONNEE = "nomSourceDonnee"; private static final String LIGNE_INCONSISTENTE = "LIGNE_INCONSISTENTE"; - - private static final Logger LOGGER = LoggerFactory.getLogger(ImportDonneesEntreePortImpl.class); private static final String STATUT_TRAITEMENT_EN_ATTENTE = StatutTraitement.EN_ATTENTE.getValue(); @@ -59,12 +57,14 @@ public class ImportDonneesEntreePortImpl implements ImportDonneesEntreePort { @Value("#{'${constraints.mode-utilisation}'.split(',')}") private List<String> modeUtilisationList; + @Override public ResultatImport importCsv(String nomOrganisation, String nomLot, String dateLot, MultipartFile csvDataCenter, MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel, MultipartFile csvApplication, + MultipartFile csvOperationNonIT, MultipartFile csvMessagerie, MultipartFile csvEntite ) { @@ -99,7 +99,11 @@ public class ImportDonneesEntreePortImpl implements ImportDonneesEntreePort { resultatImport.getRapports().add(importApplications.getKey()); resultatImport.getDonneesEntree().getApplications().addAll(importApplications.getValue()); } - + if (csvOperationNonIT != null) { + Pair<RapportImport, List<OperationNonIT>> importOperationsNonIT = importOperationsNonIT(nomLot, dateLotAsDate, nomOrganisation, csvOperationNonIT); + resultatImport.getRapports().add(importOperationsNonIT.getKey()); + resultatImport.getDonneesEntree().setOperationsNonIT(importOperationsNonIT.getValue()); + } if (csvMessagerie != null) { Pair<RapportImport, List<Messagerie>> importMessagerie = importMessageries(nomLot, dateLotAsDate, nomOrganisation, csvMessagerie); resultatImport.getRapports().add(importMessagerie.getKey()); @@ -111,6 +115,7 @@ public class ImportDonneesEntreePortImpl implements ImportDonneesEntreePort { resultatImport.getRapports().add(importEntites.getKey()); resultatImport.getDonneesEntree().setEntites(importEntites.getValue()); } + return resultatImport; } @@ -205,7 +210,7 @@ public class ImportDonneesEntreePortImpl implements ImportDonneesEntreePort { rapportImport.getErreurs().add(errorMessages.get(LIGNE_INCONSISTENTE).formatted(csvEquipementPhysique.getOriginalFilename(), csvRecord.getRecordNumber() + 1)); } else if (refTypeEquipementOpt.isEmpty()) { // CA 1.1 - rapportImport.getErreurs().add(errorMessages.get("TYPE_EQUIPEMENT_INCONNU").formatted(csvRecord.get("type"), CSVHelper.safeString(csvRecord, LABEL_NOM_EQUIPEMENT_PHYSIQUE, "equipement"))); + rapportImport.getErreurs().add(errorMessages.get("TYPE_ITEM_INCONNU").formatted(csvRecord.get("type"), CSVHelper.safeString(csvRecord, LABEL_NOM_EQUIPEMENT_PHYSIQUE, "equipement"))); } else { var goTelechargeStr = CSVHelper.safeString(csvRecord, "goTelecharge"); Float goTelecharge = goTelechargeStr == null ? null : NumberUtils.toFloat(goTelechargeStr); @@ -400,6 +405,82 @@ public class ImportDonneesEntreePortImpl implements ImportDonneesEntreePort { return Pair.of(rapportImport, domainModels); } + @Override + public Pair<RapportImport, List<OperationNonIT>> importOperationsNonIT(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvOperationNonIT) { + List<OperationNonIT> domainModels = new ArrayList<>(); + RapportImport rapportImport = new RapportImport(); + rapportImport.setFichier(csvOperationNonIT.getOriginalFilename()); + rapportImport.setType("operation_non_it"); + List<TypeItemDTO> typesItem = referentielServicePort.getAllTypesItem(); + Set<String> avertissements = new HashSet<>(); + + try (Reader reader = new InputStreamReader(csvOperationNonIT.getInputStream())) { + Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder() + .setHeader() + .setAllowMissingColumnNames(true) + .setDelimiter(CSV_SEPARATOR) + .setTrim(true) + .setSkipHeaderRecord(true) + .build().parse(reader); + records.forEach(csvRecord -> + { + String typeItem = csvRecord.get("type"); + var refTypeItemOpt = typesItem.stream() + .filter(refType -> refType.getType().equals(typeItem)) + .findFirst(); + String nomItem = CSVHelper.safeString(csvRecord, LABEL_nom_item_non_it); + String error = checkCSVRecord(csvRecord, OPERATION_NON_IT_HEADER, OPERATION_NON_IT_NOT_BLANK_FIELDS); + if (error != null) { + rapportImport.getErreurs().add(error); + } else if (refTypeItemOpt.isEmpty()) { + rapportImport.getErreurs().add(errorMessages.get("TYPE_ITEM_INCONNU").formatted(csvRecord.get("type"), nomItem)); + } else { + OperationNonIT operationToAdd = OperationNonIT.builder() + .statutTraitement(STATUT_TRAITEMENT_EN_ATTENTE) + .nomLot(nomLot) + .dateLot(dateLot) + .nomOrganisation(nomOrganisation) + .nomItemNonIT(nomItem) + .quantite(CSVHelper.safeDouble(csvRecord, "quantite")) + .type(csvRecord.get("type")) + .dureeDeVie(CSVHelper.safeDouble(csvRecord, "dureeDeVie")) + .localisation(CSVHelper.safeString(csvRecord, "localisation")) + .nomEntite(CSVHelper.safeString(csvRecord, HEADER_NOM_ENTITE)) + .nomSourceDonnee(CSVHelper.safeString(csvRecord, HEADER_NOM_SOURCE_DONNEE)) + .nomCourtDatacenter(CSVHelper.safeString(csvRecord, "nomCourtDatacenter", "refDatacenter")) + .description(CSVHelper.safeString(csvRecord, "description")) + .consoElecAnnuelle(CSVHelper.safeDouble(csvRecord, "consoElecAnnuelle")) + .build(); + + var erreurs = errorManagementService.checkOperationNonIT(operationToAdd, refTypeItemOpt.get().getRefItemParDefaut()); + + rapportImport.getErreurs().addAll(erreurs.getKey()); + avertissements.addAll(erreurs.getValue()); + + domainModels.add(operationToAdd); + } + }); + + } catch (FileNotFoundException e) { + LOGGER.error("Erreur CSV pour des opérations non IT introuvables", e); + return Pair.of(RapportImport.builder() + .erreurs(Collections.singletonList("Le fichier CSV des opérations non IT n'est pas trouvable.")) + .build() + , Collections.emptyList() + ); + } catch (Exception e) { + LOGGER.error("Erreur durant la lecture d'un CSV pour des opérations non IT", e); + return Pair.of(RapportImport.builder() + .erreurs(Collections.singletonList("Le fichier CSV des opérations non IT n'est pas lisible par le système.")) + .build() + , Collections.emptyList() + ); + } + rapportImport.setNbrLignesImportees(domainModels.size()); + rapportImport.setAvertissements(avertissements.stream().toList()); + return Pair.of(rapportImport, domainModels); + } + @Override public Pair<RapportImport, List<Messagerie>> importMessageries(String nomLot, LocalDate dateLot, String nomOrganisation, MultipartFile csvMessagerie) { List<Messagerie> domainModels = new ArrayList<>(); @@ -516,3 +597,4 @@ public class ImportDonneesEntreePortImpl implements ImportDonneesEntreePort { return Pair.of(rapportImport, domainModels); } } + diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/SoumissionCalculSyncPortImpl.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/SoumissionCalculSyncPortImpl.java index c0f73260c61dab67adab68286452b6b65abf9af3..0021cf19999bfa4a66a1dfb720dfa8f9c05dac3f 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/SoumissionCalculSyncPortImpl.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/SoumissionCalculSyncPortImpl.java @@ -10,6 +10,7 @@ import org.mte.numecoeval.expositiondonneesentrees.infrastructure.adapters.Calcu import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.DataCenterRepository; import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.EquipementPhysiqueRepository; import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.MessagerieRepository; +import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.OperationNonITRepository; import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.CalculRestMapper; import org.springframework.stereotype.Service; @@ -21,6 +22,7 @@ import java.util.List; public class SoumissionCalculSyncPortImpl implements SoumissionCalculSyncPort { EquipementPhysiqueRepository equipementPhysiqueRepository; + OperationNonITRepository operationNonITRepository; MessagerieRepository messagerieRepository; DataCenterRepository dataCenterRepository; @@ -34,11 +36,13 @@ public class SoumissionCalculSyncPortImpl implements SoumissionCalculSyncPort { // find equipements physiques à partir de nomLot et nomOrganisation List<Long> equipementPhysiqueIds = equipementPhysiqueRepository.getIdsByNomLotAndStatutTraitement(demandeCalcul.getNomLot(), StatutTraitement.EN_ATTENTE.getValue()); + List<Long> operatioNonITIds = operationNonITRepository.getIdsByNomLotAndStatutTraitement(demandeCalcul.getNomLot(), StatutTraitement.EN_ATTENTE.getValue()); List<Long> messagerieEntityIds = messagerieRepository.getIdsByNomLotAndStatutTraitement(demandeCalcul.getNomLot(), StatutTraitement.EN_ATTENTE.getValue()); // map to Rest var reponseCalculRest = calculsRestClient.postSyncCalcul( equipementPhysiqueIds, + operatioNonITIds, messagerieEntityIds ); diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/StatutPourCalculPortImpl.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/StatutPourCalculPortImpl.java index 39da64041253166f03d96ff6a093bcfd01f3632d..25106f330713eaeeae3be23629b997477dada3f0 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/StatutPourCalculPortImpl.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/input/impl/StatutPourCalculPortImpl.java @@ -28,8 +28,9 @@ public class StatutPourCalculPortImpl implements StatutPourCalculPort { public StatutCalculRest statutDesCalculs(String nomLot, String nomOrganisation) { var volumeEqPh = volumeJdbc.getVolumeBy(nomLot, nomOrganisation, Constants.TABLE_EQUIPEMENT_PHYSIQUE); + var volumeOpNonIT = volumeJdbc.getVolumeBy(nomLot, nomOrganisation, Constants.TABLE_OPERATION_NON_IT); var volumeMessagerie = volumeJdbc.getVolumeBy(nomLot, nomOrganisation, Constants.TABLE_MESSAGERIE); - return statutCalculs(volumeEqPh, volumeMessagerie); + return statutCalculs(volumeEqPh, volumeOpNonIT, volumeMessagerie); } /** @@ -39,9 +40,9 @@ public class StatutPourCalculPortImpl implements StatutPourCalculPort { * @param volumeMessagerie volume de la messagerie * @return le StatutCalculRest */ - public StatutCalculRest statutCalculs(Volume volumeEqPh, Volume volumeMessagerie) { - var totalTraite = volumeEqPh.nbTraite() + volumeMessagerie.nbTraite(); - var totalEnCours = volumeEqPh.nbEnCours() + volumeMessagerie.nbEnCours(); + public StatutCalculRest statutCalculs(Volume volumeEqPh, Volume volumeOpNonIT, Volume volumeMessagerie) { + var totalTraite = volumeEqPh.nbTraite() + volumeOpNonIT.nbTraite() + volumeMessagerie.nbTraite(); + var totalEnCours = volumeEqPh.nbEnCours() + volumeOpNonIT.nbEnCours() + volumeMessagerie.nbEnCours(); if (totalTraite + totalEnCours == 0) { throw new NotFoundException(); @@ -55,6 +56,7 @@ public class StatutPourCalculPortImpl implements StatutPourCalculPort { .statut(statut) .etat(etat + "%") .equipementPhysique(volumeMapper.toRest(volumeEqPh)) + .operationNonIT(volumeMapper.toRest(volumeOpNonIT)) .messagerie(volumeMapper.toRest(volumeMessagerie)) .build(); } diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/output/ReferentielServicePort.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/output/ReferentielServicePort.java index 7fc8e1aa6862219b38c93a4915600b5b247f1f54..44eb82e2a01d5c8e8a6a502effe99c5c8c80759b 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/output/ReferentielServicePort.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/domain/ports/output/ReferentielServicePort.java @@ -9,12 +9,15 @@ public interface ReferentielServicePort { List<TypeEquipementDTO> getAllTypesEquipement(); + List<TypeItemDTO> getAllTypesItem(); + CorrespondanceRefEquipementDTO getCorrespondance(String modele); ImpactEquipementDTO getImpactEquipement(String refEquipement, String critere, String etape); + FacteurCaracterisationDTO getFacteurCaracterisation(String critere, String etape, String refItem); + List<EtapeDTO> getAllEtapes(); List<CritereDTO> getAllCriteres(); - } diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/adapters/CalculsRestClient.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/adapters/CalculsRestClient.java index c1da6ce1ab509d8143dc84f5bd172c9bd805ffed..096e4d951157bbe02ec5791c9e0b18b2aa92962e 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/adapters/CalculsRestClient.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/adapters/CalculsRestClient.java @@ -3,7 +3,7 @@ package org.mte.numecoeval.expositiondonneesentrees.infrastructure.adapters; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.mte.numecoeval.expositiondonneesentrees.domain.exception.RestException; -import org.mte.numecoeval.expositiondonneesentrees.sync.calculs.generated.api.client.CalculsEquipementPhysiqueEtMessagerieApi; +import org.mte.numecoeval.expositiondonneesentrees.sync.calculs.generated.api.client.CalculsEquipementPhysiqueEtOperationNonItEtMessagerieApi; import org.mte.numecoeval.expositiondonneesentrees.sync.calculs.generated.api.model.ReponseCalculRest; import org.mte.numecoeval.expositiondonneesentrees.sync.calculs.generated.api.model.SyncCalculRest; import org.springframework.stereotype.Service; @@ -16,16 +16,17 @@ import java.util.List; @AllArgsConstructor public class CalculsRestClient { - private CalculsEquipementPhysiqueEtMessagerieApi calculsEquipementPhysiqueEtMessagerieApi; + private CalculsEquipementPhysiqueEtOperationNonItEtMessagerieApi calculsEquipementPhysiqueEtOperationNonItEtMessagerieApi; - public ReponseCalculRest postSyncCalcul(List<Long> equipementPhysiqueIds, List<Long> messagerieIds) { + public ReponseCalculRest postSyncCalcul(List<Long> equipementPhysiqueIds, List<Long> operationNonITIds, List<Long> messagerieIds) { try { var syncCalculRest = new SyncCalculRest(); syncCalculRest.setEquipementPhysiqueIds(equipementPhysiqueIds); + syncCalculRest.setOperationNonITIds(operationNonITIds); syncCalculRest.setMessagerieIds(messagerieIds); - return calculsEquipementPhysiqueEtMessagerieApi.syncCalculByIds(syncCalculRest).block(); + return calculsEquipementPhysiqueEtOperationNonItEtMessagerieApi.syncCalculByIds(syncCalculRest).block(); } catch (WebClientResponseException e) { throw new RestException(e); diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/adapters/ReferentielRestClient.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/adapters/ReferentielRestClient.java index b101173d9df087ab528b0bed0f0ee5be549a3d12..277f1e5da336ffafe3c7e5e7cd991f9f61d51e90 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/adapters/ReferentielRestClient.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/adapters/ReferentielRestClient.java @@ -41,6 +41,12 @@ public class ReferentielRestClient implements ReferentielServicePort { return result.getBody(); } + @Override + public List<TypeItemDTO> getAllTypesItem() { + var result = interneNumEcoEvalApi.getAllTypeItemWithHttpInfo().block(); + return result.getBody(); + } + @Cacheable("CorrespondanceRefEquipement") @Override public CorrespondanceRefEquipementDTO getCorrespondance(String modele) { @@ -72,6 +78,24 @@ public class ReferentielRestClient implements ReferentielServicePort { return null; } + @Cacheable("FacteurCaracterisation") + @Override + public FacteurCaracterisationDTO getFacteurCaracterisation(String critere, String etape, String refEquipement) { + + try { + var res = interneNumEcoEvalApi.getFacteurCaracterisation(critere, etape, refEquipement, null, null).blockFirst(); + if (res != null) { + return res; + } + } catch (WebClientResponseException e) { + if (e.getStatusCode() != HttpStatus.NOT_FOUND) { + log.error("Une erreur est survenue lors de l'appel au référentiel facteurcaracterisation", e); + return null; + } + } + return null; + } + @Cacheable("Etapes") @Override public List<EtapeDTO> getAllEtapes() { diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/cache/SchedulerEvictCache.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/cache/SchedulerEvictCache.java index c3c4ffc90bd6c9cc9c5e73b7d029a49df1c84b14..fbcc643b7ea93035124e6e80d5a0a71e21dc1b3a 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/cache/SchedulerEvictCache.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/cache/SchedulerEvictCache.java @@ -17,7 +17,8 @@ public class SchedulerEvictCache { "Etapes", "Criteres", "CorrespondanceRefEquipement", - "ImpactEquipement" + "ImpactEquipement", + "FacteurCaracterisation" }, allEntries = true) @Scheduled(fixedRateString = "${caching.spring.referentiels}") public void emptyCacheReferentiel() { diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/CommonIntegrationConfig.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/CommonIntegrationConfig.java index 608aefe087afa6b01d150aed4877dbfee666df83..0896ea4ebb222621f473329525a2a459195d25d0 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/CommonIntegrationConfig.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/config/CommonIntegrationConfig.java @@ -2,7 +2,7 @@ package org.mte.numecoeval.expositiondonneesentrees.infrastructure.config; import lombok.extern.slf4j.Slf4j; import org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.client.InterneNumEcoEvalApi; -import org.mte.numecoeval.expositiondonneesentrees.sync.calculs.generated.api.client.CalculsEquipementPhysiqueEtMessagerieApi; +import org.mte.numecoeval.expositiondonneesentrees.sync.calculs.generated.api.client.CalculsEquipementPhysiqueEtOperationNonItEtMessagerieApi; import org.mte.numecoeval.expositiondonneesentrees.sync.calculs.generated.api.invoker.ApiClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; @@ -20,8 +20,8 @@ public class CommonIntegrationConfig { String referentielUrl; @Bean - public CalculsEquipementPhysiqueEtMessagerieApi clientAPISyncCalculs() { - CalculsEquipementPhysiqueEtMessagerieApi calculsApi = new CalculsEquipementPhysiqueEtMessagerieApi(); + public CalculsEquipementPhysiqueEtOperationNonItEtMessagerieApi clientAPISyncCalculs() { + CalculsEquipementPhysiqueEtOperationNonItEtMessagerieApi calculsApi = new CalculsEquipementPhysiqueEtOperationNonItEtMessagerieApi(); var apiClient = new ApiClient(WebClient.builder() .baseUrl(calculUrl) .build()); diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/ImportCSVController.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/ImportCSVController.java index 80a48f93904645008f71660eeeea325f3403da9a..65e5a6372008f64dcbbb42d766a965e8d7f9bdd9 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/ImportCSVController.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/ImportCSVController.java @@ -41,11 +41,11 @@ public class ImportCSVController implements ImportsApi { ErrorManagementPostSaveService errorManagementPostSaveService; @Override - public ResponseEntity<List<RapportImportRest>> importCSV(String nomOrganisation, String nomLot, String dateLot, MultipartFile csvDataCenter, MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel, MultipartFile csvApplication, MultipartFile csvMessagerie, MultipartFile csvEntite) { - return importInterneCSV(nomOrganisation, nomLot, dateLot, csvDataCenter, csvEquipementPhysique, csvEquipementVirtuel, csvApplication, csvMessagerie, csvEntite); + public ResponseEntity<List<RapportImportRest>> importCSV(String nomOrganisation, String nomLot, String dateLot, MultipartFile csvDataCenter, MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel, MultipartFile csvApplication, MultipartFile csvOperationNonIT, MultipartFile csvMessagerie, MultipartFile csvEntite) { + return importInterneCSV(nomOrganisation, nomLot, dateLot, csvDataCenter, csvEquipementPhysique, csvEquipementVirtuel, csvApplication, csvOperationNonIT, csvMessagerie, csvEntite); } - public ResponseEntity<List<RapportImportRest>> importInterneCSV(String nomOrganisation, String nomLot, String dateLot, MultipartFile csvDataCenter, MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel, MultipartFile csvApplication, MultipartFile csvMessagerie, MultipartFile csvEntite) { + public ResponseEntity<List<RapportImportRest>> importInterneCSV(String nomOrganisation, String nomLot, String dateLot, MultipartFile csvDataCenter, MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel, MultipartFile csvApplication, MultipartFile csvOperationNonIT, MultipartFile csvMessagerie, MultipartFile csvEntite) { return ResponseEntity.ok( importDonneesFromCSV( nomOrganisation, nomLot, dateLot, @@ -53,6 +53,7 @@ public class ImportCSVController implements ImportsApi { csvEquipementPhysique, csvEquipementVirtuel, csvApplication, + csvOperationNonIT, csvMessagerie, csvEntite ) @@ -73,13 +74,14 @@ public class ImportCSVController implements ImportsApi { MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel, MultipartFile csvApplication, + MultipartFile csvOperationNonIT, MultipartFile csvMessagerie, MultipartFile csvEntite) throws ValidationException { LOGGER.info("Reception de fichiers pour imports de données d'entrées :Nom Organisation : {}, Nom de Lot : {}, Date de lot : {}", nomOrganisation, nomLot, dateLot); - validateRequestParametersForImportCSV(nomOrganisation, nomLot, dateLot, csvDataCenter, csvEquipementPhysique, csvEquipementVirtuel, csvApplication, csvMessagerie, csvEntite); + validateRequestParametersForImportCSV(nomOrganisation, nomLot, dateLot, csvDataCenter, csvEquipementPhysique, csvEquipementVirtuel, csvApplication, csvOperationNonIT, csvMessagerie, csvEntite); - return importAllCsv(nomOrganisation, nomLot, dateLot, csvDataCenter, csvEquipementPhysique, csvEquipementVirtuel, csvApplication, csvMessagerie, csvEntite); + return importAllCsv(nomOrganisation, nomLot, dateLot, csvDataCenter, csvEquipementPhysique, csvEquipementVirtuel, csvApplication, csvOperationNonIT, csvMessagerie, csvEntite); } /** @@ -91,15 +93,17 @@ public class ImportCSVController implements ImportsApi { * @param csvEquipementPhysique Fichier CSV des équipements physiques * @param csvEquipementVirtuel Fichier CSV des équipements virtuels * @param csvApplication Fichier CSV des applications + * @param csvOperationNonIT Fichier CSV des opérations non IT * @param csvMessagerie Fichier CSV de la messagerie * @param csvEntite Fichier CSV des entités * @throws ResponseStatusException avec le statut 400 lorsque les entrées ne sont pas cohérentes. */ - private void validateRequestParametersForImportCSV(String nomOrganisation, String nomLot, String dateLot, MultipartFile csvDataCenter, MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel, MultipartFile csvApplication, MultipartFile csvMessagerie, MultipartFile csvEntite) { + private void validateRequestParametersForImportCSV(String nomOrganisation, String nomLot, String dateLot, MultipartFile csvDataCenter, MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel, MultipartFile csvApplication, MultipartFile csvOperationNonIT, MultipartFile csvMessagerie, MultipartFile csvEntite) { if (CSVHelper.fileIsNullOrEmpty(csvDataCenter) && CSVHelper.fileIsNullOrEmpty(csvEquipementPhysique) && CSVHelper.fileIsNullOrEmpty(csvEquipementVirtuel) && CSVHelper.fileIsNullOrEmpty(csvApplication) + && CSVHelper.fileIsNullOrEmpty(csvOperationNonIT) && CSVHelper.fileIsNullOrEmpty(csvMessagerie) && CSVHelper.fileIsNullOrEmpty(csvEntite) ) { @@ -134,6 +138,7 @@ public class ImportCSVController implements ImportsApi { * @param csvEquipementPhysique Fichier CSV des équipements physiques * @param csvEquipementVirtuel Fichier CSV des équipements virtuels * @param csvApplication Fichier CSV des applications + * @param csvOperationNonIT Fichier CSV des opérations non IT * @param csvMessagerie Fichier CSV de la messagerie * @param csvEntite Fichier CSV des entités * @param dateLot Date du lot associée aux fichiers @@ -142,9 +147,9 @@ public class ImportCSVController implements ImportsApi { * @return {@link List} des {@link RapportImportRest} correspondant à l'import * @throws ValidationException en cas d'absence de donner à pousser dans le système. */ - private List<RapportImportRest> importAllCsv(String nomOrganisation, String nomLot, String dateLot, MultipartFile csvDataCenter, MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel, MultipartFile csvApplication, MultipartFile csvMessagerie, MultipartFile csvEntite) throws ValidationException { + private List<RapportImportRest> importAllCsv(String nomOrganisation, String nomLot, String dateLot, MultipartFile csvDataCenter, MultipartFile csvEquipementPhysique, MultipartFile csvEquipementVirtuel, MultipartFile csvApplication, MultipartFile csvOperationNonIT, MultipartFile csvMessagerie, MultipartFile csvEntite) throws ValidationException { // Lecture & conversion - var resultatImport = importDonneesEntreePort.importCsv(nomOrganisation, nomLot, dateLot, csvDataCenter, csvEquipementPhysique, csvEquipementVirtuel, csvApplication, csvMessagerie, csvEntite); + var resultatImport = importDonneesEntreePort.importCsv(nomOrganisation, nomLot, dateLot, csvDataCenter, csvEquipementPhysique, csvEquipementVirtuel, csvApplication, csvOperationNonIT, csvMessagerie, csvEntite); saveDonneesEntreePort.save(resultatImport.getDonneesEntree()); @@ -152,6 +157,7 @@ public class ImportCSVController implements ImportsApi { updateResultatImport(resultatImport, "equipement_physique", errorManagementPostSaveService.checkEquipementPhysiques(nomLot)); updateResultatImport(resultatImport, "equipement_virtuel", errorManagementPostSaveService.checkEquipementVirtuels(nomLot)); updateResultatImport(resultatImport, "application", errorManagementPostSaveService.checkApplications(nomLot)); + updateResultatImport(resultatImport, "operation_non_it", errorManagementPostSaveService.checkOperationsNonIT(nomLot)); return resultatImport.getRapports().stream() .map(donneesEntreeMapper::toRestDTO) diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/helper/Constants.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/helper/Constants.java index 9c448a70cffe1c8ae0f8feab903321da54a96f50..c44cef377f6eb20e82d3a1e5144ee3a0a88ee629 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/helper/Constants.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/helper/Constants.java @@ -7,5 +7,6 @@ public class Constants { public static final String TABLE_EQUIPEMENT_PHYSIQUE = "en_equipement_physique"; public static final String TABLE_EQUIPEMENT_VIRTUEL = "en_equipement_virtuel"; public static final String TABLE_APPLICATION = "en_application"; + public static final String TABLE_OPERATION_NON_IT = "en_operation_non_it"; public static final String TABLE_MESSAGERIE = "en_messagerie"; } diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jdbc/SoumissionCalculPortJdbcImpl.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jdbc/SoumissionCalculPortJdbcImpl.java index 4e6095f9aad73f3e02cbd678d8e2b77fee9fc7d2..2427ca6e309c1c0447113a98b00d460f00e42e16 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jdbc/SoumissionCalculPortJdbcImpl.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jdbc/SoumissionCalculPortJdbcImpl.java @@ -35,6 +35,7 @@ public class SoumissionCalculPortJdbcImpl implements SoumissionCalculPort { jdbcTemplate.update(getUpdateStatementForTable(TABLE_DONNEES_ENTREES), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot(), STATUT_TRAITEMENT_EN_ATTENTE); rapport.setNbrDataCenter(jdbcTemplate.update(getUpdateStatementForTable(TABLE_DATA_CENTER), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot(), STATUT_TRAITEMENT_EN_ATTENTE)); rapport.setNbrEquipementPhysique(jdbcTemplate.update(getUpdateStatementForTable(TABLE_EQUIPEMENT_PHYSIQUE), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot(), STATUT_TRAITEMENT_EN_ATTENTE)); + rapport.setNbrOperationNonIT(jdbcTemplate.update(getUpdateStatementForTable(TABLE_OPERATION_NON_IT), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot(), STATUT_TRAITEMENT_EN_ATTENTE)); rapport.setNbrMessagerie(jdbcTemplate.update(getUpdateStatementForTable(TABLE_MESSAGERIE), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot(), STATUT_TRAITEMENT_EN_ATTENTE)); return rapport; } @@ -51,6 +52,7 @@ public class SoumissionCalculPortJdbcImpl implements SoumissionCalculPort { jdbcTemplate.update(getUpdateForRejeuStatementForTable(TABLE_DONNEES_ENTREES), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot()); rapport.setNbrDataCenter(jdbcTemplate.update(getUpdateForRejeuStatementForTable(TABLE_DATA_CENTER), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot())); rapport.setNbrEquipementPhysique(jdbcTemplate.update(getUpdateForRejeuStatementForTable(TABLE_EQUIPEMENT_PHYSIQUE), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot())); + rapport.setNbrOperationNonIT(jdbcTemplate.update(getUpdateForRejeuStatementForTable(TABLE_OPERATION_NON_IT), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot())); rapport.setNbrMessagerie(jdbcTemplate.update(getUpdateForRejeuStatementForTable(TABLE_MESSAGERIE), STATUT_TRAITEMENT_A_INGERER, demandeCalcul.getNomLot())); return rapport; } diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/OperationNonITJpaAdapter.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/OperationNonITJpaAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..5249d07e7e45e14ae1c4bd02a9f11dc1df9d2ca3 --- /dev/null +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/OperationNonITJpaAdapter.java @@ -0,0 +1,31 @@ +package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter; + +import lombok.AllArgsConstructor; +import org.mte.numecoeval.expositiondonneesentrees.domain.model.OperationNonIT; +import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.EntreePersistencePort; +import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.OperationNonITRepository; +import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapper; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@AllArgsConstructor +public class OperationNonITJpaAdapter implements EntreePersistencePort<OperationNonIT> { + + OperationNonITRepository repository; + + EntreeEntityMapper entreeEntityMapper; + + @Override + public void save(OperationNonIT entree) { + repository.save(entreeEntityMapper.toEntity(entree)); + } + + @Override + public void saveAll(List<OperationNonIT> entrees) { + repository.saveAll(entreeEntityMapper.toEntityListOperationNonIT(entrees)); + } + + +} diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/SaveDonneesEntreeAdapter.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/SaveDonneesEntreeAdapter.java index 446463b9cb0f21ee842a65315f622338b97d2b9a..ae7f341761df6c036aaecce5e2d1160e4a7c614b 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/SaveDonneesEntreeAdapter.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/SaveDonneesEntreeAdapter.java @@ -26,6 +26,7 @@ public class SaveDonneesEntreeAdapter implements SaveDonneesEntreePort { private EntreePersistencePort<EquipementPhysique> equipementPhysiqueEntreePersistencePort; private EntreePersistencePort<EquipementVirtuel> equipementVirtuelEntreePersistencePort; private EntreePersistencePort<Application> applicationEntreePersistencePort; + private EntreePersistencePort<OperationNonIT> operationNonITEntreePersistencePort; private EntreePersistencePort<Messagerie> messagerieEntreePersistencePort; private EntreePersistencePort<Entite> entiteEntreePersistencePort; @@ -42,7 +43,6 @@ public class SaveDonneesEntreeAdapter implements SaveDonneesEntreePort { donneesEntree.getNomLot(), donneesEntree.getDateLot(), donneesEntree.getNomOrganisation() ); - Set<String> equipementsPhysiquesImpactes = new HashSet<>(); Set<String> csvEquipementPhysiques = new HashSet<>(); @@ -103,7 +103,15 @@ public class SaveDonneesEntreeAdapter implements SaveDonneesEntreePort { .map(Application::getNomEquipementPhysique) .collect(Collectors.toSet())); } - + if (!CollectionUtils.isEmpty(donneesEntree.getOperationsNonIT())) { + stopWatch = StopWatch.createStarted(); + operationNonITEntreePersistencePort.saveAll(donneesEntree.getOperationsNonIT()); + stopWatch.stop(); + log.info("Fin du traitement des {} objets Opérations non IT reçues en {} secondes", + donneesEntree.getOperationsNonIT().size(), + stopWatch.getTime(TimeUnit.SECONDS) + ); + } if (!CollectionUtils.isEmpty(donneesEntree.getMessageries())) { stopWatch = StopWatch.createStarted(); messagerieEntreePersistencePort.saveAll(donneesEntree.getMessageries()); diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/OperationNonITEntity.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/OperationNonITEntity.java new file mode 100644 index 0000000000000000000000000000000000000000..07915c7b101c7f8940cc63ae556ba7d01d5383b9 --- /dev/null +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/entity/OperationNonITEntity.java @@ -0,0 +1,36 @@ +package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.experimental.SuperBuilder; + +@Getter +@Setter +@SuperBuilder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "EN_OPERATION_NON_IT") +@Entity +public class OperationNonITEntity extends AbstractEntreeEntity { + + @Id + @GeneratedValue(generator = "SEQ_EN_OPERATION_NON_IT", strategy = GenerationType.SEQUENCE) + @SequenceGenerator(name = "SEQ_EN_OPERATION_NON_IT", sequenceName = "SEQ_EN_OPERATION_NON_IT", allocationSize = 1000) + @Column(nullable = false) + private Long id; + @Column(name = "nom_item_non_it") + private String nomItemNonIT; + private Double quantite; + private String type; + private Double dureeDeVie; + private String localisation; + private String nomEntite; + private String nomSourceDonnee; + private String nomCourtDatacenter; + private String description; + private Double consoElecAnnuelle; + +} diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/OperationNonITRepository.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/OperationNonITRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..8d7dd22d3aacf4115aa686d5c24d7e7832469f38 --- /dev/null +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/repository/OperationNonITRepository.java @@ -0,0 +1,27 @@ +package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository; + +import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.OperationNonITEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface OperationNonITRepository extends JpaRepository<OperationNonITEntity, Long> { + @Query(value = """ + WITH datacenters AS ( + SELECT nom_court_datacenter FROM en_data_center WHERE nom_lot = ?1 + ) + SELECT nom_item_non_it FROM en_operation_non_it eoni + WHERE nom_lot = ?1 + AND nom_court_datacenter is NOT NULL + AND nom_court_datacenter NOT IN (SELECT nom_court_datacenter FROM datacenters) + ORDER BY nom_item_non_it + """, nativeQuery = true) + List<String> getOperationNonITAvecMauvaisNomCourtDatacenter(String nomLot); + + @Query("select id from #{#entityName} where nomLot = ?1 and statutTraitement = ?2") + List<Long> getIdsByNomLotAndStatutTraitement(String nomLot, String statutTraitement); + +} diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/mapper/EntreeEntityMapper.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/mapper/EntreeEntityMapper.java index 4e2ee607e9fa0f40b02071060eb5d63337c880c9..749e0d698b0d4c19b532d562073fb4f8d376ce19 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/mapper/EntreeEntityMapper.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/mapper/EntreeEntityMapper.java @@ -2,20 +2,8 @@ package org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper; import org.mapstruct.Mapper; import org.mapstruct.Mapping; -import org.mte.numecoeval.expositiondonneesentrees.domain.model.Application; -import org.mte.numecoeval.expositiondonneesentrees.domain.model.DataCenter; -import org.mte.numecoeval.expositiondonneesentrees.domain.model.DonneesEntree; -import org.mte.numecoeval.expositiondonneesentrees.domain.model.Entite; -import org.mte.numecoeval.expositiondonneesentrees.domain.model.EquipementPhysique; -import org.mte.numecoeval.expositiondonneesentrees.domain.model.EquipementVirtuel; -import org.mte.numecoeval.expositiondonneesentrees.domain.model.Messagerie; -import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.ApplicationEntity; -import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.DataCenterEntity; -import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.DonneesEntreesEntity; -import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.EntiteEntity; -import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.EquipementPhysiqueEntity; -import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.EquipementVirtuelEntity; -import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.MessagerieEntity; +import org.mte.numecoeval.expositiondonneesentrees.domain.model.*; +import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.*; import java.util.List; @@ -23,31 +11,63 @@ import java.util.List; public interface EntreeEntityMapper { DonneesEntreesEntity toEntity(DonneesEntree domain); + DataCenterEntity toEntity(DataCenter domain); + EquipementPhysiqueEntity toEntity(EquipementPhysique domain); + @Mapping(target = "vCPU", source = "VCPU") EquipementVirtuelEntity toEntity(EquipementVirtuel domain); + ApplicationEntity toEntity(Application domain); + MessagerieEntity toEntity(Messagerie domain); + EntiteEntity toEntity(Entite domain); + + OperationNonITEntity toEntity(OperationNonIT domain); + List<DataCenterEntity> toEntityListDataCenter(List<DataCenter> domains); + List<EquipementPhysiqueEntity> toEntityListEquipementPhysique(List<EquipementPhysique> domains); + List<EquipementVirtuelEntity> toEntityListEquipementVirtuel(List<EquipementVirtuel> domains); + List<ApplicationEntity> toEntityListApplication(List<Application> domains); + List<MessagerieEntity> toEntityListMessagerie(List<Messagerie> domains); + List<EntiteEntity> toEntityListEntite(List<Entite> domains); + List<OperationNonITEntity> toEntityListOperationNonIT(List<OperationNonIT> domains); + DonneesEntree toDomain(DonneesEntreesEntity entity); + DataCenter toDomain(DataCenterEntity entity); + EquipementPhysique toDomain(EquipementPhysiqueEntity entity); + EquipementVirtuel toDomain(EquipementVirtuelEntity entity); + Application toDomain(ApplicationEntity entity); + Messagerie toDomain(MessagerieEntity entity); + Entite toDomain(Entite entity); + + OperationNonIT toDomain(OperationNonITEntity entity); + List<DataCenter> toDomainListDataCenter(List<DataCenterEntity> entities); + List<EquipementPhysique> toDomainListEquipementPhysique(List<EquipementPhysiqueEntity> entities); + List<EquipementVirtuel> toDomainListEquipementVirtuel(List<EquipementVirtuelEntity> entities); + List<Application> toDomainListApplication(List<ApplicationEntity> entities); + List<Messagerie> toDomainListMessagerie(List<MessagerieEntity> entities); + List<Entite> toDomainListEntite(List<EntiteEntity> entities); + + List<OperationNonIT> toDomainListOperationNonIT(List<OperationNonITEntity> entities); } diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementPostSaveService.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementPostSaveService.java index e10fe962bdff06ffae7153267dd9202b9faa20c7..692f72c7812fc5b64c925e888269af7c61bd7333 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementPostSaveService.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementPostSaveService.java @@ -5,6 +5,7 @@ import org.mte.numecoeval.expositiondonneesentrees.infrastructure.config.Message import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.ApplicationRepository; import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.EquipementPhysiqueRepository; import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.EquipementVirtuelRepository; +import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.OperationNonITRepository; import org.springframework.stereotype.Service; import java.util.ArrayList; @@ -15,10 +16,11 @@ import java.util.List; public class ErrorManagementPostSaveService { final MessageProperties messageProperties; - final EquipementPhysiqueRepository equipementPhysiqueRepository; final EquipementVirtuelRepository equipementVirtuelRepository; final ApplicationRepository applicationRepository; + final OperationNonITRepository operationNonITRepository; + public List<String> checkEquipementPhysiques(String nomLot) { // CA 3.2 @@ -46,9 +48,13 @@ public class ErrorManagementPostSaveService { result.addAll(applicationRepository.getApplicationSansEquipementPhysique(nomLot).stream() .map(equipementVirtuel -> messageProperties.getMessages().get("APPLICATION_AVEC_EQUIPEMENT_VIRTUEL_INCONNU").formatted(equipementVirtuel)) .toList()); - + return result; } - + public List<String> checkOperationsNonIT(String nomLot) { + return operationNonITRepository.getOperationNonITAvecMauvaisNomCourtDatacenter(nomLot).stream() + .map(itemNonIT -> messageProperties.getMessages().get("ITEM_NOM_DATACENTER_INCONNU").formatted(itemNonIT)) + .toList(); + } } diff --git a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementService.java b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementService.java index 473a1a4e1fed90602ece904dcfee3464a3919c43..89a8ee0ae9ab602a396aafb56bcc1b45a75e8610 100644 --- a/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementService.java +++ b/services/api-expositiondonneesentrees/src/main/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementService.java @@ -5,6 +5,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.mte.numecoeval.expositiondonneesentrees.domain.model.DataCenter; import org.mte.numecoeval.expositiondonneesentrees.domain.model.EquipementPhysique; +import org.mte.numecoeval.expositiondonneesentrees.domain.model.OperationNonIT; import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.ReferentielServicePort; import org.mte.numecoeval.expositiondonneesentrees.infrastructure.config.MessageProperties; import org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.model.CorrespondanceRefEquipementDTO; @@ -58,7 +59,7 @@ public class ErrorManagementService { if (StringUtils.isNotBlank(equipementPhysique.getPaysDUtilisation()) && !referentielServicePort.hasMixElec(equipementPhysique.getPaysDUtilisation())) { - erreurs.add(messageProperties.getMessages().get("EQUIPEMENT_MIX_ELEC_LOCALISATION_INCONNUE").formatted(equipementPhysique.getPaysDUtilisation(), equipementPhysique.getNomEquipementPhysique())); + erreurs.add(messageProperties.getMessages().get("ITEM_MIX_ELEC_LOCALISATION_INCONNUE").formatted(equipementPhysique.getPaysDUtilisation(), equipementPhysique.getNomEquipementPhysique())); } String refEquipement = refEquipementParDefaut; @@ -84,7 +85,7 @@ public class ErrorManagementService { for (var etape : etapes) { var impact = referentielServicePort.getImpactEquipement(refEquipement, critere.getNomCritere(), etape.getCode()); if (impact == null) { - avertissements.add(messageProperties.getMessages().get("EQUIPEMENT_IMPACT_INCONNU").formatted(refEquipement, etape.getCode(), critere.getNomCritere())); + avertissements.add(messageProperties.getMessages().get("ITEM_IMPACT_INCONNU").formatted(refEquipement, etape.getCode(), critere.getNomCritere())); } } } @@ -111,4 +112,33 @@ public class ErrorManagementService { return Pair.of(erreurs, avertissements); } + /** + * Vérifie une operation non IT + * + * @param operationNonIT l'equipement physique + * @param type la reference d'equipement par default + * @return la paire (erreurs, avertissements) + */ + public Pair<List<String>, List<String>> checkOperationNonIT(OperationNonIT operationNonIT, String type) { + var erreurs = new ArrayList<String>(); + var avertissements = new ArrayList<String>(); + // L'ajout d'une operation non it dont le type n'est pas renseigné sort une erreur + if (StringUtils.isBlank(type)) { + erreurs.add(messageProperties.getMessages().get("ITEM_CORRESPONDANCE_INCONNUE").formatted(operationNonIT.getNomItemNonIT(), operationNonIT.getType())); + } else { + // L'ajout d'une opération non it dont la référence d'impact (déterminée à partir de la table ref_type_item) est nulle sort un warning + var etapes = referentielServicePort.getAllEtapes(); + var criteres = referentielServicePort.getAllCriteres(); + for (var critere : criteres) { + for (var etape : etapes) { + var impact = referentielServicePort.getFacteurCaracterisation(critere.getNomCritere(), etape.getCode(), type); + if (impact == null) { + avertissements.add(messageProperties.getMessages().get("ITEM_IMPACT_INCONNU").formatted(type, etape.getCode(), critere.getNomCritere())); + } + } + } + } + return Pair.of(erreurs, avertissements); + } + } diff --git a/services/api-expositiondonneesentrees/src/main/resources/application.yaml b/services/api-expositiondonneesentrees/src/main/resources/application.yaml index c41b811a2864a5167ae0c7222e2dd8da0d123463..2f720681d87caf943159c0352299b0189f16b01b 100644 --- a/services/api-expositiondonneesentrees/src/main/resources/application.yaml +++ b/services/api-expositiondonneesentrees/src/main/resources/application.yaml @@ -76,15 +76,17 @@ caching: messages: LIGNE_INCONSISTENTE: "Fichier %s : La ligne n°%d n'est pas consistente avec les headers du fichier" LIGNE_INCORRECTE: "Fichier %s : La ligne n°%d est incorrecte pour l'objet %s requise" - TYPE_EQUIPEMENT_INCONNU: "Le type d'équipement %s correspondant à l'équipement %s n'existe pas dans la table des références ref_TypeEquipement" - EQUIPEMENT_MIX_ELEC_LOCALISATION_INCONNUE: "Le pays %s correspondant à l'équipement physique %s n'existe pas dans la table des mix électriques ref_MixElec.pays" + TYPE_ITEM_INCONNU: "Le type d'item %s correspondant à l'item %s n'existe pas dans la table des références ref_type_item" + ITEM_MIX_ELEC_LOCALISATION_INCONNUE: "La localisation %s correspondant à l'item %s n'existe pas dans la table des mix électriques ref_MixElec.pays" DATACENTER_MIX_ELEC_LOCALISATION_INCONNUE: "La localisation %s du centre de données %s n'existe pas dans la table des mix électriques ref_MixElec.pays" - EQUIPEMENT_CORRESPONDANCE_INCONNUE: "L'équipement %s de type %s ne possède pas de référence d'équipement par défaut dans la table ref_typeEquipement et pas de correspondance dans la table ref_CorrespondanceRefEqP" - EQUIPEMENT_IMPACT_INCONNU: "L'impact de l'équipement de référence %s pour l'étape %s et le critère %s ne pourra pas être calculé en raison de l'absence de facteur d'impact sur l'équipement" + ITEM_CORRESPONDANCE_INCONNUE: "L'item %s de type %s ne possède pas de référence d'item par défaut dans la table ref_type_item" + EQUIPEMENT_CORRESPONDANCE_INCONNUE: "L'équipement %s de type %s ne possède pas de référence d'équipement par défaut dans la table ref_type_item et pas de correspondance dans la table ref_correspondance_ref_eqp" + ITEM_IMPACT_INCONNU: "L'impact de l'item de référence %s pour l'étape %s et le critère %s ne pourra pas être calculé en raison de l'absence de facteur d'impact sur cet item" EQUIPEMENT_DATE_INCOHERENTE: "L'âge de l'équipement %s ne peut être calculé car sa date de retrait précède sa date d'achat" EQUIPEMENT_MODE_UTILISATION_INCONNU: "Le mode d'utilisation renseigné '%s' est inconnu du référentiel" EQUIPEMENT_TAUX_UTILISATION_INVALIDE: "Le taux d'utilisation renseigné '%s' n'est pas valide, il doit être compris entre 0 et 1, le taux par défaut sera appliqué." EQUIPEMENT_DATACENTER_INCONNU: "L'équipement %s n'est lié à aucun datacenter" + ITEM_NOM_DATACENTER_INCONNU: "Le nom court datacenter de l'item '%s' n'est pas dans la table datacenter" EQUIPEMENT_VIRTUEL_INCONNU: "L'équipement virtuel %s n'est supporté par aucun équipement physique" APPLICATION_AVEC_EQUIPEMENT_PHYSIQUE_INCONNU: "L'application %s n'est supporté par aucun équipement physique" APPLICATION_AVEC_EQUIPEMENT_VIRTUEL_INCONNU: "L'application %s n'est supporté par aucun équipement virtuel" diff --git a/services/api-expositiondonneesentrees/src/main/resources/schema.sql b/services/api-expositiondonneesentrees/src/main/resources/schema.sql index a6b627e6429f87542aede23ed4b0521fd2c032aa..da79c386cfcbe137f198b8dae6a199cc3172d032 100644 --- a/services/api-expositiondonneesentrees/src/main/resources/schema.sql +++ b/services/api-expositiondonneesentrees/src/main/resources/schema.sql @@ -96,6 +96,29 @@ CREATE TABLE IF NOT EXISTS en_application CONSTRAINT en_application_pkey PRIMARY KEY (id) ); +CREATE TABLE IF NOT EXISTS en_operation_non_it +( + id int8 NOT NULL, + date_creation timestamp NULL, + date_update timestamp NULL, + date_update timestamp NULL, + date_lot date NULL, + nom_lot varchar(255) NULL, + nom_organisation varchar(255) NULL, + nom_source_donnee varchar(255) NULL, + nom_item_non_it varchar(255) NULL, + quantite float8 NULL, + type varchar(255) NULL, + duree_de_vie float8 NULL, + localisation varchar(255) NULL, + nom_entite varchar(255) NULL, + nom_court_datacenter varchar(255) NULL, + description varchar(255) NULL, + conso_elec_annuelle float8 NULL, + statut_traitement varchar(255) NULL, + CONSTRAINT en_operation_non_it_pkey PRIMARY KEY (id) +); + CREATE TABLE IF NOT EXISTS en_messagerie ( id int8 NOT NULL, @@ -169,6 +192,11 @@ CREATE INDEX IF NOT EXISTS idx_en_equipement_physique_statut_traitement ON en_eq -- Accelere le count du volume des calculs - api-expositiondonneesentrees CREATE INDEX IF NOT EXISTS idx_en_equipement_physique_nom_lot ON en_equipement_physique (nom_lot); +-- Accelere la recuperation des donnees depuis OperationNonITIntegrationConfig.java +CREATE INDEX IF NOT EXISTS idx_en_operation_non_it_statut_traitement ON en_operation_non_it (statut_traitement); +-- Accelere le count du volume des calculs - api-expositiondonneesentrees +CREATE INDEX IF NOT EXISTS idx_en_operation_non_it_nom_lot ON en_operation_non_it (nom_lot); + -- Indexes pour api-event-calculs -- Accelere la recuperation des equipements virtuels d'un equipement physique CREATE INDEX IF NOT EXISTS idx_en_equipement_virtuel_nom_equipement_physique ON en_equipement_virtuel (nom_equipement_physique); diff --git a/services/api-expositiondonneesentrees/src/main/resources/static/openapi.yaml b/services/api-expositiondonneesentrees/src/main/resources/static/openapi.yaml index 821abfa69dc5d0dfdf300e14f99f09649aae2c83..e7627b35cac88cf4ebac50d0567f425c5d4f44f3 100644 --- a/services/api-expositiondonneesentrees/src/main/resources/static/openapi.yaml +++ b/services/api-expositiondonneesentrees/src/main/resources/static/openapi.yaml @@ -184,6 +184,8 @@ paths: Le Header du CSV des application est : nomApplication;typeEnvironnement;(nomEquipementVirtuel);(nomSourceEquipementVirtuel);domaine;sousDomaine;(nomEntite);nomEquipementPhysique;(nomSourceDonnee). <br/> + Le Header du CSV des opérations non IT est : nomItemNonIT;quantite;type;dureeDeVie;localisation;(nomEntite);(nomSourceDonnee);nomCourtDatacenter;description;consoElecAnnuelle. <br/> + Le Header du CSV de la messagerie est : nombreMailEmis;nombreMailEmisXDestinataires;volumeTotalMailEmis;MoisAnnee;(nomEntite). <br/> Le Header du CSV des entités est : nomEntite;nbCollaborateurs;responsableEntite;responsableNumeriqueResponsable. @@ -216,6 +218,9 @@ paths: csvApplication: type: string format: binary + csvOperationNonIT: + type: string + format: binary csvMessagerie: type: string format: binary @@ -285,6 +290,9 @@ components: equipementPhysique: description: "Bloc equipement physique" $ref: '#/components/schemas/VolumeRest' + operationNonIT: + description: "Bloc opération non it" + $ref: '#/components/schemas/VolumeRest' messagerie: description: "Bloc messagerie" $ref: '#/components/schemas/VolumeRest' @@ -314,6 +322,9 @@ components: nbrApplication: description: Nombre d'application concernées type: integer + nbrOperationNonIT: + description: Nombre d'opérations non IT concernées + type: integer nbrMessagerie: description: Nombre d'éléments de messagerie concernés type: integer @@ -378,6 +389,10 @@ components: type: array items: $ref: "#/components/schemas/EquipementPhysiqueRest" + operationsNonIT: + type: array + items: + $ref: "#/components/schemas/OperationNonITRest" messageries: type: array items: @@ -546,6 +561,40 @@ components: nomSourceDonneeEquipementVirtuel: description: "Nom de la source de la donnée pour l'équipement virtuel" type: string + OperationNonITRest: + description: Représentation d'une opération non IT dans NumEcoEval + properties: + nomItemNonIT: + description: "" + type: string + quantite: + description: "" + type: number + type: + description: "" + type: string + dureeDeVie: + description: "" + type: number + localisation: + description: "" + type: string + nomEntite: + description: "" + type: string + nomSourceDonnee: + description: "Nom de la source de la donnée" + type: string + nomCourtDatacenter: + description: "" + type: string + description: + description: "" + type: string + consoElecAnnuelle: + description: "" + type: number + format: double MessagerieRest: description: Représentation d'éléments de messagerie dans NumEcoEval properties: diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/ImportDonneesEntreePortImplTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/ImportDonneesEntreePortImplTest.java index d4063d474093e97c63092d189b33dea4f9fdb10d..1bad50adcee65618aa3c4c16b942aa47f359709a 100644 --- a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/ImportDonneesEntreePortImplTest.java +++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/ImportDonneesEntreePortImplTest.java @@ -122,6 +122,26 @@ class ImportDonneesEntreePortImplTest { assertEquals("Le fichier CSV des Applications n'est pas trouvable.", resultImport.getKey().getErreurs().get(0)); } + @Test + void importOperationsNonIT_onIOException_shouldReturnReportWith1Error() throws IOException { + Mockito.when(fileToRead.getInputStream()).thenThrow(new IOException("Test")); + + Pair<RapportImport, List<OperationNonIT>> resultImport = importDonneesEntreePort.importOperationsNonIT(null, null, null, fileToRead); + + assertTrue(resultImport.getValue().isEmpty()); + assertEquals("Le fichier CSV des opérations non IT n'est pas lisible par le système.", resultImport.getKey().getErreurs().get(0)); + } + + @Test + void importOperationsNonIT_onFileNotFoundException_shouldReturnReportWith1Error() throws IOException { + Mockito.when(fileToRead.getInputStream()).thenThrow(new FileNotFoundException("Test")); + + Pair<RapportImport, List<OperationNonIT>> resultImport = importDonneesEntreePort.importOperationsNonIT(null, null, null, fileToRead); + + assertTrue(resultImport.getValue().isEmpty()); + assertEquals("Le fichier CSV des opérations non IT n'est pas trouvable.", resultImport.getKey().getErreurs().get(0)); + } + @Test void importMessageries_onIOException_shouldReturnReportWith1Error() throws IOException { Mockito.when(fileToRead.getInputStream()).thenThrow(new IOException("Test")); diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/StatutPourCalculPortImplTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/StatutPourCalculPortImplTest.java index 759780e146182eda45ed3fccfc9c797dc81d13f7..6f8f2676ce809eaeefeaa33a1c9804cd2daf810f 100644 --- a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/StatutPourCalculPortImplTest.java +++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/domain/port/input/StatutPourCalculPortImplTest.java @@ -43,18 +43,23 @@ class StatutPourCalculPortImplTest { /* INPUT VOLUME MOCKED */ var volumeEqPhysique = new Volume(10L, 100L); + var volumeOpNonIT = new Volume(100L, 10L); var volumeMessagerie = new Volume(50L, 5000L); /* EXECUTE : params does not matter in the test */ - var actual = statutPourCalculPort.statutCalculs(volumeEqPhysique, volumeMessagerie); + var actual = statutPourCalculPort.statutCalculs(volumeEqPhysique, volumeOpNonIT, volumeMessagerie); var expected = StatutCalculRest.builder() .statut(StatutCalculRest.StatutEnum.EN_COURS) - .etat("98%") + .etat("96%") .equipementPhysique(VolumeRest.builder() .nbEnCours(10) .nbTraite(100) .build()) + .operationNonIT(VolumeRest.builder() + .nbEnCours(100) + .nbTraite(10) + .build()) .messagerie(VolumeRest.builder() .nbEnCours(50) .nbTraite(5000) @@ -71,10 +76,11 @@ class StatutPourCalculPortImplTest { /* INPUT VOLUME MOCKED */ var volumeEqPhysique = new Volume(0L, 100L); + var volumeOperationNonIT = new Volume(0L, 100L); var volumeMessagerie = new Volume(0L, 5000L); /* EXECUTE : params does not matter in the test */ - var actual = statutPourCalculPort.statutCalculs(volumeEqPhysique, volumeMessagerie); + var actual = statutPourCalculPort.statutCalculs(volumeEqPhysique, volumeOperationNonIT, volumeMessagerie); var expected = StatutCalculRest.builder() .statut(StatutCalculRest.StatutEnum.TERMINE) @@ -83,6 +89,10 @@ class StatutPourCalculPortImplTest { .nbEnCours(0) .nbTraite(100) .build()) + .operationNonIT(VolumeRest.builder() + .nbEnCours(0) + .nbTraite(100) + .build()) .messagerie(VolumeRest.builder() .nbEnCours(0) .nbTraite(5000) @@ -97,7 +107,7 @@ class StatutPourCalculPortImplTest { @Test void testStatutDesCalculs_NotFound() { var volume0 = new Volume(0L, 0L); - assertThrows(NotFoundException.class, () -> statutPourCalculPort.statutCalculs(volume0, volume0)); + assertThrows(NotFoundException.class, () -> statutPourCalculPort.statutCalculs(volume0, volume0, volume0)); } } diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/ImportCSVControllerTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/ImportCSVControllerTest.java index a38ae6109bbf325cdd1341d3d9851d02db9489c5..318f3eed3c261476354402674ae88e51b0d4d465 100644 --- a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/ImportCSVControllerTest.java +++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/controller/ImportCSVControllerTest.java @@ -59,7 +59,7 @@ class ImportCSVControllerTest { @Test void importCSV_onNullFiles_shouldThrowResponseStatusExceptionWithBadRequest() { - var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importInterneCSV("nomLot", "2023-01-01", "TEST", null, null, null, null, null, null)); + var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importInterneCSV("nomLot", "2023-01-01", "TEST", null, null, null, null, null, null, null)); assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode()); assertEquals("Tous les fichiers ne peuvent être vides en même temps", exception.getReason()); @@ -71,10 +71,11 @@ class ImportCSVControllerTest { MockMultipartFile csvEquipements = new MockMultipartFile("csvEquipementsVide.csv", new byte[]{}); MockMultipartFile csvEquipementsVirtuels = new MockMultipartFile("csvEquipementVirtuelVide.csv", new byte[]{}); MockMultipartFile csvApplications = new MockMultipartFile("csvApplicationVide.csv", new byte[]{}); + MockMultipartFile csvOperationsNonIT = new MockMultipartFile("csvOperationsNonITVide.csv", new byte[]{}); MockMultipartFile csvMessagerie = new MockMultipartFile("csvMessagerieVide.csv", new byte[]{}); MockMultipartFile csvEntite = new MockMultipartFile("csvEntiteVide.csv", new byte[]{}); - var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importInterneCSV("nomLot", "2023-01-01", "TEST", csvDataCenters, csvEquipements, csvEquipementsVirtuels, csvApplications, csvMessagerie, csvEntite)); + var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importInterneCSV("nomLot", "2023-01-01", "TEST", csvDataCenters, csvEquipements, csvEquipementsVirtuels, csvApplications, csvOperationsNonIT, csvMessagerie, csvEntite)); assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode()); assertEquals("Tous les fichiers ne peuvent être vides en même temps", exception.getReason()); @@ -88,10 +89,11 @@ class ImportCSVControllerTest { MockMultipartFile csvEquipements = new MockMultipartFile("csvEquipementEquipementNonVide.csv", fileEquipement); MockMultipartFile csvEquipementsVirtuels = null; MockMultipartFile csvApplications = null; + MockMultipartFile csvOperationsNonIT = null; MockMultipartFile csvMessagerie = null; MockMultipartFile csvEntite = null; - var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importInterneCSV("TEST", nomLot, "2023-01-01", csvDataCenters, csvEquipements, csvEquipementsVirtuels, csvApplications, csvMessagerie, csvEntite)); + var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importInterneCSV("TEST", nomLot, "2023-01-01", csvDataCenters, csvEquipements, csvEquipementsVirtuels, csvApplications, csvOperationsNonIT, csvMessagerie, csvEntite)); assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode()); assertEquals("Le nom du Lot ne peut être pas vide", exception.getReason()); @@ -104,10 +106,11 @@ class ImportCSVControllerTest { MockMultipartFile csvEquipements = new MockMultipartFile("csvEquipementEquipementNonVide.csv", fileEquipement); MockMultipartFile csvEquipementsVirtuels = null; MockMultipartFile csvApplications = null; + MockMultipartFile csvoperationNonIT = null; MockMultipartFile csvMessagerie = null; MockMultipartFile csvEntite = null; - var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importInterneCSV("test", "20230101", "TEST", csvDataCenters, csvEquipements, csvEquipementsVirtuels, csvApplications, csvMessagerie, csvEntite)); + var exception = assertThrows(ResponseStatusException.class, () -> importCSVController.importInterneCSV("test", "20230101", "TEST", csvDataCenters, csvEquipements, csvEquipementsVirtuels, csvApplications, csvoperationNonIT, csvMessagerie, csvEntite)); assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode()); assertEquals("La date du lot doit avoir le format yyyy-MM-dd", exception.getReason()); diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/OperationNonITJpaAdapterTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/OperationNonITJpaAdapterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d53b9b73f25732a43271454b0d8d425084680a1c --- /dev/null +++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/jpa/adapter/OperationNonITJpaAdapterTest.java @@ -0,0 +1,66 @@ +package org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.adapter; + +import org.instancio.Instancio; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mte.numecoeval.expositiondonneesentrees.domain.model.OperationNonIT; +import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.entity.OperationNonITEntity; +import org.mte.numecoeval.expositiondonneesentrees.infrastructure.jpa.repository.OperationNonITRepository; +import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapper; +import org.mte.numecoeval.expositiondonneesentrees.infrastructure.mapper.EntreeEntityMapperImpl; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.times; + +@ExtendWith(MockitoExtension.class) +class OperationNonITJpaAdapterTest { + @InjectMocks + private OperationNonITJpaAdapter jpaAdapter; + @Mock + OperationNonITRepository repository; + + EntreeEntityMapper entreeEntityMapper = new EntreeEntityMapperImpl(); + + @BeforeEach + void setup() { + jpaAdapter = new OperationNonITJpaAdapter(repository, entreeEntityMapper); + } + + @Test + void saveShouldConvertAndCallSave() { + OperationNonIT domain = Instancio.of(OperationNonIT.class).create(); + ArgumentCaptor<OperationNonITEntity> valueCapture = ArgumentCaptor.forClass(OperationNonITEntity.class); + + jpaAdapter.save(domain); + + Mockito.verify(repository, times(1)).save(valueCapture.capture()); + assertNotNull(valueCapture.getValue()); + } + + @Test + void saveAllShouldConvertAndCallSaveAll() { + OperationNonIT domain1 = Instancio.of(OperationNonIT.class).create(); + OperationNonIT domain2 = Instancio.of(OperationNonIT.class).create(); + ArgumentCaptor<List<OperationNonITEntity>> valueCapture = ArgumentCaptor.forClass(List.class); + List<OperationNonIT> entrees = Arrays.asList( + domain1, + domain2 + ); + + jpaAdapter.saveAll(entrees); + + Mockito.verify(repository, times(1)).saveAll(valueCapture.capture()); + assertNotNull(valueCapture.getValue()); + assertEquals(2, valueCapture.getValue().size()); + } +} diff --git a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementServiceTest.java b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementServiceTest.java index 0e4adc46067632e80213c44e6c6ee6bb155b6e2b..dc59827e83bebc6889ddb898e62d72a87c00874b 100644 --- a/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementServiceTest.java +++ b/services/api-expositiondonneesentrees/src/test/java/org/mte/numecoeval/expositiondonneesentrees/infrastructure/service/ErrorManagementServiceTest.java @@ -1,5 +1,10 @@ package org.mte.numecoeval.expositiondonneesentrees.infrastructure.service; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.apache.commons.lang3.tuple.Pair; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -8,49 +13,42 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; import org.mte.numecoeval.expositiondonneesentrees.domain.model.EquipementPhysique; +import org.mte.numecoeval.expositiondonneesentrees.domain.model.OperationNonIT; import org.mte.numecoeval.expositiondonneesentrees.domain.ports.output.ReferentielServicePort; import org.mte.numecoeval.expositiondonneesentrees.infrastructure.config.MessageProperties; +import org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.model.CritereDTO; +import org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.model.EtapeDTO; +import org.mte.numecoeval.expositiondonneesentrees.referentiels.generated.api.model.FacteurCaracterisationDTO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.ConfigDataApplicationContextInitializer; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; import java.io.IOException; import java.time.LocalDate; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Arrays; import java.util.List; -import java.util.Map; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; -@ExtendWith(MockitoExtension.class) +@ExtendWith({MockitoExtension.class, SpringExtension.class}) +@ContextConfiguration(initializers = ConfigDataApplicationContextInitializer.class) +@EnableConfigurationProperties(value = MessageProperties.class) public class ErrorManagementServiceTest { - @Mock + private static final ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule()); + + @Autowired MessageProperties messageProperties; @InjectMocks ErrorManagementService errorManagementService; @Mock ReferentielServicePort referentielServicePort; - private Map<String, String> messages = new HashMap<>(); - @BeforeEach public void init() { - List<String> modeUtilisationList = new ArrayList<>(); - errorManagementService = new ErrorManagementService(messageProperties, referentielServicePort, modeUtilisationList); - messages.put("LIGNE_INCONSISTENTE", "Fichier %s , La ligne n°%d n'est pas consistente avec les headers du fichier"); - messages.put("LIGNE_INCORRECTE", "Fichier %s , La ligne n°%d est incorrecte pour l'objet %s requise"); - messages.put("TYPE_EQUIPEMENT_INCONNU", "Le type d'équipement %s correspondant à l'équipement %s n'existe pas dans la table des références ref_TypeEquipement"); - messages.put("EQUIPEMENT_MIX_ELEC_LOCALISATION_INCONNUE", "Le pays %s correspondant à l'équipement physique %s n'existe pas dans la table des mix électriques ref_MixElec.pays"); - messages.put("DATACENTER_MIX_ELEC_LOCALISATION_INCONNUE", "La localisation %s du centre de données %s n'existe pas dans la table des mix électriques ref_MixElec.pays"); - messages.put("EQUIPEMENT_CORRESPONDANCE_INCONNUE", "L'équipement %s de type %s ne possède pas de référence d'équipement par défaut dans la table ref_typeEquipement et pas de correspondance dans la table ref_CorrespondanceRefEqP"); - messages.put("EQUIPEMENT_IMPACT_INCONNU", "L'impact de l'équipement de référence %s pour l'étape %s et le critère %s ne pourra pas être calculé en raison de l'absence de facteur d'impact sur l'équipement"); - messages.put("EQUIPEMENT_DATE_INCOHERENTE", "L'âge de l'équipement %s ne peut être calculé car sa date de retrait précède sa date d'achat"); - messages.put("EQUIPEMENT_MODE_UTILISATION_INCONNU", "Le mode d'utilisation renseigné '%s' est inconnu du référentiel"); - messages.put("EQUIPEMENT_TAUX_UTILISATION_INVALIDE", "Le taux d'utilisation renseigné '%s' n'est pas valide, il doit être compris entre 0 et 1, le taux par défaut sera appliqué."); - messages.put("EQUIPEMENT_DATACENTER_INCONNU", "L'équipement %s n'est lié à aucun datacenter"); - messages.put("EQUIPEMENT_VIRTUEL_INCONNU", "L'équipement virtuel %s n'est supporté par aucun équipement physique"); - messages.put("APPLICATION_AVEC_EQUIPEMENT_PHYSIQUE_INCONNU", "L'application %s n'est supporté par aucun équipement physique"); - messages.put("APPLICATION_AVEC_EQUIPEMENT_VIRTUEL_INCONNU", "L'application %s n'est supporté par aucun équipement virtuel"); - Mockito.lenient().when(messageProperties.getMessages()).thenReturn(messages); + errorManagementService = new ErrorManagementService(messageProperties, referentielServicePort, new ArrayList<>()); } @Test @@ -67,7 +65,7 @@ public class ErrorManagementServiceTest { .modeUtilisation("COPE").build(); var actual = errorManagementService.checkEquipementPhysique(eq1, ""); - assertTrue(actual.getKey().stream().anyMatch(ds -> "L'âge de l'équipement physical-eq-001 ne peut être calculé car sa date de retrait précède sa date d'achat".equals(ds))); + Assertions.assertTrue(actual.getKey().stream().anyMatch("L'âge de l'équipement physical-eq-001 ne peut être calculé car sa date de retrait précède sa date d'achat"::equals)); } @Test @@ -84,6 +82,86 @@ public class ErrorManagementServiceTest { .modeUtilisation("COPE").build(); var actual = errorManagementService.checkEquipementPhysique(eq1, ""); - assertFalse(actual.getKey().stream().anyMatch(ds -> "L'âge de l'équipement physical-eq-001 ne peut être calculé car sa date de retrait précède sa date d'achat".equals(ds))); + Assertions.assertFalse(actual.getKey().stream().anyMatch("L'âge de l'équipement physical-eq-001 ne peut être calculé car sa date de retrait précède sa date d'achat"::equals)); + } + + @Test + void importOperationNonIT_with_TypeNotInRefType_shouldReturnReportWith1Error() { + OperationNonIT eq1 = OperationNonIT.builder() + .nomItemNonIT("Batiment_datacenter_St_Malo") + .quantite(1.0) + .dureeDeVie(5.0) + .type("Monitor") + .localisation("France").build(); + var actual = errorManagementService.checkOperationNonIT(eq1, null); + Assertions.assertEquals("L'item Batiment_datacenter_St_Malo de type Monitor ne possède pas de référence d'item par défaut dans la table ref_type_item", actual.getKey().get(0)); + + } + + @Test + void importOperationNonIT_with_TypeNotRefTypeItem_shouldReturnReportWith1Error() throws JsonProcessingException { + OperationNonIT eq1 = OperationNonIT.builder() + .nomItemNonIT("Batiment_datacenter_St_Malo") + .quantite(1.0) + .dureeDeVie(5.0) + .type("batiment") + .localisation("France").build(); + + /* MOCK REFERENTIEL : FacteurCaracterisation */ + Mockito.lenient().when(referentielServicePort.getFacteurCaracterisation(any(), any(), any())).thenReturn(null); + + /* MOCK REFERENTIEL : Etapes */ + Mockito.lenient().when(referentielServicePort.getAllEtapes()).thenReturn(Arrays.asList(mapper.readValue(""" + [{ "code": "UTILISATION", "libelle": "Using" }] + """, EtapeDTO[].class))); + + /* MOCK REFERENTIEL : Criteres */ + Mockito.lenient().when(referentielServicePort.getAllCriteres()).thenReturn(Arrays.asList(mapper.readValue(""" + [{ + "nomCritere": "Climate change", + "unite": "kg CO2 eq", + "description": "Greenhouse gases (GHG)" + }] + """, CritereDTO[].class))); + var actual = errorManagementService.checkOperationNonIT(eq1, eq1.getType()); + Assertions.assertEquals("L'impact de l'item de référence batiment pour l'étape UTILISATION et le critère Climate change ne pourra pas être calculé en raison de l'absence de facteur d'impact sur cet item", actual.getValue().get(0)); + } + + @Test + void importOperationNonIT_with_TypeInRefTypeItem_shouldNotReturnError() throws JsonProcessingException { + OperationNonIT eq1 = OperationNonIT.builder() + .nomItemNonIT("Batiment_datacenter_St_Malo") + .quantite(1.0) + .dureeDeVie(5.0) + .type("batiment") + .localisation("France").build(); + + /* MOCK REFERENTIEL : FacteurCaracterisation */ + Mockito.lenient().when(referentielServicePort.getFacteurCaracterisation(any(), any(), any())).thenReturn(mapper.readValue(""" + { + "nom": "reseau-fixe-1", + "etape" : "UTILISATION", + "critere" : "Climate change", + "localisation": "France", + "consoElecMoyenne": 12.7, + "valeur" : "8.34" + } + """, FacteurCaracterisationDTO.class)); + + /* MOCK REFERENTIEL : Etapes */ + Mockito.lenient().when(referentielServicePort.getAllEtapes()).thenReturn(Arrays.asList(mapper.readValue(""" + [{ "code": "UTILISATION", "libelle": "Using" }] + """, EtapeDTO[].class))); + + /* MOCK REFERENTIEL : Criteres */ + Mockito.lenient().when(referentielServicePort.getAllCriteres()).thenReturn(Arrays.asList(mapper.readValue(""" + [{ + "nomCritere": "Climate change", + "unite": "kg CO2 eq", + "description": "Greenhouse gases (GHG)" + }] + """, CritereDTO[].class))); + Pair<List<String>, List<String>> actual = errorManagementService.checkOperationNonIT(eq1, eq1.getType()); + Assertions.assertEquals(0, actual.getKey().size()); } } diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/Hypothese.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/Hypothese.java index 1c55577c9ee2320a50ceed50ed7ffac765ad3c15..a1248c8efa5f5d142e89b60b449fc5b95a707494 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/Hypothese.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/Hypothese.java @@ -1,10 +1,6 @@ package org.mte.numecoeval.referentiel.domain.model; -import lombok.AccessLevel; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; +import lombok.*; import lombok.experimental.Accessors; import lombok.experimental.FieldDefaults; @@ -18,5 +14,6 @@ public class Hypothese implements AbstractReferentiel { String code; String valeur; String source; + String description; } diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/TypeItem.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/TypeItem.java new file mode 100644 index 0000000000000000000000000000000000000000..363366091d269083926b4fd1e6f5a7bc628605f0 --- /dev/null +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/model/TypeItem.java @@ -0,0 +1,22 @@ +package org.mte.numecoeval.referentiel.domain.model; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Data; +import lombok.experimental.FieldDefaults; + +@Builder +@Data +@FieldDefaults(level = AccessLevel.PRIVATE) +public class TypeItem implements AbstractReferentiel { + String type; + String categorie; + boolean serveur; + String commentaire; + Double dureeVieDefaut; + String refHypothese; + String source; + // Référence de l'item par défaut, permet des correspondances en cas d'absence de correspondance directe. + String refItemParDefaut; + +} diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportHypothesePortImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportHypothesePortImpl.java index a14c212bf109b37daa8441740e7cf7c1e9d937e8..925ad02f229a0a897d473fccff3a5919fff08d85 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportHypothesePortImpl.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportHypothesePortImpl.java @@ -3,10 +3,10 @@ package org.mte.numecoeval.referentiel.domain.ports.input.impl; import lombok.extern.slf4j.Slf4j; import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVRecord; -import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.HypotheseDTO; import org.mte.numecoeval.referentiel.domain.data.ResultatImport; import org.mte.numecoeval.referentiel.domain.exception.ReferentielException; import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort; +import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.HypotheseDTO; import java.io.InputStream; import java.io.InputStreamReader; @@ -18,14 +18,16 @@ import java.util.List; @Slf4j public class ImportHypothesePortImpl implements ImportCSVReferentielPort<HypotheseDTO> { private static final String HEADER_VALEUR = "valeur"; - private static final String[] HEADERS = new String[]{"cle", HEADER_VALEUR, "source"}; + private static final String[] MANDATORY_HEADERS = new String[]{"cle", HEADER_VALEUR, "source"}; + + private static final String[] HEADERS = new String[]{"cle", HEADER_VALEUR, "source", "description"}; public static String[] getHeaders() { return HEADERS; } public void checkCSVRecord(CSVRecord csvRecord) throws ReferentielException { - checkAllHeadersAreMapped(csvRecord, HEADERS); + checkAllHeadersAreMapped(csvRecord, MANDATORY_HEADERS); checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, "cle"); checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, HEADER_VALEUR); } @@ -50,11 +52,11 @@ public class ImportHypothesePortImpl implements ImportCSVReferentielPort<Hypothe .valeur(csvRecord.get(HEADER_VALEUR).trim()) .code(csvRecord.get("cle").trim()) .source(csvRecord.get("source").trim()) + .description(getStringValueFromRecord(csvRecord, "description")) .build()); - } - catch (Exception e) { - log.error("Erreur prévue lors de la lecture de la ligne {} : {}", csvRecord.getRecordNumber()+1, e.getMessage()); - resultatImport.getErreurs().add( e.getMessage() ); + } catch (Exception e) { + log.error("Erreur prévue lors de la lecture de la ligne {} : {}", csvRecord.getRecordNumber() + 1, e.getMessage()); + resultatImport.getErreurs().add(e.getMessage()); } }); diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportTypeItemPortImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportTypeItemPortImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..73182924f3cb27779e65767de59845065f55ab0d --- /dev/null +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/input/impl/ImportTypeItemPortImpl.java @@ -0,0 +1,78 @@ +package org.mte.numecoeval.referentiel.domain.ports.input.impl; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVRecord; +import org.apache.commons.lang3.BooleanUtils; +import org.mte.numecoeval.referentiel.domain.data.ResultatImport; +import org.mte.numecoeval.referentiel.domain.exception.ReferentielException; +import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort; +import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeItemDTO; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Slf4j +public class ImportTypeItemPortImpl implements ImportCSVReferentielPort<TypeItemDTO> { + private static final String HEADER_TYPE = "type"; + private static final String[] HEADERS = new String[]{HEADER_TYPE, "categorie", "serveur", "commentaire", "dureeVieDefaut", "refHypothese", "source", "refItemParDefaut"}; + + public static String[] getHeaders() { + return HEADERS; + } + + public void checkCSVRecord(CSVRecord csvRecord) throws ReferentielException { + checkAllHeadersAreMapped(csvRecord, HEADERS); + checkFieldIsMappedAndNotBlankInCSVRecord(csvRecord, HEADER_TYPE); + } + + @Override + public ResultatImport<TypeItemDTO> importCSV(InputStream csvInputStream) { + ResultatImport<TypeItemDTO> resultatImport = new ResultatImport<>(); + List<TypeItemDTO> dtos = new ArrayList<>(); + + try (Reader reader = new InputStreamReader(csvInputStream)) { + Iterable<CSVRecord> records = CSVFormat.DEFAULT.builder() + .setHeader() + .setDelimiter(CSV_SEPARATOR) + .setTrim(true) + .setAllowMissingColumnNames(true) + .setSkipHeaderRecord(true) + .build().parse(reader); + records.forEach(csvRecord -> { + try { + checkCSVRecord(csvRecord); + dtos.add(TypeItemDTO.builder() + .type(csvRecord.get(HEADER_TYPE).trim()) + .categorie(csvRecord.get("categorie").trim()) + .serveur(BooleanUtils.toBoolean(csvRecord.get("serveur").trim())) + .commentaire(csvRecord.get("commentaire").trim()) + .dureeVieDefaut(getDoubleValueFromRecord(csvRecord, "dureeVieDefaut", null)) + .refHypothese(csvRecord.get("refHypothese").trim()) + .source(csvRecord.get("source").trim()) + .refItemParDefaut(getStringValueFromRecord(csvRecord, "refItemParDefaut")) + .build()); + } catch (Exception e) { + log.error("Erreur prévue lors de la lecture de la ligne {} : {}", csvRecord.getRecordNumber() + 1, e.getMessage()); + resultatImport.getErreurs().add(e.getMessage()); + } + }); + + } catch (Exception e) { + log.error("Erreur de traitement du fichier", e); + + resultatImport.setErreurs(Collections.singletonList("Le fichier CSV n'a pas pu être lu.")); + resultatImport.setNbrLignesImportees(0); + resultatImport.setObjects(null); + return resultatImport; + } + resultatImport.setObjects(dtos); + resultatImport.setNbrLignesImportees(dtos.size()); + return resultatImport; + } + +} diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/output/ReferentielPersistencePort.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/output/ReferentielPersistencePort.java index 8ea16327109dcd0edaa87801de08a740f88876b9..78061eaf1ff653614d3459b23294a5bafc30f95f 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/output/ReferentielPersistencePort.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/domain/ports/output/ReferentielPersistencePort.java @@ -45,5 +45,14 @@ public interface ReferentielPersistencePort<T extends AbstractReferentiel, P ext */ List<T> getAll(); + /** + * Find by filters + * + * @param params param list + * @return the list of objects + */ + default List<T> findByFilters(String... params) throws ReferentielException { + return List.of(); + } } diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/HypotheseCsvExportService.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/HypotheseCsvExportService.java index 684802434814496fe3fb183ca27a8dd6f785e7af..e5a44db7d86b9daf4dced6adf94b789059357397 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/HypotheseCsvExportService.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/HypotheseCsvExportService.java @@ -37,7 +37,7 @@ public class HypotheseCsvExportService extends ReferentielCsvExportService<Hypot @Override public void printRecord(CSVPrinter csvPrinter, HypotheseEntity objectToWrite) throws IOException { - csvPrinter.printRecord(objectToWrite.getCode(),objectToWrite.getValeur(),objectToWrite.getSource()); + csvPrinter.printRecord(objectToWrite.getCode(), objectToWrite.getValeur(), objectToWrite.getSource(), objectToWrite.getDescription()); } } diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeEquipementCsvExportService.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeEquipementCsvExportService.java index adee3de7ce6a40528edc120eac8b4420da7c6b52..51bcb9f0d24813cd5917fbf28ecd293aba7866ff 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeEquipementCsvExportService.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeEquipementCsvExportService.java @@ -1,23 +1,33 @@ package org.mte.numecoeval.referentiel.infrastructure.adapter.export; import org.apache.commons.csv.CSVPrinter; +import org.mte.numecoeval.referentiel.domain.model.TypeEquipement; +import org.mte.numecoeval.referentiel.domain.model.TypeItem; import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportTypeEquipementPortImpl; import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielCsvExportService; -import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.TypeEquipementEntity; -import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.TypeEquipementRepository; +import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.TypeItemRepository; +import org.mte.numecoeval.referentiel.infrastructure.mapper.TypeEquipementMapper; +import org.mte.numecoeval.referentiel.infrastructure.mapper.TypeItemMapper; import org.springframework.stereotype.Service; import java.io.IOException; import java.util.List; +import static org.mte.numecoeval.referentiel.utils.Constants.CATEGORIE_EQUIPEMENT_PHYSIQUE; + @Service -public class TypeEquipementCsvExportService extends ReferentielCsvExportService<TypeEquipementEntity> { +public class TypeEquipementCsvExportService extends ReferentielCsvExportService<TypeEquipement> { + + private final TypeItemRepository repository; + private final TypeItemMapper typeItemMapper; + private final TypeEquipementMapper typeEquipementMapper; - private final TypeEquipementRepository repository; - public TypeEquipementCsvExportService(TypeEquipementRepository repository) { - super(TypeEquipementEntity.class); + public TypeEquipementCsvExportService(TypeItemRepository repository, TypeItemMapper typeItemMapper, TypeEquipementMapper typeEquipementMapper) { + super(TypeEquipement.class); this.repository = repository; + this.typeItemMapper = typeItemMapper; + this.typeEquipementMapper = typeEquipementMapper; } @Override @@ -26,17 +36,18 @@ public class TypeEquipementCsvExportService extends ReferentielCsvExportService< } @Override - public List<TypeEquipementEntity> getObjectsToWrite() { - return repository.findAll(); + public List<TypeEquipement> getObjectsToWrite() { + List<TypeItem> typeItemList = typeItemMapper.toDomains(repository.findByCategorie(CATEGORIE_EQUIPEMENT_PHYSIQUE)); + return typeEquipementMapper.toTypeEquipements(typeItemList); } @Override - protected String getObjectId(TypeEquipementEntity object) { + protected String getObjectId(TypeEquipement object) { return object.getType(); } @Override - public void printRecord(CSVPrinter csvPrinter, TypeEquipementEntity objectToWrite) throws IOException { + public void printRecord(CSVPrinter csvPrinter, TypeEquipement objectToWrite) throws IOException { csvPrinter.printRecord(objectToWrite.getType(), objectToWrite.isServeur(), objectToWrite.getCommentaire(), diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeItemCsvExportService.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeItemCsvExportService.java new file mode 100644 index 0000000000000000000000000000000000000000..851bba7b29e1f6cf504270b4fd76745036eef4e3 --- /dev/null +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeItemCsvExportService.java @@ -0,0 +1,49 @@ +package org.mte.numecoeval.referentiel.infrastructure.adapter.export; + +import org.apache.commons.csv.CSVPrinter; +import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportTypeItemPortImpl; +import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielCsvExportService; +import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.TypeItemEntity; +import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.TypeItemRepository; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.util.List; + +@Service +public class TypeItemCsvExportService extends ReferentielCsvExportService<TypeItemEntity> { + + private final TypeItemRepository repository; + + public TypeItemCsvExportService(TypeItemRepository repository) { + super(TypeItemEntity.class); + this.repository = repository; + } + + @Override + public String[] getHeaders() { + return ImportTypeItemPortImpl.getHeaders(); + } + + @Override + public List<TypeItemEntity> getObjectsToWrite() { + return repository.findAll(); + } + + @Override + protected String getObjectId(TypeItemEntity object) { + return object.getType(); + } + + @Override + public void printRecord(CSVPrinter csvPrinter, TypeItemEntity objectToWrite) throws IOException { + csvPrinter.printRecord(objectToWrite.getType(), + objectToWrite.getCategorie(), + objectToWrite.isServeur(), + objectToWrite.getCommentaire(), + formatDouble(objectToWrite.getDureeVieDefaut()), + objectToWrite.getRefHypothese(), + objectToWrite.getSource(), objectToWrite.getRefItemParDefaut()); + } + +} diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/init/MigrationToRefTypeItem.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/init/MigrationToRefTypeItem.java new file mode 100644 index 0000000000000000000000000000000000000000..a4f9a4cf9a8d3d132133aff76151dbc15ca2b04d --- /dev/null +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/init/MigrationToRefTypeItem.java @@ -0,0 +1,35 @@ +package org.mte.numecoeval.referentiel.infrastructure.init; + +import jakarta.annotation.PostConstruct; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.mte.numecoeval.referentiel.domain.exception.ReferentielException; +import org.mte.numecoeval.referentiel.infrastructure.jpa.adapter.TypeItemJpaAdapter; +import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.TypeEquipementEntity; +import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.TypeEquipementRepository; +import org.mte.numecoeval.referentiel.infrastructure.mapper.TypeEquipementMapper; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Slf4j +@AllArgsConstructor +public class MigrationToRefTypeItem { + + private TypeEquipementRepository typeEquipementRepository; + private TypeEquipementMapper typeEquipementMapper; + private TypeItemJpaAdapter typeItemJpaAdapter; + + @PostConstruct + public void init() throws ReferentielException { + log.info("démarrage de la migration de la table ref_type_equipement vers ref_type_item"); + List<TypeEquipementEntity> typesEquipement = typeEquipementRepository.findAll(); + if (!typesEquipement.isEmpty()) { + log.info("migration des référentiels de types d'équipements existants vers la nouvelle table"); + typeItemJpaAdapter.saveAll(typeEquipementMapper.toTypesItem(typeEquipementMapper.toDomaines(typesEquipement))); + typeEquipementRepository.deleteAll(); + log.info("fin de la migration de la table ref_type_equipement vers ref_type_item"); + } + } +} diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/CorrespondanceRefEquipementJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/CorrespondanceRefEquipementJpaAdapter.java index f57cd54eff759fa682146d885396b2bc09e70168..39b3a471cf91b174f075d3ff3fc4011b597d344d 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/CorrespondanceRefEquipementJpaAdapter.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/CorrespondanceRefEquipementJpaAdapter.java @@ -16,7 +16,7 @@ import java.util.List; @Service @Slf4j @AllArgsConstructor -public class CorrespondanceRefEquipementJpaAdapter implements ReferentielPersistencePort<CorrespondanceRefEquipement,String> { +public class CorrespondanceRefEquipementJpaAdapter implements ReferentielPersistencePort<CorrespondanceRefEquipement, String> { CorrespondanceRefEquipementMapper mapper; CorrespondanceRefEquipementRepository repository; @@ -24,7 +24,7 @@ public class CorrespondanceRefEquipementJpaAdapter implements ReferentielPersist @Override public CorrespondanceRefEquipement save(CorrespondanceRefEquipement referentiel) throws ReferentielException { var entityToSave = mapper.toEntity(referentiel); - if(entityToSave != null) { + if (entityToSave != null) { var entitySaved = repository.save(entityToSave); return mapper.toDomain(entitySaved); } @@ -41,11 +41,11 @@ public class CorrespondanceRefEquipementJpaAdapter implements ReferentielPersist @Override public CorrespondanceRefEquipement get(String id) throws ReferentielException { - if(id != null) { - var entityOpt= repository.findById(id); + if (id != null) { + var entityOpt = repository.findById(id); return entityOpt .map(entity -> mapper.toDomain(entity)) - .orElseThrow(() -> new ReferentielException("Correspondance au RefEquipement "+ id +" non trouvé")); + .orElseThrow(() -> new ReferentielException("Correspondance au RefEquipement " + id + " non trouvé")); } throw new ReferentielException("Correspondance au RefEquipement (id null) non trouvé"); } @@ -63,4 +63,5 @@ public class CorrespondanceRefEquipementJpaAdapter implements ReferentielPersist .map(typeEquipementEntity -> mapper.toDomain(typeEquipementEntity)) .toList(); } + } diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/EtapeJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/EtapeJpaAdapter.java index f41082688aca9e14fffef4141d7132667ac5e51d..b1aadad62690147b79edb7fa4724c7a7e408a10b 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/EtapeJpaAdapter.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/EtapeJpaAdapter.java @@ -52,4 +52,5 @@ public class EtapeJpaAdapter implements ReferentielPersistencePort<Etape, EtapeI public List<Etape> getAll() { return etapeMapper.toDomains(etapeRepository.findAll()); } + } diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/FacteurCaracterisationJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/FacteurCaracterisationJpaAdapter.java index a01d01daab7ca1dcdcf67e8fbaa58b8c62ce6d99..9456a4818963fbb5f9b16c7ec1a61bcb8b6b2257 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/FacteurCaracterisationJpaAdapter.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/FacteurCaracterisationJpaAdapter.java @@ -21,11 +21,11 @@ import java.util.Optional; @Slf4j @AllArgsConstructor public class FacteurCaracterisationJpaAdapter implements ReferentielPersistencePort<FacteurCaracterisation, FacteurCaracterisationId> { + private FacteurCaracterisationRepository repository; private FacteurCaracterisationMapper mapper; - @Override public FacteurCaracterisation save(FacteurCaracterisation referentiel) throws ReferentielException { var entityToSave = mapper.toEntity(referentiel); @@ -54,6 +54,14 @@ public class FacteurCaracterisationJpaAdapter implements ReferentielPersistenceP throw new ReferentielException("Facteur Caractérisation non trouvé"); } + @Override + public List<FacteurCaracterisation> findByFilters(String... params) throws ReferentielException { + List<FacteurCaracterisationEntity> facteurCaracterisationEntity = + repository.findByCritereAndEtapeAndNomAndLocalisationAndCategorie(params[0], params[1], params[2], params[3], params[4]); + + return mapper.toDomains(facteurCaracterisationEntity); + } + @Override public void purge() { repository.deleteAll(); diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/HypotheseJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/HypotheseJpaAdapter.java index ec82b030e9eb5fea4709fbcdf3cc9ace87cc64dd..1ec8b369edcb46a712ad02b4b79efa2381b32529 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/HypotheseJpaAdapter.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/HypotheseJpaAdapter.java @@ -28,7 +28,7 @@ public class HypotheseJpaAdapter implements ReferentielPersistencePort<Hypothese @Override public Hypothese save(Hypothese referentiel) throws ReferentielException { var entityToSave = hypotheseMapper.toEntity(referentiel); - if(entityToSave != null) { + if (entityToSave != null) { var entitySaved = hypotheseRepository.save(entityToSave); return hypotheseMapper.toDomain(entitySaved); } diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/ImpactMessagerieJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/ImpactMessagerieJpaAdapter.java index 585544e835c4e9608192d2ce99bb80cb90548d47..d6142962d8fa2e98d875c0600ab46b87082172fe 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/ImpactMessagerieJpaAdapter.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/ImpactMessagerieJpaAdapter.java @@ -17,7 +17,7 @@ import java.util.List; @Service @Slf4j @AllArgsConstructor -public class ImpactMessagerieJpaAdapter implements ReferentielPersistencePort<ImpactMessagerie,String> { +public class ImpactMessagerieJpaAdapter implements ReferentielPersistencePort<ImpactMessagerie, String> { ImpactMessagerieMapper impactMessagerieMapper; ImpactMessagerieRepository impactMessagerieRepository; @@ -36,8 +36,8 @@ public class ImpactMessagerieJpaAdapter implements ReferentielPersistencePort<Im @Override public ImpactMessagerie get(String critere) throws ReferentielException { - if(critere != null) { - var entityOpt= impactMessagerieRepository.findById(critere); + if (critere != null) { + var entityOpt = impactMessagerieRepository.findById(critere); return entityOpt .map(impactMessagerieEntity -> impactMessagerieMapper.toDomain(impactMessagerieEntity)) .orElseThrow(() -> new ReferentielException("ImpactMessagerie non trouvé")); diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/MixElectriqueJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/MixElectriqueJpaAdapter.java index f1131a65b1bb1bace3fc2739ea948103d4d1e0ef..9916db201dedad228a31d95d283d0f851f369084 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/MixElectriqueJpaAdapter.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/MixElectriqueJpaAdapter.java @@ -16,7 +16,6 @@ import org.springframework.stereotype.Service; import java.util.Collection; import java.util.List; -import java.util.Optional; @Service @@ -51,9 +50,12 @@ public class MixElectriqueJpaAdapter implements ReferentielPersistencePort<MixEl public MixElectrique get(MixElectriqueId id) throws ReferentielException { if (id != null) { - Optional<FacteurCaracterisationEntity> facteurCaracterisationEntities = facteurCaracterisationRepository.findByNiveauAndCategorieAndLocalisationAndCritere(Constants.MIXELEC_NIVEAU, Constants.MIXELEC_CATEGORIE, id.getPays(), id.getCritere()); - if (facteurCaracterisationEntities.isPresent()) { - return mixElectriqueMapper.toMixElectrique(facteurCaracterisationMapper.toDomain(facteurCaracterisationEntities.get())); + List<FacteurCaracterisationEntity> facteurCaracterisationEntities = facteurCaracterisationRepository.findByNiveauAndCategorieAndLocalisationAndCritere(Constants.MIXELEC_NIVEAU, Constants.MIXELEC_CATEGORIE, id.getPays(), id.getCritere()); + if (!facteurCaracterisationEntities.isEmpty()) { + if (facteurCaracterisationEntities.size() > 1) { + log.warn("Il y a plusieurs mix électriques pour la même localisation {} et critère {}", id.getPays(), id.getCritere()); + } + return mixElectriqueMapper.toMixElectrique(facteurCaracterisationMapper.toDomain(facteurCaracterisationEntities.get(0))); } else { throw new ReferentielException("Mix Electrique non trouvé pour l'id " + id); } @@ -70,5 +72,4 @@ public class MixElectriqueJpaAdapter implements ReferentielPersistencePort<MixEl public List<MixElectrique> getAll() { return mixElectriqueMapper.toMixElectriques(facteurCaracterisationMapper.toDomains(facteurCaracterisationRepository.findByNiveauAndCategorie(Constants.MIXELEC_NIVEAU, Constants.MIXELEC_CATEGORIE))); } - } diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/TypeEquipementJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/TypeEquipementJpaAdapter.java index e0c2e7d9d1136f0bf5f91361a5426c81fcfa7f8b..34e623df3b4c0f15516616efe18cdcb7b429ef0b 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/TypeEquipementJpaAdapter.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/TypeEquipementJpaAdapter.java @@ -2,59 +2,67 @@ package org.mte.numecoeval.referentiel.infrastructure.jpa.adapter; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections4.ListUtils; import org.mte.numecoeval.referentiel.domain.exception.ReferentielException; import org.mte.numecoeval.referentiel.domain.model.TypeEquipement; +import org.mte.numecoeval.referentiel.domain.model.TypeItem; import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort; -import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.TypeEquipementRepository; +import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.TypeItemEntity; +import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.TypeItemRepository; import org.mte.numecoeval.referentiel.infrastructure.mapper.TypeEquipementMapper; +import org.mte.numecoeval.referentiel.infrastructure.mapper.TypeItemMapper; import org.springframework.stereotype.Service; import java.util.Collection; import java.util.List; +import java.util.Optional; + +import static org.mte.numecoeval.referentiel.utils.Constants.CATEGORIE_EQUIPEMENT_PHYSIQUE; @Service @Slf4j @AllArgsConstructor -public class TypeEquipementJpaAdapter implements ReferentielPersistencePort<TypeEquipement,String> { +public class TypeEquipementJpaAdapter implements ReferentielPersistencePort<TypeEquipement, String> { + TypeItemRepository typeItemRepository; + TypeItemMapper typeItemMapper; TypeEquipementMapper typeEquipementMapper; - TypeEquipementRepository typeEquipementRepository; @Override public TypeEquipement save(TypeEquipement referentiel) throws ReferentielException { - typeEquipementRepository.save(typeEquipementMapper.toEntity(referentiel)); + var entityToSave = typeItemMapper.toEntity(typeEquipementMapper.toTypeItem(referentiel)); + if (entityToSave != null) { + typeItemRepository.save(entityToSave); + return referentiel; + } return null; } @Override public void saveAll(Collection<TypeEquipement> referentiels) throws ReferentielException { - typeEquipementRepository.saveAll(ListUtils.emptyIfNull(referentiels - .stream() - .map(typeEquipement -> typeEquipementMapper.toEntity(typeEquipement)) - .toList())); + List<TypeItem> typeItemList = typeEquipementMapper.toTypesItem(referentiels.stream().toList()); + typeItemRepository.saveAll(typeItemMapper.toEntities(typeItemList)); } @Override public TypeEquipement get(String id) throws ReferentielException { - var entityOpt= typeEquipementRepository.findById(id); - if(entityOpt.isPresent()){ - return typeEquipementMapper.toDomaine(entityOpt.get()); + if (id == null) throw new ReferentielException("Type Equipement non trouvé pour l'id null"); + + Optional<TypeItemEntity> typeItemEntities = typeItemRepository.findById(id); + if (typeItemEntities.isPresent()) { + return typeEquipementMapper.toTypeEquipement(typeItemMapper.toDomain(typeItemEntities.get())); + } else { + throw new ReferentielException("Type Equipement non trouvé pour l'id " + id); } - return null; } @Override public void purge() { - typeEquipementRepository.deleteAll(); + typeItemRepository.deleteAll(); } @Override public List<TypeEquipement> getAll() { - - return ListUtils.emptyIfNull(typeEquipementRepository.findAll()) - .stream() - .map(typeEquipementEntity -> typeEquipementMapper.toDomaine(typeEquipementEntity)) - .toList(); + List<TypeItemEntity> typeItems = typeItemRepository.findByCategorie(CATEGORIE_EQUIPEMENT_PHYSIQUE); + return typeEquipementMapper.toTypeEquipements(typeItemMapper.toDomains(typeItems)); } } diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/TypeItemJpaAdapter.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/TypeItemJpaAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..a2216c7b134a6b5cd77e8b8d533cdacb26713dfb --- /dev/null +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/adapter/TypeItemJpaAdapter.java @@ -0,0 +1,57 @@ +package org.mte.numecoeval.referentiel.infrastructure.jpa.adapter; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.mte.numecoeval.referentiel.domain.exception.ReferentielException; +import org.mte.numecoeval.referentiel.domain.model.TypeItem; +import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort; +import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.TypeItemRepository; +import org.mte.numecoeval.referentiel.infrastructure.mapper.TypeItemMapper; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; + +@Service +@Slf4j +@AllArgsConstructor +public class TypeItemJpaAdapter implements ReferentielPersistencePort<TypeItem, String> { + + TypeItemMapper typeItemMapper; + TypeItemRepository typeItemRepository; + + @Override + public TypeItem save(TypeItem typeItem) throws ReferentielException { + typeItemRepository.save(typeItemMapper.toEntity(typeItem)); + return typeItem; + } + + @Override + public void saveAll(Collection<TypeItem> referentiels) throws ReferentielException { + if (referentiels == null) return; + + typeItemRepository.saveAll(referentiels.stream() + .map(TypeItem -> typeItemMapper.toEntity(TypeItem)) + .toList()); + } + + @Override + public TypeItem get(String id) throws ReferentielException { + return typeItemRepository.findById(id) + .map(typeItemEntity -> typeItemMapper.toDomain(typeItemEntity)) + .orElse(null); + } + + @Override + public void purge() { + typeItemRepository.deleteAll(); + } + + @Override + public List<TypeItem> getAll() { + return typeItemRepository.findAll() + .stream() + .map(TypeItemEntity -> typeItemMapper.toDomain(TypeItemEntity)) + .toList(); + } +} \ No newline at end of file diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/FacteurCaracterisationEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/FacteurCaracterisationEntity.java index 1f805bc5ab9a072b5fea46cfd617a69a7502190e..c679fa410b93ad92da1fa062e9f91d39982ecbfe 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/FacteurCaracterisationEntity.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/FacteurCaracterisationEntity.java @@ -21,14 +21,12 @@ public class FacteurCaracterisationEntity implements AbstractReferentielEntity { @Id String nom; @Id - @Column(name = "ETAPEACV") + @Column(name = "etapeacv") String etape; @Id - @Column(name = "NOMCRITERE") + @Column(name = "nomcritere") String critere; - String localisation; - String description; String niveau; String tiers; diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/HypotheseEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/HypotheseEntity.java index ab8fc01d6afe8d1ac715682ffe993053c9d076ac..265d148edfe67fb9b6c112bd15bd3572885191d0 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/HypotheseEntity.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/HypotheseEntity.java @@ -27,6 +27,7 @@ public class HypotheseEntity implements AbstractReferentielEntity { String code; String valeur; String source; + String description; @Override public boolean equals(Object o) { @@ -36,11 +37,11 @@ public class HypotheseEntity implements AbstractReferentielEntity { HypotheseEntity that = (HypotheseEntity) o; - return new EqualsBuilder().append(code, that.code).append(valeur, that.valeur).append(source, that.source).isEquals(); + return new EqualsBuilder().append(code, that.code).append(valeur, that.valeur).append(source, that.source).append(description, that.description).isEquals(); } @Override public int hashCode() { - return new HashCodeBuilder(17, 37).append(code).append(valeur).append(source).toHashCode(); + return new HashCodeBuilder(17, 37).append(code).append(valeur).append(source).append(description).toHashCode(); } } diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/TypeItemEntity.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/TypeItemEntity.java new file mode 100644 index 0000000000000000000000000000000000000000..81ab071772f31a659c2f5e809678807bd04354df --- /dev/null +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/entity/TypeItemEntity.java @@ -0,0 +1,45 @@ +package org.mte.numecoeval.referentiel.infrastructure.jpa.entity; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import lombok.*; +import lombok.experimental.Accessors; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; + +@Builder +@Getter +@Setter +@Accessors(chain = true) +@NoArgsConstructor +@AllArgsConstructor +@Entity(name = "REF_TYPE_ITEM") +public class TypeItemEntity implements AbstractReferentielEntity { + @Id + String type; + String categorie; + boolean serveur; + String commentaire; + Double dureeVieDefaut; + // ref de l'hypothèse nécesssaire pour le calcul de l'impact de cet l'item + String refHypothese; + String source; + // Référence de l'item par défaut, permet des correspondances en cas d'absence de correspondance directe. + String refItemParDefaut; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + + if (o == null || getClass() != o.getClass()) return false; + + TypeItemEntity that = (TypeItemEntity) o; + + return new EqualsBuilder().append(categorie, that.categorie).append(serveur, that.serveur).append(type, that.type).append(commentaire, that.commentaire).append(dureeVieDefaut, that.dureeVieDefaut).append(refHypothese, that.refHypothese).append(source, that.source).isEquals(); + } + + @Override + public int hashCode() { + return new HashCodeBuilder(17, 37).append(type).append(categorie).append(serveur).append(commentaire).append(dureeVieDefaut).append(refHypothese).append(source).toHashCode(); + } +} diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/FacteurCaracterisationRepository.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/FacteurCaracterisationRepository.java index bd6cb54385e58bf83a00474ea462766cb8a10ab0..da8d00f777b6391be92df8d6dbfcbd17164bf48f 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/FacteurCaracterisationRepository.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/FacteurCaracterisationRepository.java @@ -6,6 +6,7 @@ import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.FacteurCaracteri import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.id.FacteurCaracterisationIdEntity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; import org.springframework.data.rest.core.annotation.RepositoryRestResource; import java.util.List; @@ -27,7 +28,17 @@ public interface FacteurCaracterisationRepository extends JpaRepository<FacteurC @Modifying void deleteByNiveauAndTiers(String niveau, String tiers); - Optional<FacteurCaracterisationEntity> findByNiveauAndCategorieAndLocalisationAndCritere(String niveau, String categorie, String localisation, String critere); + @Query(""" + SELECT fc FROM #{#entityName} fc WHERE + ((?1 IS NULL) OR (?1 IS NOT NULL AND fc.critere = ?1)) AND + ((?2 IS NULL) OR (?2 IS NOT NULL AND fc.etape = ?2)) AND + ((?3 IS NULL) OR (?3 IS NOT NULL AND fc.nom = ?3)) AND + ((?4 IS NULL) OR (?4 IS NOT NULL AND fc.localisation = ?4)) AND + ((?5 IS NULL) OR (?5 IS NOT NULL AND fc.categorie = ?5)) + """) + List<FacteurCaracterisationEntity> findByCritereAndEtapeAndNomAndLocalisationAndCategorie(String nomcritere, String etape, String nom, String localisation, String categorie); + + List<FacteurCaracterisationEntity> findByNiveauAndCategorieAndLocalisationAndCritere(String niveau, String categorie, String localisation, String critere); Optional<FacteurCaracterisationEntity> findByNomAndEtapeAndCritere(String nom, String etape, String critere); diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/TypeItemRepository.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/TypeItemRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..f824bf685b2d8c6de84c01eed4f945e5f9bd3623 --- /dev/null +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/jpa/repository/TypeItemRepository.java @@ -0,0 +1,16 @@ +package org.mte.numecoeval.referentiel.infrastructure.jpa.repository; + +import io.swagger.v3.oas.annotations.tags.Tag; +import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.TypeItemEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.rest.core.annotation.RepositoryRestResource; + +import java.util.List; + +@RepositoryRestResource(path = "TypeItem", itemResourceRel = "TypesEquipements") +@Tag(name = "TypeItem - CRUD/Spring Data REST") +public interface TypeItemRepository extends JpaRepository<TypeItemEntity, String> { + + List<TypeItemEntity> findByCategorie(String categorie); + +} diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/FacteurCaracterisationMapper.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/FacteurCaracterisationMapper.java index 57baea0f12f5bd1e88a50d633f8bebca0afe2339..42df19c67a11f8140d857b6d83f57559277a2a3c 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/FacteurCaracterisationMapper.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/FacteurCaracterisationMapper.java @@ -30,4 +30,7 @@ public interface FacteurCaracterisationMapper { List<FacteurCaracterisation> toDomainsFromDTO(List<FacteurCaracterisationDTO> iesDTO); FacteurCaracterisationDTO toDTO(FacteurCaracterisation facteurCaracterisation); + + List<FacteurCaracterisationDTO> toDTOs(List<FacteurCaracterisation> facteurCaracterisations); + } diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/TypeEquipementMapper.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/TypeEquipementMapper.java index aef63367511cdd0991bc65ce28de9f84b2100c66..5af2f6ad6fd476fb60523d75e0020af5b34cc730 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/TypeEquipementMapper.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/TypeEquipementMapper.java @@ -1,9 +1,11 @@ package org.mte.numecoeval.referentiel.infrastructure.mapper; import org.mapstruct.Mapper; -import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeEquipementDTO; +import org.mapstruct.Mapping; import org.mte.numecoeval.referentiel.domain.model.TypeEquipement; +import org.mte.numecoeval.referentiel.domain.model.TypeItem; import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.TypeEquipementEntity; +import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeEquipementDTO; import java.util.Collection; import java.util.List; @@ -12,12 +14,27 @@ import java.util.List; public interface TypeEquipementMapper { TypeEquipement toDomaine(TypeEquipementEntity typeEquipementEntity); + + List<TypeEquipement> toDomaines(List<TypeEquipementEntity> typeEquipementEntities); + TypeEquipement toDomaine(TypeEquipementDTO typeEquipementDTO); TypeEquipementEntity toEntity(TypeEquipement typeEquipement); + List<TypeEquipementEntity> toEntities(Collection<TypeEquipement> typeEquipements); TypeEquipementDTO toDto(TypeEquipement typeEquipement); + @Mapping(target = "refItemParDefaut", source = "refEquipementParDefaut") + @Mapping(target = "categorie", expression = "java(org.mte.numecoeval.referentiel.utils.Constants.CATEGORIE_EQUIPEMENT_PHYSIQUE)") + TypeItem toTypeItem(TypeEquipement typeEquipement); + + List<TypeItem> toTypesItem(List<TypeEquipement> typesEquipement); + + @Mapping(target = "refEquipementParDefaut", source = "refItemParDefaut") + TypeEquipement toTypeEquipement(TypeItem typeItem); + + List<TypeEquipement> toTypeEquipements(List<TypeItem> typeItems); + } diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/TypeItemMapper.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/TypeItemMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..16e9ec80b96b31bf8ad23d3ad69d0d78322bc19b --- /dev/null +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/mapper/TypeItemMapper.java @@ -0,0 +1,27 @@ +package org.mte.numecoeval.referentiel.infrastructure.mapper; + +import org.mapstruct.Mapper; +import org.mte.numecoeval.referentiel.domain.model.TypeItem; +import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.TypeItemEntity; +import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeItemDTO; + +import java.util.Collection; +import java.util.List; + +@Mapper(componentModel = "spring") +public interface TypeItemMapper { + + TypeItem toDomain(TypeItemEntity TypeItemEntity); + + List<TypeItem> toDomains(List<TypeItemEntity> TypeItemEntities); + + TypeItem toDomain(TypeItemDTO TypeItemDTO); + + TypeItemEntity toEntity(TypeItem TypeItem); + + List<TypeItemEntity> toEntities(Collection<TypeItem> TypeItems); + + TypeItemDTO toDTO(TypeItem TypeItem); + + +} diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/facteurcaracterisation/ReferentielFacteurCaracterisationRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/facteurcaracterisation/ReferentielFacteurCaracterisationRestApi.java index 056cd35dcb397e3d4a76b3d8b267ca8219c773e3..b172e0c1e562640bb270631991b38d3369fa767c 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/facteurcaracterisation/ReferentielFacteurCaracterisationRestApi.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/facteurcaracterisation/ReferentielFacteurCaracterisationRestApi.java @@ -1,6 +1,7 @@ package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.facteurcaracterisation; import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; @@ -11,36 +12,44 @@ import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; +import java.util.List; + public interface ReferentielFacteurCaracterisationRestApi { - @Operation(summary = "Endpoint interne à NumEcoEval - Récupération d'un Facteur de Caractérisation", + @Operation(summary = "Endpoint interne à NumEcoEval - Récupération des Facteurs de Caractérisation", description = """ Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval. - Récupération d'un impact équipement en fonction de 3 paramètres: + Récupération des Facteurs de Caractérisation en fonction de 5 paramètres: <ul> - <li>Le nom du facteur de caractérisation: nom</li> - <li>L'étape ACV: etape</li> - <li>Le critère d'impact: critere</li> + <li>Le nom du critère d'impact écologique: critere</li> + <li>Le code de l'étape ACV: etapeacv</li> + <li>Le nom du facteur de caractérisation recherché: nom</li> + <li>La localisation: localisation</li> + <li>La catégorie: categorie</li> </ul> . """, tags = "Interne NumEcoEval", operationId = "getFacteurCaracterisation") @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Facteur Caractérisation trouvé", - content = {@Content(mediaType = "application/json", schema = @Schema(implementation = FacteurCaracterisationDTO.class))}), + @ApiResponse(responseCode = "200", description = "Liste des Facteurs de Caractérisation trouvés", + content = {@Content(mediaType = "application/json", array = @ArraySchema(schema = @Schema(implementation = FacteurCaracterisationDTO.class)))}), @ApiResponse(responseCode = "400", description = "Invalid request", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponseDTO.class))}), @ApiResponse(responseCode = "404", description = "Facteur Caractérisation non trouvé", content = {@Content(mediaType = "application/json", schema = @Schema(implementation = ErrorResponseDTO.class))})}) @GetMapping(path = "/referentiel/facteursCaracterisation", produces = MediaType.APPLICATION_JSON_VALUE) - FacteurCaracterisationDTO get( - @RequestParam - @Schema(description = "Nom du facteur de caractérisation recherché") final String nom, - @RequestParam + List<FacteurCaracterisationDTO> get( + @RequestParam(required = false) @Schema(description = "Nom du critère d'impact écologique") final String critere, - @RequestParam - @Schema(description = "Code de l'étape ACV") final String etapeacv + @RequestParam(required = false) + @Schema(description = "Code de l'étape ACV") final String etapeacv, + @RequestParam(required = false) + @Schema(description = "Nom du facteur de caractérisation recherché") final String nom, + @RequestParam(required = false) + @Schema(description = "Nom de la localisation") final String localisation, + @RequestParam(required = false) + @Schema(description = "Nom de la catégorie") final String categorie ); } diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/facteurcaracterisation/ReferentielFacteurCaracterisationRestApiImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/facteurcaracterisation/ReferentielFacteurCaracterisationRestApiImpl.java index c71b396f0fc4c3075f29dca64b267e439e84e223..6ae975f47cf38c6c25868b1027a94eac3fdfe38a 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/facteurcaracterisation/ReferentielFacteurCaracterisationRestApiImpl.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/facteurcaracterisation/ReferentielFacteurCaracterisationRestApiImpl.java @@ -4,7 +4,6 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.AllArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.mte.numecoeval.referentiel.domain.exception.ReferentielException; import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportFacteurCaracterisationPortImpl; import org.mte.numecoeval.referentiel.infrastructure.adapter.export.FacteurCaracterisationCsvExportService; @@ -12,7 +11,6 @@ import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.FacteurCaracteri import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.BaseExportReferentiel; import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.FacteurCaracterisationDTO; import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO; -import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.FacteurCaracterisationIdDTO; import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.FacteurCaracterisationFacade; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.RestController; @@ -20,6 +18,7 @@ import org.springframework.web.multipart.MultipartFile; import org.springframework.web.server.ResponseStatusException; import java.io.IOException; +import java.util.List; @RestController @Slf4j @@ -31,17 +30,12 @@ public class ReferentielFacteurCaracterisationRestApiImpl implements BaseExportR @SneakyThrows @Override - public FacteurCaracterisationDTO get(String nom, String critere, String etapeacv) { - - FacteurCaracterisationIdDTO id = FacteurCaracterisationIdDTO.builder() - .nom(StringUtils.trim(nom)) - .critere(critere) - .etape(etapeacv) - .build(); - - return referentielFacade.get(id); + public List<FacteurCaracterisationDTO> get(String critere, String etapeacv, String nom, String localisation, String categorie) { + String[] params = {critere, etapeacv, nom, localisation, categorie}; + return referentielFacade.getByFilters(params); } + @Override public RapportImportDTO importCSV(MultipartFile fichier, String mode) throws IOException, ReferentielException { if (fichier == null || fichier.isEmpty()) { @@ -66,6 +60,6 @@ public class ReferentielFacteurCaracterisationRestApiImpl implements BaseExportR @Override public void exportCSV(HttpServletResponse servletResponse) throws IOException { - exportCSV(servletResponse, csvExportService, "facteurCaracterisation"); + exportCSV(servletResponse, csvExportService, "facteursCaracterisation"); } } diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeequipement/ReferentielTypeEquipementRestApiImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeequipement/ReferentielTypeEquipementRestApiImpl.java index 13b16bec0eb738adf4b449529f099b8222ad21e1..2b49476f71aeb9efdf3e9a23e7f6326be658e251 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeequipement/ReferentielTypeEquipementRestApiImpl.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeequipement/ReferentielTypeEquipementRestApiImpl.java @@ -3,13 +3,13 @@ package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.typeequ import jakarta.servlet.http.HttpServletResponse; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeEquipementDTO; import org.mte.numecoeval.referentiel.domain.exception.ReferentielException; +import org.mte.numecoeval.referentiel.domain.model.TypeEquipement; import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportTypeEquipementPortImpl; import org.mte.numecoeval.referentiel.infrastructure.adapter.export.TypeEquipementCsvExportService; -import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.TypeEquipementEntity; import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.BaseExportReferentiel; import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO; +import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeEquipementDTO; import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.TypeEquipementFacade; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.RestController; @@ -22,11 +22,11 @@ import java.util.List; @RestController @Slf4j @AllArgsConstructor -public class ReferentielTypeEquipementRestApiImpl implements BaseExportReferentiel<TypeEquipementEntity>, ReferentielTypeEquipementRestApi, ReferentielAdministrationTypeEquipementRestApi { +public class ReferentielTypeEquipementRestApiImpl implements BaseExportReferentiel<TypeEquipement>, ReferentielTypeEquipementRestApi, ReferentielAdministrationTypeEquipementRestApi { - private TypeEquipementFacade typeEquipementFacade; + private TypeEquipementFacade typeEquipementFacade; - private TypeEquipementCsvExportService csvExportService; + private TypeEquipementCsvExportService csvExportService; @Override public RapportImportDTO importCSV(MultipartFile fichier) throws IOException, ReferentielException { diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeitem/ReferentielAdministrationTypeItemRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeitem/ReferentielAdministrationTypeItemRestApi.java new file mode 100644 index 0000000000000000000000000000000000000000..3c00bb6e5c7938e0d5389e03913fa49e5489e35a --- /dev/null +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeitem/ReferentielAdministrationTypeItemRestApi.java @@ -0,0 +1,57 @@ +package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.typeitem; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import jakarta.servlet.http.HttpServletResponse; +import org.mte.numecoeval.referentiel.domain.exception.ReferentielException; +import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO; +import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.multipart.MultipartFile; + +import java.io.IOException; + +public interface ReferentielAdministrationTypeItemRestApi { + + @Operation( + summary = "Alimentation du référentiel Type Item par csv : annule et remplace.", + description = """ + Le référentiel est global à tout le système. L’import se fait uniquement avec un fichier CSV. + Lors de l’import, les données précédentes sont supprimées. + <ul> + <li>Entrée : Le fichier CSV du référentiel</li> + <li>Sortie : Rapport du fichier CSV (nombre de lignes totales, nombre de lignes en erreur, nombre de lignes traitées, liste des erreurs par lignes).</li> + </ul> + """, + tags = {"Import Référentiels"}, + operationId = "importTypeItemCSV" + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Rapport d'import du fichier CSV"), + @ApiResponse(responseCode = "400", description = "Invalid request", + content = {@Content(mediaType = "application/json", + schema = @Schema(implementation = ErrorResponseDTO.class))})}) + @PostMapping(path = "/referentiel/typeItem/csv", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + RapportImportDTO importCSV(@RequestPart("file") MultipartFile file) throws IOException, ReferentielException; + + + @Operation( + summary = "Exporter les impacts des types d'items sous format csv", + description = """ + <ul> + <li>Entrée : Aucune </li> + <li>Sortie : Renvoie la liste des étapes de ref_TypeItem </li> + </ul> + """, + tags = {"Export Référentiels"}, + operationId = "exportTypeItemCSV" + ) + @GetMapping("/referentiel/typeItem/csv") + void exportCSV(HttpServletResponse servletResponse) throws IOException; +} diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeitem/ReferentielTypeItemRestApi.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeitem/ReferentielTypeItemRestApi.java new file mode 100644 index 0000000000000000000000000000000000000000..bbdab44b4a800753bf5d79e44f6bba42dc37d4b9 --- /dev/null +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeitem/ReferentielTypeItemRestApi.java @@ -0,0 +1,63 @@ +package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.typeitem; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.mte.numecoeval.referentiel.domain.exception.ReferentielException; +import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.ErrorResponseDTO; +import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeItemDTO; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; + +import java.util.List; + +public interface ReferentielTypeItemRestApi { + + @Operation( + summary = "Endpoint interne à NumEcoEval - Récupération de tous les types d'items", + description = """ + Endpoint interne utilisé à la réception de données d'entrées par le module api-expositiondonneesentrees de NumEcoEval. + Renvoie l'intégralité des types d'items utilisables par NumEcoEval. + + Les types d'items servent notamment à alimenter la durée de vie par défaut des items + reçues. + """, + tags = "Interne NumEcoEval", + operationId = "getAllTypeItem" + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Types Item", + content = {@Content(mediaType = "application/json", + array = @ArraySchema(schema = @Schema(implementation = TypeItemDTO.class)))}), + @ApiResponse(responseCode = "400", description = "Invalid request", + content = {@Content(mediaType = "application/json", + schema = @Schema(implementation = ErrorResponseDTO.class))}), + @ApiResponse(responseCode = "404", description = "Types Item non trouvé", content = {@Content(mediaType = "application/json", + schema = @Schema(implementation = ErrorResponseDTO.class))})}) + @GetMapping(path = "/referentiel/typesItem", produces = MediaType.APPLICATION_JSON_VALUE) + List<TypeItemDTO> getTypesItem(); + + @Operation( + summary = "Endpoint interne à NumEcoEval - Récupération d'items via leur type", + description = """ + Endpoint interne utilisé à la réception de données d'entrées par le module api-expositiondonneesentrees de NumEcoEval. Renvoie l'intégralité des types d'items d'un certain type. + """, + tags = "Interne NumEcoEval", + operationId = "getTypeItem" + ) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Types Item", + content = {@Content(mediaType = "application/json", + schema = @Schema(implementation = TypeItemDTO.class))}), + @ApiResponse(responseCode = "400", description = "Invalid request", + content = {@Content(mediaType = "application/json", + schema = @Schema(implementation = ErrorResponseDTO.class))}), + @ApiResponse(responseCode = "404", description = "Types Item non trouvé", content = {@Content(mediaType = "application/json", + schema = @Schema(implementation = ErrorResponseDTO.class))})}) + @GetMapping(path = "/referentiel/typesItem/{type}", produces = MediaType.APPLICATION_JSON_VALUE) + TypeItemDTO getTypeItem(@PathVariable @Schema(description = "type recherché") String type) throws ReferentielException; +} diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeitem/ReferentielTypeItemRestApiImpl.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeitem/ReferentielTypeItemRestApiImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..50fb8d329aa5667969c8ef8a451ce8ecbad58a4c --- /dev/null +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeitem/ReferentielTypeItemRestApiImpl.java @@ -0,0 +1,59 @@ +package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.typeitem; + +import jakarta.servlet.http.HttpServletResponse; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.mte.numecoeval.referentiel.domain.exception.ReferentielException; +import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportTypeItemPortImpl; +import org.mte.numecoeval.referentiel.infrastructure.adapter.export.TypeItemCsvExportService; +import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.TypeItemEntity; +import org.mte.numecoeval.referentiel.infrastructure.restapi.controller.BaseExportReferentiel; +import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.RapportImportDTO; +import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeItemDTO; +import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.TypeItemFacade; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.server.ResponseStatusException; + +import java.io.IOException; +import java.util.List; + +@RestController +@Slf4j +@AllArgsConstructor +public class ReferentielTypeItemRestApiImpl implements BaseExportReferentiel<TypeItemEntity>, ReferentielTypeItemRestApi, ReferentielAdministrationTypeItemRestApi { + + private TypeItemFacade TypeItemFacade; + + private TypeItemCsvExportService csvExportService; + + @Override + public RapportImportDTO importCSV(MultipartFile fichier) throws IOException, ReferentielException { + if (fichier == null || fichier.isEmpty()) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Le fichier n'existe pas ou alors il est vide"); + } + var rapportImport = new ImportTypeItemPortImpl().importCSV(fichier.getInputStream()); + TypeItemFacade.purgeAndAddAll(rapportImport.getObjects()); + return new RapportImportDTO( + fichier.getOriginalFilename(), + rapportImport.getErreurs(), + rapportImport.getNbrLignesImportees() + ); + } + + @Override + public TypeItemDTO getTypeItem(String type) throws ReferentielException { + return TypeItemFacade.getTypeItemForType(type); + } + + @Override + public List<TypeItemDTO> getTypesItem() { + return TypeItemFacade.getAllTypesItem(); + } + + @Override + public void exportCSV(HttpServletResponse servletResponse) throws IOException { + exportCSV(servletResponse, csvExportService, "typeItem"); + } +} diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/HypotheseDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/HypotheseDTO.java index cfb8931abfbb6657c620b5409683029929e8b8e2..4fae57c7ad424360bd98e68a1016680d7652168e 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/HypotheseDTO.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/HypotheseDTO.java @@ -30,4 +30,8 @@ public class HypotheseDTO implements Serializable { description = "Source de l'hypothèse" ) String source; + @Schema( + description = "Description de l'hypothèse" + ) + String description; } diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/TypeItemDTO.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/TypeItemDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..ddf50fe98d054369832457107c121025443033f4 --- /dev/null +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/dto/TypeItemDTO.java @@ -0,0 +1,54 @@ +package org.mte.numecoeval.referentiel.infrastructure.restapi.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; + +import java.io.Serializable; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Accessors(chain = true) +@FieldDefaults(level = AccessLevel.PRIVATE) +@EqualsAndHashCode +@Builder +@Schema( + description = "Référentiel des types d'items utilisables dans le système. La clé du référentiel est le champ type." +) +public class TypeItemDTO implements Serializable { + @Schema( + description = "Type d'item, clé du référentiel" + ) + String type; + @Schema( + description = "Catégorie de l'item" + ) + String categorie; + @Schema( + description = "Flag indiquant si l'item est un serveur" + ) + boolean serveur; + @Schema( + description = "Commentaire de l'entrée dans le référentiel" + ) + String commentaire; + @Schema( + description = "Durée de vie par défaut de ce type d'item" + ) + Double dureeVieDefaut; + @Schema( + description = "Référence vers l'hypothèse nécessaire pour le calcul d'impact de cet item" + ) + String refHypothese; + @Schema( + description = "Source de l'information du référentiel" + ) + String source; + @Schema( + description = "Référence de l'item par défaut, permet des correspondances en cas d'absence de correspondance directe" + ) + String refItemParDefaut; +} diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/FacteurCaracterisationFacade.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/FacteurCaracterisationFacade.java index f959e8c849da1dd0712d46da8cb0f8ce5effe2ba..f603f84ea3aa4c8bfe8c57fb8c9a98d194535fcf 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/FacteurCaracterisationFacade.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/FacteurCaracterisationFacade.java @@ -30,6 +30,11 @@ public class FacteurCaracterisationFacade { return mapper.toDTO(facteurCaracterisation); } + public List<FacteurCaracterisationDTO> getByFilters(String... params) throws ReferentielException { + List<FacteurCaracterisation> facteurCaracterisation = persistencePort.findByFilters(params[0], params[1], params[2], params[3], params[4]); + return mapper.toDTOs(facteurCaracterisation); + } + public void purgeAndAddAll(List<FacteurCaracterisationDTO> fcsDTO) throws ReferentielException { persistencePort.purge(); persistencePort.saveAll(mapper.toDomainsFromDTO(fcsDTO)); diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/TypeItemFacade.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/TypeItemFacade.java new file mode 100644 index 0000000000000000000000000000000000000000..b15e0ec8cd7c00c19783e87ce2d0258c05b3c2c0 --- /dev/null +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/TypeItemFacade.java @@ -0,0 +1,44 @@ +package org.mte.numecoeval.referentiel.infrastructure.restapi.facade; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.mte.numecoeval.referentiel.domain.exception.ReferentielException; +import org.mte.numecoeval.referentiel.domain.model.TypeItem; +import org.mte.numecoeval.referentiel.domain.ports.output.ReferentielPersistencePort; +import org.mte.numecoeval.referentiel.infrastructure.mapper.TypeItemMapper; +import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeItemDTO; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Slf4j +@AllArgsConstructor +public class TypeItemFacade { + + private ReferentielPersistencePort<TypeItem, String> persistencePort; + private TypeItemMapper mapper; + + public TypeItemDTO getTypeItemForType(String type) throws ReferentielException { + var TypeItem = persistencePort.get(type); + if (TypeItem != null) { + return mapper.toDTO(TypeItem); + } + return null; + } + + public List<TypeItemDTO> getAllTypesItem() { + return persistencePort.getAll().stream() + .map(TypeItem -> mapper.toDTO(TypeItem)) + .toList(); + } + + public void purgeAndAddAll(List<TypeItemDTO> types) throws ReferentielException { + if (types == null) return; + persistencePort.purge(); + persistencePort.saveAll(types.stream() + .map(TypeItemDTO -> mapper.toDomain(TypeItemDTO)) + .toList()); + } + +} diff --git a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/utils/Constants.java b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/utils/Constants.java index 27b7430f4e7a134e442d0c8d784d914db06572d7..15bc08bf29b9d2e364ede56ce5806202c93acac4 100644 --- a/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/utils/Constants.java +++ b/services/api-referentiel/src/main/java/org/mte/numecoeval/referentiel/utils/Constants.java @@ -9,5 +9,6 @@ public class Constants { public static final String MIXELEC_NOM_LOW_VOLTAGE = "Electricity Mix/ Production mix/ Low voltage/ "; public static final String RESEAU_NIVEAU = "3-System"; public static final String RESEAU_TIERS = "Network"; + public static final String CATEGORIE_EQUIPEMENT_PHYSIQUE = "EquipementPhysique"; } diff --git a/services/api-referentiel/src/main/resources/schema.sql b/services/api-referentiel/src/main/resources/schema.sql index e52a333a27706cac1ca02a000762765e8a1b25f2..1f910575e8599bc34ff0e3036a01cff8b0b4c2f7 100644 --- a/services/api-referentiel/src/main/resources/schema.sql +++ b/services/api-referentiel/src/main/resources/schema.sql @@ -18,6 +18,7 @@ CREATE TABLE IF NOT EXISTS ref_hypothese code varchar(255) NOT NULL, "source" varchar(255) NULL, valeur varchar(255) NULL, + description varchar(255) NULL, CONSTRAINT ref_hypothese_pkey PRIMARY KEY (code) ); @@ -32,6 +33,19 @@ CREATE TABLE IF NOT EXISTS ref_type_equipement CONSTRAINT ref_type_equipement_pkey PRIMARY KEY (type) ); +CREATE TABLE IF NOT EXISTS ref_type_item +( + "type" varchar(255) NOT NULL, + categorie varchar(255) NULL, + commentaire varchar(255) NULL, + duree_vie_defaut float8 NULL, + ref_conso_moyenne varchar(255) NULL, + serveur bool NOT NULL, + "source" varchar(255) NULL, + ref_item_par_defaut varchar(255) NULL, + CONSTRAINT ref_type_item_pkey PRIMARY KEY (type) +); + CREATE TABLE IF NOT EXISTS ref_impact_messagerie ( constante_coefficient_directeur float8 NULL, diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportTypeItemPortTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportTypeItemPortTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cf5bb6a02d7702e9fbbd37ac1bb9bf905c91d7ac --- /dev/null +++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/domain/port/input/ImportTypeItemPortTest.java @@ -0,0 +1,115 @@ +package org.mte.numecoeval.referentiel.domain.port.input; + +import org.junit.jupiter.api.Test; +import org.mte.numecoeval.referentiel.domain.ports.input.ImportCSVReferentielPort; +import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportTypeItemPortImpl; +import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeItemDTO; +import org.springframework.util.ResourceUtils; + +import java.io.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.*; + +class ImportTypeItemPortTest { + + ImportCSVReferentielPort<TypeItemDTO> importPortToTest = new ImportTypeItemPortImpl(); + + @Test + void importCSV_shouldImportAllDatas() throws Exception { + File file = ResourceUtils.getFile("classpath:csv/unit/typeItem.csv"); + var resultatImport = importPortToTest.importCSV(new FileInputStream(file)); + + assertEquals(2, resultatImport.getNbrLignesImportees()); + assertEquals(0, resultatImport.getErreurs().size()); + assertEquals(2, resultatImport.getObjects().size()); + assertTrue(resultatImport.getObjects().stream().anyMatch(typeItemDTO -> + "Serveur".equals(typeItemDTO.getType()) + && typeItemDTO.getCategorie().isEmpty() + && typeItemDTO.isServeur() + && "Exemple de serveur basique".equals(typeItemDTO.getCommentaire()) + && Double.valueOf(6.0).equals(typeItemDTO.getDureeVieDefaut()) + && "NegaOctet".equals(typeItemDTO.getSource()) + && "serveur_par_defaut".equals(typeItemDTO.getRefItemParDefaut()) + ) + ); + assertTrue(resultatImport.getObjects().stream().anyMatch(typeItemDTO -> + "deplacement voiture hybride".equals(typeItemDTO.getType()) + && "deplacement_hybride".equals(typeItemDTO.getCategorie()) + && !typeItemDTO.isServeur() + && "Exemple d'opération non it".equals(typeItemDTO.getCommentaire()) + && Double.valueOf(50.0).equals(typeItemDTO.getDureeVieDefaut()) + && "SSG".equals(typeItemDTO.getSource()) + && "deplacement_voiture_hybride".equals(typeItemDTO.getRefItemParDefaut()) + ) + ); + } + + @Test + void importCSV_whenErrorInMiddleOfFile_shouldImportDatasWithErrors() throws Exception { + File file = ResourceUtils.getFile("classpath:csv/unit/typeItem_errorInMiddle.csv"); + var resultatImport = importPortToTest.importCSV(new FileInputStream(file)); + + assertEquals(2, resultatImport.getNbrLignesImportees()); + assertEquals(1, resultatImport.getErreurs().size()); + assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°3 est invalide : La colonne type ne peut être vide"::equals)); + assertEquals(2, resultatImport.getObjects().size()); + assertTrue(resultatImport.getObjects().stream().anyMatch(typeItemDTO -> + "Serveur".equals(typeItemDTO.getType()) + && typeItemDTO.getCategorie().isEmpty() + && typeItemDTO.isServeur() + && "Exemple de serveur basique".equals(typeItemDTO.getCommentaire()) + && Double.valueOf(6.0).equals(typeItemDTO.getDureeVieDefaut()) + && "NegaOctet".equals(typeItemDTO.getSource()) + && "serveur_par_defaut".equals(typeItemDTO.getRefItemParDefaut()) + ) + ); + assertTrue(resultatImport.getObjects().stream().anyMatch(typeItemDTO -> + "deplacement voiture hybride".equals(typeItemDTO.getType()) + && "deplacement_hybride".equals(typeItemDTO.getCategorie()) + && !typeItemDTO.isServeur() + && "Exemple d'opération non it".equals(typeItemDTO.getCommentaire()) + && Double.valueOf(50.0).equals(typeItemDTO.getDureeVieDefaut()) + && "SSG".equals(typeItemDTO.getSource()) + && "deplacement_voiture_hybride".equals(typeItemDTO.getRefItemParDefaut()) + ) + ); + } + + @Test + void importCSV_whenWrongFile_shouldReturnOnlyErrors() throws Exception { + File file = ResourceUtils.getFile("classpath:csv/unit/wrongCSVFile.csv"); + var resultatImport = importPortToTest.importCSV(new FileInputStream(file)); + + assertEquals(0, resultatImport.getNbrLignesImportees()); + assertEquals(1, resultatImport.getErreurs().size()); + assertTrue(resultatImport.getErreurs().stream().anyMatch("La ligne n°2 est invalide : Entêtes incohérentes"::equals)); + } + + @Test + void importCSV_whenStreamAlreadyClosedShouldReturnReportWithOneError() throws IOException { + DataInputStream dataInputStream = mock(DataInputStream.class); + doNothing().when(dataInputStream).close(); + + var resultatImport = importPortToTest.importCSV(dataInputStream); + + verify(dataInputStream).close(); + assertEquals(0, resultatImport.getNbrLignesImportees()); + assertEquals(1, resultatImport.getErreurs().size()); + assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0)); + } + + @Test + void importCSV_whenFileNotFoundShouldReturnReportWithOneError() throws IOException { + DataInputStream dataInputStream = mock(DataInputStream.class); + doThrow(new FileNotFoundException("start Read csv etape")).when(dataInputStream).close(); + + var resultatImport = importPortToTest.importCSV(dataInputStream); + + verify(dataInputStream).close(); + assertEquals(0, resultatImport.getNbrLignesImportees()); + assertEquals(1, resultatImport.getErreurs().size()); + assertEquals("Le fichier CSV n'a pas pu être lu.", resultatImport.getErreurs().get(0)); + } +} diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/factory/TestDataFactory.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/factory/TestDataFactory.java index 53bc5801502b2dd52f92a827d92b0d8863318d12..6082c03d5e511d913efc700801eb8dbe79f3d593 100644 --- a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/factory/TestDataFactory.java +++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/factory/TestDataFactory.java @@ -82,22 +82,24 @@ public class TestDataFactory { } public static class HypotheseFactory { - public static HypotheseDTO dto(String code, String valeur, String source) { - return new HypotheseDTO(code, valeur, source); + public static HypotheseDTO dto(String code, String valeur, String source, String description) { + return new HypotheseDTO(code, valeur, source, description); } - public static Hypothese domain(String code, String valeur, String source) { + public static Hypothese domain(String code, String valeur, String source, String description) { return new Hypothese() .setCode(code) .setValeur(valeur) - .setSource(source); + .setSource(source) + .setDescription(description); } - public static HypotheseEntity entity(String code, String valeur, String source) { + public static HypotheseEntity entity(String code, String valeur, String source, String description) { return new HypotheseEntity() .setCode(code) .setValeur(valeur) - .setSource(source); + .setSource(source) + .setDescription(description); } public static HypotheseIdDTO idDTO(String code) { @@ -144,6 +146,38 @@ public class TestDataFactory { } } + public static class TypeItemFactory { + public static TypeItemDTO dto(String type, String categorie, boolean estUnServeur, String commentaire, Double dureeVieDefaut, String refHypothese, String source, String refItemParDefaut) { + return TypeItemDTO.builder() + .type(type) + .categorie(categorie) + .serveur(estUnServeur) + .dureeVieDefaut(dureeVieDefaut) + .refHypothese(refHypothese) + .source(source) + .commentaire(commentaire) + .refItemParDefaut(refItemParDefaut) + .build(); + } + + public static TypeItem domain(String type, String categorie, boolean estUnServeur, String commentaire, Double dureeVieDefaut, String refHypothese, String source, String refItemParDefaut) { + return TypeItem.builder() + .type(type) + .categorie(categorie) + .serveur(estUnServeur) + .dureeVieDefaut(dureeVieDefaut) + .refHypothese(refHypothese) + .source(source) + .commentaire(commentaire) + .refItemParDefaut(refItemParDefaut) + .build(); + } + + public static TypeItemEntity entity(String type, String categorie, boolean estUnServeur, String commentaire, Double dureeVieDefaut, String refHypothese, String source, String refItemParDefaut) { + return new TypeItemEntity(type, categorie, estUnServeur, commentaire, dureeVieDefaut, refHypothese, source, refItemParDefaut); + } + } + public static class MixElectriqueFactory { diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/HypotheseCsvExportServiceTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/HypotheseCsvExportServiceTest.java index 349805af1058ff0598b4d95fa389445a1240f5bc..0e8a555dd124edf043feb6d085b81da0056d5524 100644 --- a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/HypotheseCsvExportServiceTest.java +++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/HypotheseCsvExportServiceTest.java @@ -44,8 +44,8 @@ class HypotheseCsvExportServiceTest { @Test void getObjectsToWriteShouldReturnRepositoryFindAll() { var entities = List.of( - TestDataFactory.HypotheseFactory.entity("clé", "0.0","Source"), - TestDataFactory.HypotheseFactory.entity("clé2", "1.0","Source") + TestDataFactory.HypotheseFactory.entity("clé", "0.0", "Source", "exemple de description"), + TestDataFactory.HypotheseFactory.entity("clé2", "1.0", "Source", "exemple de description") ); when(repository.findAll()).thenReturn(entities); @@ -54,27 +54,27 @@ class HypotheseCsvExportServiceTest { @Test void printRecordShouldUseEntityAttributes() throws IOException { - var entity = TestDataFactory.HypotheseFactory.entity("clé", "0.0","Source"); + var entity = TestDataFactory.HypotheseFactory.entity("clé", "0.0", "Source", "exemple de description"); assertDoesNotThrow(() -> exportService.printRecord(csvPrinter, entity)); - Mockito.verify(csvPrinter, times(1)).printRecord(entity.getCode(), entity.getValeur(), entity.getSource()); + Mockito.verify(csvPrinter, times(1)).printRecord(entity.getCode(), entity.getValeur(), entity.getSource(), entity.getDescription()); } @Test - void logRecordErrorShouldLogSpecificErrorForRecord(){ - var entity = TestDataFactory.HypotheseFactory.entity("clé", "0.0","Source"); + void logRecordErrorShouldLogSpecificErrorForRecord() { + var entity = TestDataFactory.HypotheseFactory.entity("clé", "0.0", "Source", "exemple de description"); assertDoesNotThrow(() -> exportService.logRecordError(entity, new Exception("Test"))); } @Test - void logRecordErrorShouldLogGenericErrorForRecord(){ + void logRecordErrorShouldLogGenericErrorForRecord() { assertDoesNotThrow(() -> exportService.logRecordError(null, new Exception("Test"))); } @Test - void logRecordErrorShouldLogGenericErrorForFile(){ + void logRecordErrorShouldLogGenericErrorForFile() { assertDoesNotThrow(() -> exportService.logWriterError(new Exception("Test"))); } @@ -82,7 +82,7 @@ class HypotheseCsvExportServiceTest { void writeToCsvShouldReturnCSV() { // given var entities = List.of( - TestDataFactory.HypotheseFactory.entity("clé", "0.0","Source") + TestDataFactory.HypotheseFactory.entity("clé", "0.0", "Source", "exemple de description") ); when(repository.findAll()).thenReturn(entities); StringWriter stringWriter = new StringWriter(); @@ -93,7 +93,7 @@ class HypotheseCsvExportServiceTest { // Then String result = stringWriter.toString(); assertEquals( - "cle;valeur;source\r\nclé;0.0;Source\r\n", + "cle;valeur;source;description\r\nclé;0.0;Source;exemple de description\r\n", result ); } diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactMixElectriqueCsvExportServiceTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactMixElectriqueCsvExportServiceTest.java index f079cedeebc1378c6fdb59121a7c7b5d3967be4b..1553433eddd5e0e4bb4a87d672acd432f1d23386 100644 --- a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactMixElectriqueCsvExportServiceTest.java +++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/ImpactMixElectriqueCsvExportServiceTest.java @@ -83,7 +83,6 @@ class ImpactMixElectriqueCsvExportServiceTest { @Test void getObjectsToWriteShouldReturnRepositoryFindAll() { var entities = facteurCaracterisationEntities(); - when(repository.findByNiveauAndCategorie(Constants.MIXELEC_NIVEAU, Constants.MIXELEC_CATEGORIE)).thenReturn(entities); var actual = exportService.getObjectsToWrite(); assertEquals(2, actual.size()); diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeEquipementCsvExportServiceTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeEquipementCsvExportServiceTest.java index 2433525aad876db28bc19c054c014b44f0bd884a..47eb4fcf78699fc9510401759381b478cd9d5843 100644 --- a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeEquipementCsvExportServiceTest.java +++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeEquipementCsvExportServiceTest.java @@ -8,9 +8,17 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import org.mte.numecoeval.referentiel.domain.model.TypeEquipement; import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportTypeEquipementPortImpl; import org.mte.numecoeval.referentiel.factory.TestDataFactory; -import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.TypeEquipementRepository; +import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.TypeEquipementEntity; +import org.mte.numecoeval.referentiel.infrastructure.jpa.entity.TypeItemEntity; +import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.TypeItemRepository; +import org.mte.numecoeval.referentiel.infrastructure.mapper.TypeEquipementMapper; +import org.mte.numecoeval.referentiel.infrastructure.mapper.TypeEquipementMapperImpl; +import org.mte.numecoeval.referentiel.infrastructure.mapper.TypeItemMapper; +import org.mte.numecoeval.referentiel.infrastructure.mapper.TypeItemMapperImpl; +import org.springframework.test.util.ReflectionTestUtils; import java.io.IOException; import java.io.StringWriter; @@ -18,11 +26,13 @@ import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.util.List; import java.util.Locale; +import java.util.stream.Collectors; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.times; import static org.mockito.Mockito.when; +import static org.mte.numecoeval.referentiel.utils.Constants.CATEGORIE_EQUIPEMENT_PHYSIQUE; class TypeEquipementCsvExportServiceTest { @@ -30,7 +40,9 @@ class TypeEquipementCsvExportServiceTest { TypeEquipementCsvExportService exportService; @Mock - TypeEquipementRepository repository; + TypeItemRepository repository; + TypeItemMapper typeItemMapper = new TypeItemMapperImpl(); + TypeEquipementMapper typeEquipementMapper = new TypeEquipementMapperImpl(); @Mock CSVPrinter csvPrinter; @@ -38,6 +50,24 @@ class TypeEquipementCsvExportServiceTest { @BeforeEach void setup() { MockitoAnnotations.openMocks(this); + ReflectionTestUtils.setField(exportService, "typeItemMapper", typeItemMapper); + ReflectionTestUtils.setField(exportService, "typeEquipementMapper", typeEquipementMapper); + } + + private List<TypeItemEntity> typeItemEntities() { + return List.of( + TestDataFactory.TypeItemFactory.entity( + "Serveur", CATEGORIE_EQUIPEMENT_PHYSIQUE, true, null, 6.0, null, "", "Test"), + TestDataFactory.TypeItemFactory.entity( + "Communication Device", CATEGORIE_EQUIPEMENT_PHYSIQUE, false, "commentaires", 4.0, null, "SSG", + "refItem") + ); + } + + private TypeEquipementEntity typeEquipementEntity() { + return TestDataFactory.TypeEquipementFactory.entity( + "Serveur", true, 6.0, "Commentaires", "Test", + "test"); } @Test @@ -47,28 +77,20 @@ class TypeEquipementCsvExportServiceTest { @Test void getObjectsToWriteShouldReturnRepositoryFindAll() { - var entities = List.of( - TestDataFactory.TypeEquipementFactory.entity( - "Serveur", true, 6.0, "", "Test", - "test"), - TestDataFactory.TypeEquipementFactory.entity( - "Ecran", false, 4.0, "", "Test", - "test") - ); - when(repository.findAll()).thenReturn(entities); - - assertEquals(entities, exportService.getObjectsToWrite()); + List<TypeItemEntity> entities = typeItemEntities(); + when(repository.findByCategorie(CATEGORIE_EQUIPEMENT_PHYSIQUE)).thenReturn(entities); + var actual = exportService.getObjectsToWrite(); + assertEquals(2, actual.size()); + assertEquals("Communication Device,Serveur", actual.stream().map(TypeEquipement::getType).sorted().collect(Collectors.joining(","))); } @Test void printRecordShouldUseEntityAttributes() throws IOException { - var entity = TestDataFactory.TypeEquipementFactory.entity( - "Serveur", true, 6.0, "", "Test", - "test"); + var entity = typeEquipementEntity(); DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH)); df.setMaximumFractionDigits(340); - assertDoesNotThrow(() -> exportService.printRecord(csvPrinter, entity)); + assertDoesNotThrow(() -> exportService.printRecord(csvPrinter, typeEquipementMapper.toDomaine(entity))); Mockito.verify(csvPrinter, times(1)).printRecord( entity.getType(), @@ -81,11 +103,8 @@ class TypeEquipementCsvExportServiceTest { @Test void logRecordErrorShouldLogSpecificErrorForRecord() { - var entity = TestDataFactory.TypeEquipementFactory.entity( - "Serveur", true, 6.0, "", "Test", - "test"); - - assertDoesNotThrow(() -> exportService.logRecordError(entity, new Exception("Test"))); + var entity = typeEquipementEntity(); + assertDoesNotThrow(() -> exportService.logRecordError(typeEquipementMapper.toDomaine(entity), new Exception("Test"))); } @Test @@ -101,12 +120,8 @@ class TypeEquipementCsvExportServiceTest { @Test void writeToCsvShouldReturnCSV() { // given - var entities = List.of( - TestDataFactory.TypeEquipementFactory.entity( - "Serveur", true, 6.0, "Commentaires", "Test", - "test") - ); - when(repository.findAll()).thenReturn(entities); + var entities = typeItemEntities(); + when(repository.findByCategorie(CATEGORIE_EQUIPEMENT_PHYSIQUE)).thenReturn(entities); StringWriter stringWriter = new StringWriter(); // when @@ -115,8 +130,12 @@ class TypeEquipementCsvExportServiceTest { // Then String result = stringWriter.toString(); assertEquals( - "type;serveur;commentaire;dureeVieDefaut;source;refEquipementParDefaut\r\nServeur;true;Commentaires;6;Test;test\r\n", - result + """ + type;serveur;commentaire;dureeVieDefaut;source;refEquipementParDefaut + Serveur;true;;6;;Test + Communication Device;false;commentaires;4;SSG;refItem + """, + result.replaceAll("\r\n", "\n") ); } } diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeItemCsvExportServiceTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeItemCsvExportServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..1d800d1810b2c4c2e51bcb2e86775469ec32cac2 --- /dev/null +++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/adapter/export/TypeItemCsvExportServiceTest.java @@ -0,0 +1,128 @@ +package org.mte.numecoeval.referentiel.infrastructure.adapter.export; + +import org.apache.commons.csv.CSVPrinter; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mte.numecoeval.referentiel.domain.ports.input.impl.ImportTypeItemPortImpl; +import org.mte.numecoeval.referentiel.factory.TestDataFactory; +import org.mte.numecoeval.referentiel.infrastructure.jpa.repository.TypeItemRepository; + +import java.io.IOException; +import java.io.StringWriter; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.List; +import java.util.Locale; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.when; + +class TypeItemCsvExportServiceTest { + + @InjectMocks + TypeItemCsvExportService exportService; + + @Mock + TypeItemRepository repository; + + @Mock + CSVPrinter csvPrinter; + + @BeforeEach + void setup() { + MockitoAnnotations.openMocks(this); + } + + @Test + void getHeadersShouldReturnSameHeadersAsImport() { + Assertions.assertEquals(ImportTypeItemPortImpl.getHeaders(), exportService.getHeaders()); + } + + @Test + void getObjectsToWriteShouldReturnRepositoryFindAll() { + var entities = List.of( + TestDataFactory.TypeItemFactory.entity( + "Serveur", null, true, "Exemple de serveur basique", + 6.0, null, "NegaOctet", "serveur_par_defaut"), + TestDataFactory.TypeItemFactory.entity( + "deplacement voiture hybride", "deplacement_hybride", false, + "Exemple d'opération non it", 50.0, "CONSO_MOYENNE_VOITURE_HYBRIDE", "SSG", "deplacement_voiture_hybride" + ) + ); + when(repository.findAll()).thenReturn(entities); + + assertEquals(entities, exportService.getObjectsToWrite()); + } + + @Test + void printRecordShouldUseEntityAttributes() throws IOException { + var entity = TestDataFactory.TypeItemFactory.entity( + "Serveur", null, true, "Exemple de serveur basique", + 6.0, null, "NegaOctet", "serveur_par_defaut"); + DecimalFormat df = new DecimalFormat("0", DecimalFormatSymbols.getInstance(Locale.ENGLISH)); + df.setMaximumFractionDigits(340); + + assertDoesNotThrow(() -> exportService.printRecord(csvPrinter, entity)); + + Mockito.verify(csvPrinter, times(1)).printRecord( + entity.getType(), + entity.getCategorie(), + entity.isServeur(), + entity.getCommentaire(), + df.format(entity.getDureeVieDefaut()), + entity.getRefHypothese(), + entity.getSource(), + entity.getRefItemParDefaut()); + } + + @Test + void logRecordErrorShouldLogSpecificErrorForRecord() { + var entity = TestDataFactory.TypeItemFactory.entity( + "Serveur", null, true, "Exemple de serveur basique", + 6.0, null, "NegaOctet", "serveur_par_defaut"); + + assertDoesNotThrow(() -> exportService.logRecordError(entity, new Exception("Test"))); + } + + @Test + void logRecordErrorShouldLogGenericErrorForRecord() { + assertDoesNotThrow(() -> exportService.logRecordError(null, new Exception("Test"))); + } + + @Test + void logRecordErrorShouldLogGenericErrorForFile() { + assertDoesNotThrow(() -> exportService.logWriterError(new Exception("Test"))); + } + + @Test + void writeToCsvShouldReturnCSV() { + // given + var entities = List.of( + TestDataFactory.TypeItemFactory.entity( + "Serveur", null, true, "Exemple de serveur basique", + 6.0, null, "NegaOctet", "serveur_par_defaut") + ); + when(repository.findAll()).thenReturn(entities); + StringWriter stringWriter = new StringWriter(); + + // when + exportService.writeToCsv(stringWriter); + + // Then + String result = stringWriter.toString(); + assertEquals( + """ + type;categorie;serveur;commentaire;dureeVieDefaut;refHypothese;source;refItemParDefaut + Serveur;;true;Exemple de serveur basique;6;;NegaOctet;serveur_par_defaut + """, + result.replaceAll("\r\n", "\n") + ); + } +} diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/MixElectriqueJpaAdapterTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/MixElectriqueJpaAdapterTest.java index f06a4f596029bee7ae713c317a51124b5ecd20ad..e46ae4d4d11b97d6b83232ae29a60834774c43ec 100644 --- a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/MixElectriqueJpaAdapterTest.java +++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/jpa/MixElectriqueJpaAdapterTest.java @@ -23,7 +23,7 @@ import org.mte.numecoeval.referentiel.utils.Constants; import org.springframework.test.util.ReflectionTestUtils; import java.util.Collections; -import java.util.Optional; +import java.util.List; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; @@ -74,8 +74,7 @@ class MixElectriqueJpaAdapterTest { .setPays(PAYS) .setCritere(CRITERE); - Mockito.when(repository.findByNiveauAndCategorieAndLocalisationAndCritere(Constants.MIXELEC_NIVEAU, Constants.MIXELEC_CATEGORIE, wantedId.getPays(), wantedId.getCritere())).thenReturn(Optional.of(expectedEntity)); - + Mockito.when(repository.findByNiveauAndCategorieAndLocalisationAndCritere(Constants.MIXELEC_NIVEAU, Constants.MIXELEC_CATEGORIE, wantedId.getPays(), wantedId.getCritere())).thenReturn(List.of(expectedEntity)); var actualDomain = assertDoesNotThrow(() -> jpaAdapter.get(wantedId)); assertNotNull(actualDomain.getCritere()); @@ -89,7 +88,7 @@ class MixElectriqueJpaAdapterTest { var wantedId = new MixElectriqueId() .setPays("NonExistant") .setCritere("Inexistant"); - Mockito.when(repository.findByNiveauAndCategorieAndLocalisationAndCritere(Constants.MIXELEC_NIVEAU, Constants.MIXELEC_CATEGORIE, wantedId.getPays(), wantedId.getCritere())).thenReturn(Optional.empty()); + Mockito.when(repository.findByNiveauAndCategorieAndLocalisationAndCritere(Constants.MIXELEC_NIVEAU, Constants.MIXELEC_CATEGORIE, wantedId.getPays(), wantedId.getCritere())).thenReturn(Collections.emptyList()); ReferentielException expectedException = assertThrows(ReferentielException.class, () -> jpaAdapter.get(wantedId)); diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/facteurcaracterisation/ReferentielFacteurCaracterisationRestApiImplTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/facteurcaracterisation/ReferentielFacteurCaracterisationRestApiImplTest.java index 3a1fd17532c770010e4f10a5b9732abcb43041ff..8fd5ec7e0923d0e9f2f4a95bb9ca47ef7020c672 100644 --- a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/facteurcaracterisation/ReferentielFacteurCaracterisationRestApiImplTest.java +++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/facteurcaracterisation/ReferentielFacteurCaracterisationRestApiImplTest.java @@ -5,7 +5,6 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mte.numecoeval.referentiel.domain.exception.ReferentielException; import org.mte.numecoeval.referentiel.infrastructure.adapter.export.FacteurCaracterisationCsvExportService; import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.FacteurCaracterisationDTO; -import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.id.FacteurCaracterisationIdDTO; import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.FacteurCaracterisationFacade; import org.mte.numecoeval.referentiel.utils.Constants; import org.springframework.beans.factory.annotation.Autowired; @@ -20,6 +19,7 @@ import org.springframework.web.server.ResponseStatusException; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; +import java.util.List; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @@ -43,36 +43,31 @@ public class ReferentielFacteurCaracterisationRestApiImplTest { String nom = "Ordinateur Portable"; String nomCritere = "Changement Climatique"; String codeEtapeACV = "UTILISATION"; - var idDTO = new FacteurCaracterisationIdDTO(nom, - codeEtapeACV, - nomCritere - ); - var expectedDTO = FacteurCaracterisationDTO.builder() + + var fc = FacteurCaracterisationDTO.builder() .nom(nom) .etape(codeEtapeACV) .critere(nomCritere) .niveau(Constants.EQUIPEMENT_NIVEAU) .valeur(1.0).build(); - when(referentielFacade.get(idDTO)).thenReturn(expectedDTO); + var expectedDTO = List.of(fc); + when(referentielFacade.getByFilters(nomCritere, codeEtapeACV, nom, null, null)).thenReturn(expectedDTO); - var receivedDTO = referentielRestApi.get(nom, nomCritere, codeEtapeACV); - assertSame(receivedDTO, receivedDTO); - verify(referentielFacade).get(idDTO); + var actualDTO = referentielRestApi.get(nomCritere, codeEtapeACV, nom, null, null); + assertSame(expectedDTO, actualDTO); + verify(referentielFacade).getByFilters(nomCritere, codeEtapeACV, nom, null, null); } @Test void get_whenNotFound_thenShouldThrowReferentielException() throws ReferentielException { - String refEquipement = "Ordinateur Portable"; + String nom = "Ordinateur Portable"; String nomCritere = "Changement Climatique"; String codeEtapeACV = "UTILISATION"; - var idDTO = new FacteurCaracterisationIdDTO(refEquipement, - codeEtapeACV, - nomCritere - ); - when(referentielFacade.get(idDTO)).thenThrow(new ReferentielException("Impact Equipement non trouvé")); - var exception = assertThrows(ReferentielException.class, () -> referentielRestApi.get(refEquipement, nomCritere, codeEtapeACV)); + when(referentielFacade.getByFilters(nomCritere, codeEtapeACV, nom, null, null)).thenThrow(new ReferentielException("Impact Equipement non trouvé")); + + var exception = assertThrows(ReferentielException.class, () -> referentielRestApi.get(nomCritere, codeEtapeACV, nom, null, null)); assertEquals("Impact Equipement non trouvé", exception.getMessage()); } @@ -122,7 +117,7 @@ public class ReferentielFacteurCaracterisationRestApiImplTest { assertEquals("text/csv;charset=UTF-8", servletResponse.getContentType()); String headerContentDisposition = servletResponse.getHeader("Content-Disposition"); assertNotNull(headerContentDisposition); - assertTrue(headerContentDisposition.contains("attachment; filename=facteurCaracterisation-")); + assertTrue(headerContentDisposition.contains("attachment; filename=facteursCaracterisation-")); assertEquals(200, servletResponse.getStatus()); } diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeitem/ReferentielTypeItemRestApiImplTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeitem/ReferentielTypeItemRestApiImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..82f74fa2118fdf7dfba934ed9b30a58e8327ac55 --- /dev/null +++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/controller/typeitem/ReferentielTypeItemRestApiImplTest.java @@ -0,0 +1,115 @@ +package org.mte.numecoeval.referentiel.infrastructure.restapi.controller.typeitem; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mte.numecoeval.referentiel.domain.exception.ReferentielException; +import org.mte.numecoeval.referentiel.factory.TestDataFactory; +import org.mte.numecoeval.referentiel.infrastructure.adapter.export.TypeItemCsvExportService; +import org.mte.numecoeval.referentiel.infrastructure.restapi.dto.TypeItemDTO; +import org.mte.numecoeval.referentiel.infrastructure.restapi.facade.TypeItemFacade; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.HttpStatus; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.web.server.ResponseStatusException; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ContextConfiguration(classes = {ReferentielTypeItemRestApiImpl.class}) +@ExtendWith(SpringExtension.class) +class ReferentielTypeItemRestApiImplTest { + @Autowired + private ReferentielTypeItemRestApiImpl referentielRestApi; + + @MockBean + private TypeItemFacade referentielFacade; + + @MockBean + private TypeItemCsvExportService csvExportService; + + @Test + void getAll_shouldCallFacadeGetAllAndReturnAllDTOs() { + ArrayList<TypeItemDTO> typeItemDTOS = new ArrayList<>(); + when(referentielFacade.getAllTypesItem()).thenReturn(typeItemDTOS); + + List<TypeItemDTO> actualAll = referentielRestApi.getTypesItem(); + + assertSame(typeItemDTOS, actualAll); + assertTrue(actualAll.isEmpty()); + verify(referentielFacade).getAllTypesItem(); + } + + @Test + void getTypeItem_shouldCallFacadeGetAndReturnDTO() throws ReferentielException { + + String expectedType = "Serveur"; + TypeItemDTO expectedDTO = TestDataFactory.TypeItemFactory.dto(expectedType, null, true, "Exemple de serveur basique", + 6.0, null, "NegaOctet", "serveur_par_defaut"); + when(referentielFacade.getTypeItemForType(expectedType)).thenReturn(expectedDTO); + + TypeItemDTO actualResponse = referentielRestApi.getTypeItem(expectedType); + + assertSame(expectedDTO, actualResponse); + verify(referentielFacade).getTypeItemForType(expectedType); + } + + @Test + void importCSV_shouldCallPurgeAndAddAll() throws IOException, ReferentielException { + doNothing().when(referentielFacade).purgeAndAddAll(any()); + + referentielRestApi.importCSV(new MockMultipartFile("Name", "AAAAAAAA".getBytes(StandardCharsets.UTF_8))); + + verify(referentielFacade).purgeAndAddAll(any()); + } + + @Test + void importCSV_whenEmptyFileThenShouldThrowException() throws ReferentielException { + doNothing().when(referentielFacade).purgeAndAddAll(any()); + MockMultipartFile file = new MockMultipartFile("Name", (byte[]) null); + + ResponseStatusException responseStatusException = assertThrows( + ResponseStatusException.class, + () -> referentielRestApi.importCSV(file) + ); + + assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode()); + assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason()); + } + + @Test + void importCSV_whenNullFileThenShouldThrowException() throws ReferentielException { + doNothing().when(referentielFacade).purgeAndAddAll(any()); + + ResponseStatusException responseStatusException = assertThrows( + ResponseStatusException.class, + () -> referentielRestApi.importCSV(null) + ); + + assertEquals(HttpStatus.BAD_REQUEST, responseStatusException.getStatusCode()); + assertEquals("Le fichier n'existe pas ou alors il est vide", responseStatusException.getReason()); + } + + @Test + void exportCSV_shouldReturnCSVFile() { + var servletResponse = new MockHttpServletResponse(); + + assertDoesNotThrow(() -> referentielRestApi.exportCSV(servletResponse)); + + assertEquals("text/csv;charset=UTF-8", servletResponse.getContentType()); + String headerContentDisposition = servletResponse.getHeader("Content-Disposition"); + assertNotNull(headerContentDisposition); + assertTrue(headerContentDisposition.contains("attachment; filename=typeItem-")); + assertEquals(200, servletResponse.getStatus()); + + } +} diff --git a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/HypotheseFacadeTest.java b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/HypotheseFacadeTest.java index 8e40c311bcdb9ca408a4d61c9a58bf9747920e42..1fea959937cc93c35e017dee9c282e711c3a9a15 100644 --- a/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/HypotheseFacadeTest.java +++ b/services/api-referentiel/src/test/java/org/mte/numecoeval/referentiel/infrastructure/restapi/facade/HypotheseFacadeTest.java @@ -2,11 +2,7 @@ package org.mte.numecoeval.referentiel.infrastructure.restapi.facade; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; +import org.mockito.*; import org.mte.numecoeval.referentiel.domain.exception.ReferentielException; import org.mte.numecoeval.referentiel.domain.model.Hypothese; import org.mte.numecoeval.referentiel.domain.model.id.HypotheseId; @@ -41,7 +37,7 @@ class HypotheseFacadeTest { void get_shouldReturnMatchingDTO() throws ReferentielException { var wantedDTOId = TestDataFactory.HypotheseFactory.idDTO("code"); var expectedDomainID = TestDataFactory.HypotheseFactory.idDomain("code"); - var expectedDomain = TestDataFactory.HypotheseFactory.domain("code", "1.1", "Test"); + var expectedDomain = TestDataFactory.HypotheseFactory.domain("code", "1.1", "Test", "exemple de description"); Mockito.when(persistencePort.get(expectedDomainID)).thenReturn(expectedDomain); @@ -55,17 +51,17 @@ class HypotheseFacadeTest { @Test void getAll_ShouldAllReturnMatchingDTO() { var expectedDomains = Arrays.asList( - TestDataFactory.HypotheseFactory.domain("code", "2.0", "Test"), - TestDataFactory.HypotheseFactory.domain("code2", "3.0", "Test") + TestDataFactory.HypotheseFactory.domain("code", "2.0", "Test", "exemple de description"), + TestDataFactory.HypotheseFactory.domain("code2", "3.0", "Test", "exemple de description") ); Mockito.when(persistencePort.getAll()).thenReturn(expectedDomains); - var result = assertDoesNotThrow( () -> facadeToTest.getAll() ); + var result = assertDoesNotThrow(() -> facadeToTest.getAll()); assertEquals(expectedDomains.size(), result.size()); - expectedDomains.forEach( expectedDomain -> { + expectedDomains.forEach(expectedDomain -> { var matchingDTO = result.stream() .filter(critereDTO -> expectedDomain.getCode().equals(critereDTO.getCode())) .findAny(); @@ -82,8 +78,8 @@ class HypotheseFacadeTest { @Test void purgeAndAddAll_ShouldCallPurgeThenSaveAll() throws ReferentielException { var dtosToSave = Arrays.asList( - TestDataFactory.HypotheseFactory.dto("hyp", "1.0", "Test"), - TestDataFactory.HypotheseFactory.dto("hyp2", "m3", "Autre Test") + TestDataFactory.HypotheseFactory.dto("hyp", "1.0", "Test", "exemple de description"), + TestDataFactory.HypotheseFactory.dto("hyp2", "m3", "Autre Test", "exemple de description") ); ArgumentCaptor<Collection<Hypothese>> valueCapture = ArgumentCaptor.forClass(Collection.class); diff --git a/services/api-referentiel/src/test/resources/csv/unit/hypothese.csv b/services/api-referentiel/src/test/resources/csv/unit/hypothese.csv index a1a6b28614a66c174a8d3e58047a24c3dfa46a90..4093f137d0cbd94d4f21de122f35e37bd84bb5f0 100644 --- a/services/api-referentiel/src/test/resources/csv/unit/hypothese.csv +++ b/services/api-referentiel/src/test/resources/csv/unit/hypothese.csv @@ -1,3 +1,3 @@ -cle;valeur;source -PUEPardDfault;1.6;expertise IJO -DureeVieServeurParDefaut;3;US 46 +cle;valeur;source;description +PUEPardDfault;1.6;expertise IJO; +DureeVieServeurParDefaut;3;US 46;unité: années diff --git a/services/api-referentiel/src/test/resources/csv/unit/hypothese_errorInMiddle.csv b/services/api-referentiel/src/test/resources/csv/unit/hypothese_errorInMiddle.csv index 66f419ba89de4a72df7b2341bce92633b44f34dd..b4a98ebda2b87f76584eebc9133d1b207783c7df 100644 --- a/services/api-referentiel/src/test/resources/csv/unit/hypothese_errorInMiddle.csv +++ b/services/api-referentiel/src/test/resources/csv/unit/hypothese_errorInMiddle.csv @@ -1,5 +1,5 @@ -cle;valeur;source -PUEPardDfault;1.6;expertise IJO -;PasUnChiffreMaisPasGrave;Test;Pas;Le;Bon;Nombre;De;Colonne -ErreurValeur;;Test;Pas;Le;Bon;Nombre;De;Colonne -DureeVieServeurParDefaut;3;US 46 +cle;valeur;source;description +PUEPardDfault;1.6;expertise IJO; +;PasUnChiffreMaisPasGrave;Test;Pas;Le;Bon;Nombre;De;Colonne; +ErreurValeur;;Test;Pas;Le;Bon;Nombre;De;Colonne; +DureeVieServeurParDefaut;3;US 46;unité: années \ No newline at end of file diff --git a/services/api-referentiel/src/test/resources/csv/unit/typeItem.csv b/services/api-referentiel/src/test/resources/csv/unit/typeItem.csv new file mode 100644 index 0000000000000000000000000000000000000000..f96c37285188c75bee2e5495bc1b73b29f74dd2d --- /dev/null +++ b/services/api-referentiel/src/test/resources/csv/unit/typeItem.csv @@ -0,0 +1,3 @@ +type;categorie;serveur;commentaire;dureeVieDefaut;refHypothese;source;refItemParDefaut +Serveur;;true;Exemple de serveur basique;6.0;;NegaOctet;serveur_par_defaut +deplacement voiture hybride;deplacement_hybride;false;Exemple d'opération non it;50.0;CONSO_MOYENNE_VOITURE_HYBRIDE;SSG;deplacement_voiture_hybride diff --git a/services/api-referentiel/src/test/resources/csv/unit/typeItem_errorInMiddle.csv b/services/api-referentiel/src/test/resources/csv/unit/typeItem_errorInMiddle.csv new file mode 100644 index 0000000000000000000000000000000000000000..e690069c2d67ed3b32e6938bc0d31aadc1055458 --- /dev/null +++ b/services/api-referentiel/src/test/resources/csv/unit/typeItem_errorInMiddle.csv @@ -0,0 +1,4 @@ +type;categorie;serveur;commentaire;dureeVieDefaut;refHypothese;source;refItemParDefaut +Serveur;;true;Exemple de serveur basique;6.0;;NegaOctet;serveur_par_defaut +;;TypeAbsent;"est une erreur";complete;"Sur toute";"La";"Ligne"; +deplacement voiture hybride;deplacement_hybride;false;Exemple d'opération non it;50.0;CONSO_MOYENNE_VOITURE_HYBRIDE;SSG;deplacement_voiture_hybride \ No newline at end of file diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactOperationNonIT.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactOperationNonIT.java new file mode 100644 index 0000000000000000000000000000000000000000..746d364850e01523509e3406e671c0e21fde79c1 --- /dev/null +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/DemandeCalculImpactOperationNonIT.java @@ -0,0 +1,85 @@ +package org.mte.numecoeval.calculs.domain.data.demande; + +import lombok.*; +import org.mte.numecoeval.calculs.domain.data.entree.OperationNonIT; +import org.mte.numecoeval.calculs.domain.data.referentiel.*; +import org.mte.numecoeval.calculs.domain.utils.Constants; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import static org.mte.numecoeval.calculs.domain.utils.Constants.CATEGORIES_INDIRECT_FABRICATION; + +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class DemandeCalculImpactOperationNonIT { + + LocalDateTime dateCalcul; + + OperationNonIT operationNonIT; + + ReferentielEtapeACV etape; + + ReferentielCritere critere; + + ReferentielTypeItem typeItem; + + List<ReferentielHypothese> hypotheses; + + List<ReferentielFacteurCaracterisation> facteurCaracterisations; + + public Optional<ReferentielHypothese> getHypotheseFromCode(String code) { + if (code == null || hypotheses == null) { + return Optional.empty(); + } + + return hypotheses.stream() + .filter(hypothese -> code.equals(hypothese.getCode())) + .findFirst(); + } + + public Optional<ReferentielFacteurCaracterisation> getFacteurCaracterisation(String refItem) { + if (refItem == null || facteurCaracterisations == null) { + return Optional.empty(); + } + if (CATEGORIES_INDIRECT_FABRICATION.contains(typeItem.getCategorie())) { + return facteurCaracterisations.stream() + .filter(Objects::nonNull) + .filter(facteurCaracterisation -> refItem.equals(facteurCaracterisation.getNom()) + && critere.getNomCritere().equals(facteurCaracterisation.getCritere()) + && "FABRICATION".equals(facteurCaracterisation.getEtape()) + ) + .findFirst(); + } + return facteurCaracterisations.stream() + .filter(Objects::nonNull) + .filter(facteurCaracterisation -> refItem.equals(facteurCaracterisation.getNom()) + && critere.getNomCritere().equals(facteurCaracterisation.getCritere()) + && etape.getCode().equals(facteurCaracterisation.getEtape()) + ) + .findFirst(); + } + + public Optional<ReferentielFacteurCaracterisation> getMixElectriqueFromFacteurCaracterisation(String localisation) { + if (localisation == null || facteurCaracterisations == null) { + return Optional.empty(); + } + return facteurCaracterisations.stream() + .filter(Objects::nonNull) + .filter(fc -> Constants.ELECTRICITY_MIX_CATEGORY.equals(fc.getCategorie()) && + localisation.equals(fc.getLocalisation())) + .findFirst(); + } + + public String getRefItemParDefaut() { + if (typeItem != null) { + return typeItem.getRefItemParDefaut(); + } + return null; + } +} diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/MetadataCalcul.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/MetadataCalcul.java new file mode 100644 index 0000000000000000000000000000000000000000..db3d15aa9c969e3663c0ab0cd9d3cc8af6617047 --- /dev/null +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/demande/MetadataCalcul.java @@ -0,0 +1,7 @@ +package org.mte.numecoeval.calculs.domain.data.demande; + +import org.mte.numecoeval.calculs.domain.data.trace.TraceCalculImpactOperationNonIT; + +public record MetadataCalcul(double valeurImpactUnitaire, + TraceCalculImpactOperationNonIT traceCalculImpactOperationNonIT) { +} \ No newline at end of file diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/OperationNonIT.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/OperationNonIT.java new file mode 100644 index 0000000000000000000000000000000000000000..c20ed65c7c4c5adcb535138cf08d90aea5eef32b --- /dev/null +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/entree/OperationNonIT.java @@ -0,0 +1,28 @@ +package org.mte.numecoeval.calculs.domain.data.entree; + +import lombok.*; + +import java.time.LocalDate; + +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class OperationNonIT { + private String nomItemNonIT; + private Double quantite; + private String type; + private Double dureeDeVie; + private String localisation; + private String nomEntite; + private String nomCourtDatacenter; + private String description; + private Double consoElecAnnuelle; + private String nomLot; + private LocalDate dateLot; + private String nomOrganisation; + private String nomSourceDonnee; + private String statut; + +} diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactOperationNonIT.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactOperationNonIT.java new file mode 100644 index 0000000000000000000000000000000000000000..deb3ee080d5b21ec3de3e1d69172114f7c974fe5 --- /dev/null +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/indicateurs/ImpactOperationNonIT.java @@ -0,0 +1,35 @@ +package org.mte.numecoeval.calculs.domain.data.indicateurs; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Builder +@AllArgsConstructor +@Getter +@Setter +public class ImpactOperationNonIT { + LocalDateTime dateCalcul; + String versionCalcul; + String etapeACV; + String critere; + String source; + String statutIndicateur; + String trace; + String nomLot; + LocalDate dateLot; + String unite; + String nomOrganisation; + String nomEntite; + String nomSourceDonnee; + String reference; + String nomItemNonIT; + String typeItem; + Double impactUnitaire; + Double consoElecMoyenne; + Double quantite; +} diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielCritere.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielCritere.java index 20969e5659b259d9119c2fed8f7fd541e5e33ed5..770b1a7e40583de558f6a3d54c33b7a2c6df5ee8 100644 --- a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielCritere.java +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielCritere.java @@ -1,10 +1,12 @@ package org.mte.numecoeval.calculs.domain.data.referentiel; -import lombok.Builder; -import lombok.Data; +import lombok.*; @Builder -@Data +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter public class ReferentielCritere { String nomCritere; String unite; diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielEtapeACV.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielEtapeACV.java index 9e42c59578ccf75c0eb96b00407d831a63608f38..bd09a0cb89ac95c0a2c2e6acc944fa3bb4db6b40 100644 --- a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielEtapeACV.java +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielEtapeACV.java @@ -1,12 +1,13 @@ package org.mte.numecoeval.calculs.domain.data.referentiel; -import lombok.Builder; -import lombok.Data; +import lombok.*; @Builder -@Data +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter public class ReferentielEtapeACV { String code; String libelle; - } diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielFacteurCaracterisation.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielFacteurCaracterisation.java new file mode 100644 index 0000000000000000000000000000000000000000..8eaddbf9551318081e78c3b676a413fa6c21de10 --- /dev/null +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielFacteurCaracterisation.java @@ -0,0 +1,23 @@ +package org.mte.numecoeval.calculs.domain.data.referentiel; + +import lombok.*; + +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class ReferentielFacteurCaracterisation { + String nom; + String etape; + String critere; + String description; + String niveau; + String tiers; + String categorie; + Double consoElecMoyenne; + String localisation; + Double valeur; + String unite; + String source; +} diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielHypothese.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielHypothese.java index 351db7d66d9947e2ac313724bf41f43e823a7507..916a02728c277971731c0111033f7e0532c0bbd1 100644 --- a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielHypothese.java +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielHypothese.java @@ -1,11 +1,13 @@ package org.mte.numecoeval.calculs.domain.data.referentiel; -import lombok.Builder; -import lombok.Data; +import lombok.*; -@Data @Builder +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter public class ReferentielHypothese { private String code; diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielTypeItem.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielTypeItem.java new file mode 100644 index 0000000000000000000000000000000000000000..88b6e4d013dc0876eeb1cb7bdf5fab8c248da1cd --- /dev/null +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/referentiel/ReferentielTypeItem.java @@ -0,0 +1,26 @@ +package org.mte.numecoeval.calculs.domain.data.referentiel; + +import lombok.*; + +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class ReferentielTypeItem { + String type; + + String categorie; + + Boolean serveur; + + String commentaire; + + Double dureeVieDefaut; + + String refHypothese; + + String refItemParDefaut; + + String source; +} diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/ConsoElecAnMoyenne.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/ConsoElecAnMoyenne.java index fc99e3b335011d4d6505df09d9031f0884f2ee23..de0d6c5f0d0a89d4cd33288fd127b4195afe8795 100644 --- a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/ConsoElecAnMoyenne.java +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/ConsoElecAnMoyenne.java @@ -9,7 +9,7 @@ import lombok.Data; @JsonInclude(JsonInclude.Include.NON_NULL) public class ConsoElecAnMoyenne { private Double valeur; - private Double valeurEquipementConsoElecAnnuelle; + private Double valeurItemConsoElecAnnuelle; private Double valeurReferentielConsoElecMoyenne; - private String sourceReferentielImpactEquipement; + private String sourceReferentielFacteurCaracterisation; } diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/DureeDeVieParDefaut.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/DureeDeVieParDefaut.java index bb046fc9dabf3a04fd721242479f381e525fe352..ca182aaed29a27b5bd0ab88c1988c511605294ac 100644 --- a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/DureeDeVieParDefaut.java +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/DureeDeVieParDefaut.java @@ -8,8 +8,9 @@ import lombok.Data; @Builder @JsonInclude(JsonInclude.Include.NON_NULL) public class DureeDeVieParDefaut { - private Double valeur; - private Double valeurEquipementDureeVieDefaut; + private Double valeur; + private Double valeurTypeItemDureeVieDefaut; + private String sourceTypeItemDureeVieDefaut; private Double valeurReferentielHypothese; private String sourceReferentielHypothese; } diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/Hypothese.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/Hypothese.java new file mode 100644 index 0000000000000000000000000000000000000000..076f2b762f63650a93b49c7095210525445af646 --- /dev/null +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/Hypothese.java @@ -0,0 +1,14 @@ +package org.mte.numecoeval.calculs.domain.data.trace; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Builder; +import lombok.Data; + +@Builder +@Data +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Hypothese { + private Double valeur; + private String nom_hypothese; + private String source; +} diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/MixElectrique.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/MixElectrique.java index 5f6e0e459f790242b1391067eae37902067ac2a8..41b191a874687a129ac47d9a939d1f95dad34413 100644 --- a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/MixElectrique.java +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/MixElectrique.java @@ -13,4 +13,5 @@ public class MixElectrique { private Double dataCenterPue; private Double valeurReferentielMixElectrique; private String sourceReferentielMixElectrique; + } diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactOperationNonIT.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactOperationNonIT.java new file mode 100644 index 0000000000000000000000000000000000000000..116a74ad77cbcd8de9216e132ae8e2c35d7b82c0 --- /dev/null +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/data/trace/TraceCalculImpactOperationNonIT.java @@ -0,0 +1,19 @@ +package org.mte.numecoeval.calculs.domain.data.trace; + +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +@JsonInclude(JsonInclude.Include.NON_NULL) +public class TraceCalculImpactOperationNonIT { + private String formule; + private ConsoElecAnMoyenne consoElecAnMoyenne; + private MixElectrique mixElectrique; + private Double valeurReferentielFacteurCaracterisation; + private String sourceReferentielFacteurCaracterisation; + private Hypothese hypothese; + private DureeDeVie dureeDeVie; + private String erreur; +} diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactOperationNonITService.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactOperationNonITService.java new file mode 100644 index 0000000000000000000000000000000000000000..41024a3465b453ab5607b4b044f7e45ebb507052 --- /dev/null +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/CalculImpactOperationNonITService.java @@ -0,0 +1,10 @@ +package org.mte.numecoeval.calculs.domain.port.input.service; + +import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactOperationNonIT; +import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactOperationNonIT; + +public interface CalculImpactOperationNonITService { + + ImpactOperationNonIT calculerImpactOperationNonIT(DemandeCalculImpactOperationNonIT demandeCalcul); + +} diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactApplicationServiceImpl.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactApplicationServiceImpl.java index d2ff97428a7bbf4f85bfd9f5686905a611ce8f43..a73c527175f2acc7f1cd6b5822c43de61718fef4 100644 --- a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactApplicationServiceImpl.java +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactApplicationServiceImpl.java @@ -1,6 +1,5 @@ package org.mte.numecoeval.calculs.domain.port.input.service.impl; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactApplication; @@ -18,8 +17,6 @@ public class CalculImpactApplicationServiceImpl implements CalculImpactApplicati private static final String VERSION_CALCUL = "1.1"; - private ObjectMapper objectMapper; - @Override public ImpactApplication calculImpactApplicatif(DemandeCalculImpactApplication demandeCalcul) { ImpactApplication impactErreur; @@ -60,7 +57,7 @@ public class CalculImpactApplicationServiceImpl implements CalculImpactApplicati .etapeACV(demandeCalcul.getImpactEquipementVirtuel().getEtapeACV()) .critere(demandeCalcul.getImpactEquipementVirtuel().getCritere()) .statutIndicateur("ERREUR") - .trace(TraceUtils.getTraceFromTraceur(objectMapper, TraceCalculImpactVirtuelUtils.buildTraceErreur(exception))) + .trace(TraceUtils.getTraceFromTraceur(TraceCalculImpactVirtuelUtils.buildTraceErreur(exception))) .nomLot(demandeCalcul.getApplication().getNomLot()) .nomSourceDonnee(demandeCalcul.getApplication().getNomSourceDonnee()) .dateLot(demandeCalcul.getApplication().getDateLot()) @@ -117,7 +114,7 @@ public class CalculImpactApplicationServiceImpl implements CalculImpactApplicati .dateLot(demandeCalcul.getApplication().getDateLot()) .versionCalcul(VERSION_CALCUL) .statutIndicateur("OK") - .trace(TraceUtils.getTraceFromTraceur(objectMapper, TraceCalculImpactApplicationUtils.buildTrace(demandeCalcul))) + .trace(TraceUtils.getTraceFromTraceur(TraceCalculImpactApplicationUtils.buildTrace(demandeCalcul))) .impactUnitaire(resultCalcul.valeurImpact) .consoElecMoyenne(resultCalcul.consoElecMoyenne) .build(); diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactEquipementPhysiqueServiceImpl.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactEquipementPhysiqueServiceImpl.java index 3dcdfe0a167e67091853e653241ba500a778fd71..91a7cd60107013f636467f53afe8246575e197d0 100644 --- a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactEquipementPhysiqueServiceImpl.java +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactEquipementPhysiqueServiceImpl.java @@ -1,6 +1,5 @@ package org.mte.numecoeval.calculs.domain.port.input.service.impl; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -30,8 +29,6 @@ public class CalculImpactEquipementPhysiqueServiceImpl implements CalculImpactEq public static final String ERREUR_DE_CALCUL_IMPACT_EQUIPEMENT_MESSAGE = "Erreur de calcul impact équipement: Type: {}, Cause: {}, Etape: {}, Critere: {}, Equipement Physique: {}, RefEquipementRetenu: {}, RefEquipementParDefaut: {}"; private final DureeDeVieEquipementPhysiqueService dureeDeVieEquipementPhysiqueService; - private final ObjectMapper objectMapper; - public ImpactEquipementPhysique calculerImpactEquipementPhysique(DemandeCalculImpactEquipementPhysique demandeCalcul) { log.debug("Début de calcul d'impact d'équipement physique : {}, {}, {} ", @@ -94,7 +91,7 @@ public class CalculImpactEquipementPhysiqueServiceImpl implements CalculImpactEq } var calcul = buildCalculImpactEquipementPhysique(demandeCalcul, valeurImpactUnitaire, consoElecMoyenne); - calcul.setTrace(TraceUtils.getTraceFromTraceur(objectMapper, traceCalculImpactEquipementPhysique)); + calcul.setTrace(TraceUtils.getTraceFromTraceur(traceCalculImpactEquipementPhysique)); return calcul; } @@ -159,7 +156,7 @@ public class CalculImpactEquipementPhysiqueServiceImpl implements CalculImpactEq .dateLot(demandeCalcul.getEquipementPhysique().getDateLot()) .nomEntite(demandeCalcul.getEquipementPhysique().getNomEntite()) .nomOrganisation(demandeCalcul.getEquipementPhysique().getNomOrganisation()) - .trace(TraceUtils.getTraceFromTraceur(objectMapper, TraceCalculImpactEquipementPhysiqueUtils.buildTraceErreur(exception))) + .trace(TraceUtils.getTraceFromTraceur(TraceCalculImpactEquipementPhysiqueUtils.buildTraceErreur(exception))) .build(); } @@ -167,7 +164,7 @@ public class CalculImpactEquipementPhysiqueServiceImpl implements CalculImpactEq if (demandeCalcul.getEquipementPhysique().getConsoElecAnnuelle() != null) { var valeur = demandeCalcul.getEquipementPhysique().getConsoElecAnnuelle(); return ConsoElecAnMoyenne.builder() - .valeurEquipementConsoElecAnnuelle(valeur) + .valeurItemConsoElecAnnuelle(valeur) .valeur(valeur) .build(); } @@ -192,7 +189,7 @@ public class CalculImpactEquipementPhysiqueServiceImpl implements CalculImpactEq var valeur = referentielImpactEquipementOpt.get().getConsoElecMoyenne(); return ConsoElecAnMoyenne.builder() - .sourceReferentielImpactEquipement(referentielImpactEquipementOpt.get().getSource()) + .sourceReferentielFacteurCaracterisation(referentielImpactEquipementOpt.get().getSource()) .valeurReferentielConsoElecMoyenne(valeur) .valeur(valeur) .build(); @@ -301,3 +298,4 @@ public class CalculImpactEquipementPhysiqueServiceImpl implements CalculImpactEq } } } + diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactEquipementVirtuelServiceImpl.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactEquipementVirtuelServiceImpl.java index ef137c98ed35cecf4b70a9bd130065e6026c36b2..f06f606d3deeb693e776401e1300f7bfd34b136c 100644 --- a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactEquipementVirtuelServiceImpl.java +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactEquipementVirtuelServiceImpl.java @@ -1,6 +1,5 @@ package org.mte.numecoeval.calculs.domain.port.input.service.impl; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementVirtuel; @@ -19,7 +18,6 @@ public class CalculImpactEquipementVirtuelServiceImpl implements CalculImpactEqu private static final String VERSION_CALCUL = "1.1"; public static final String TYPE_EQUIPEMENT_VIRTUEL_STOCKAGE = "stockage"; public static final String TYPE_EQUIPEMENT_VIRTUEL_CALCUL = "calcul"; - private final ObjectMapper objectMapper; @Override public ImpactEquipementVirtuel calculerImpactEquipementVirtuel(DemandeCalculImpactEquipementVirtuel demandeCalcul) { @@ -76,7 +74,7 @@ public class CalculImpactEquipementVirtuelServiceImpl implements CalculImpactEqu .critere(demandeCalcul.getImpactEquipement().getCritere()) .unite(demandeCalcul.getImpactEquipement().getUnite()) .statutIndicateur("OK") - .trace(TraceUtils.getTraceFromTraceur(objectMapper, trace)) + .trace(TraceUtils.getTraceFromTraceur(trace)) .nomLot(demandeCalcul.getEquipementVirtuel().getNomLot()) .nomSourceDonnee(demandeCalcul.getEquipementVirtuel().getNomSourceDonnee()) .dateLot(demandeCalcul.getEquipementVirtuel().getDateLot()) @@ -99,7 +97,7 @@ public class CalculImpactEquipementVirtuelServiceImpl implements CalculImpactEqu .critere(demandeCalcul.getImpactEquipement().getCritere()) .unite(demandeCalcul.getImpactEquipement().getUnite()) .statutIndicateur("ERREUR") - .trace(TraceUtils.getTraceFromTraceur(objectMapper, TraceCalculImpactVirtuelUtils.buildTraceErreur(exception))) + .trace(TraceUtils.getTraceFromTraceur(TraceCalculImpactVirtuelUtils.buildTraceErreur(exception))) .nomLot(demandeCalcul.getEquipementVirtuel().getNomLot()) .nomSourceDonnee(demandeCalcul.getEquipementVirtuel().getNomSourceDonnee()) .dateLot(demandeCalcul.getEquipementVirtuel().getDateLot()) diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactMessagerieServiceImpl.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactMessagerieServiceImpl.java index 35fa91dac13a1198ce21ddfa4feba080f2fa5cdb..ac74311c1601f5c6461e10d880d17eadd842e71c 100644 --- a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactMessagerieServiceImpl.java +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactMessagerieServiceImpl.java @@ -1,6 +1,5 @@ package org.mte.numecoeval.calculs.domain.port.input.service.impl; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactMessagerie; @@ -16,7 +15,6 @@ import org.mte.numecoeval.calculs.domain.traceur.TraceUtils; @AllArgsConstructor public class CalculImpactMessagerieServiceImpl implements CalculImpactMessagerieService { private static final String VERSION_CALCUL = "1.0"; - private final ObjectMapper objectMapper; @Override public ImpactMessagerie calculerImpactMessagerie(DemandeCalculImpactMessagerie demandeCalcul) { @@ -79,7 +77,7 @@ public class CalculImpactMessagerieServiceImpl implements CalculImpactMessagerie .nomEntite(demandeCalcul.getMessagerie().getNomEntite()) .nomOrganisation(demandeCalcul.getMessagerie().getNomOrganisation()) .versionCalcul(VERSION_CALCUL) - .trace(TraceUtils.getTraceFromTraceur(objectMapper, TraceCalculImpactMessagerieUtils.buildTrace(demandeCalcul, referentielImpactMessagerie))) + .trace(TraceUtils.getTraceFromTraceur(TraceCalculImpactMessagerieUtils.buildTrace(demandeCalcul, referentielImpactMessagerie))) .build(); } @@ -99,7 +97,7 @@ public class CalculImpactMessagerieServiceImpl implements CalculImpactMessagerie .nomEntite(demandeCalcul.getMessagerie().getNomEntite()) .nomOrganisation(demandeCalcul.getMessagerie().getNomOrganisation()) .versionCalcul(VERSION_CALCUL) - .trace(TraceUtils.getTraceFromTraceur(objectMapper, TraceCalculImpactMessagerieUtils.buildTraceError(exception))) + .trace(TraceUtils.getTraceFromTraceur(TraceCalculImpactMessagerieUtils.buildTraceError(exception))) .build(); } diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactOperationNonITServiceImpl.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactOperationNonITServiceImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..2b4449e2971761ba968900d4aaf68e0f8f0835a7 --- /dev/null +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactOperationNonITServiceImpl.java @@ -0,0 +1,350 @@ +package org.mte.numecoeval.calculs.domain.port.input.service.impl; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactOperationNonIT; +import org.mte.numecoeval.calculs.domain.data.demande.MetadataCalcul; +import org.mte.numecoeval.calculs.domain.data.erreur.TypeErreurCalcul; +import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactOperationNonIT; +import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielFacteurCaracterisation; +import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielHypothese; +import org.mte.numecoeval.calculs.domain.data.trace.*; +import org.mte.numecoeval.calculs.domain.exception.CalculImpactException; +import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactOperationNonITService; +import org.mte.numecoeval.calculs.domain.traceur.TraceCalculImpactOperationNonITUtils; +import org.mte.numecoeval.calculs.domain.traceur.TraceUtils; + +import java.util.Optional; + +import static org.mte.numecoeval.calculs.domain.traceur.TraceCalculImpactOperationNonITUtils.*; +import static org.mte.numecoeval.calculs.domain.utils.Constants.*; + +@Slf4j +@AllArgsConstructor +public class CalculImpactOperationNonITServiceImpl implements CalculImpactOperationNonITService { + private static final String VERSION_CALCUL = "1.0"; + + public ImpactOperationNonIT calculerImpactOperationNonIT(DemandeCalculImpactOperationNonIT demandeCalcul) { + log.debug("Début de calcul d'impact d'un item non it : {}, {}, {} ", + demandeCalcul.getEtape().getCode(), + demandeCalcul.getCritere().getNomCritere(), + demandeCalcul.getOperationNonIT().getNomItemNonIT()); + ImpactOperationNonIT impactErreur = null; + + try { + return getCalculImpactOperationNonIT(demandeCalcul); + } catch (CalculImpactException e) { + log.debug("Erreur de calcul impact item: Type: {}, Cause: {}, Etape: {}, Critere: {}, Item Physique: {}, RefItemRetenu: {}, RefItemParDefaut: {}", + e.getErrorType(), + e.getMessage(), + demandeCalcul.getEtape().getCode(), + demandeCalcul.getCritere().getNomCritere(), + demandeCalcul.getOperationNonIT().getNomItemNonIT(), + demandeCalcul.getTypeItem().getType(), + demandeCalcul.getRefItemParDefaut()); + impactErreur = buildCalculImpactForError(demandeCalcul, e); + } catch (Exception e) { + log.debug("{} : Erreur de calcul impact item physique: Erreur technique de l'indicateur : {}", TypeErreurCalcul.ERREUR_TECHNIQUE.getCode(), e.getMessage()); + impactErreur = buildCalculImpactForError(demandeCalcul, new CalculImpactException(TypeErreurCalcul.ERREUR_TECHNIQUE.getCode(), "Erreur publication de l'indicateur : " + e.getMessage())); + } + return impactErreur; + } + + private ImpactOperationNonIT getCalculImpactOperationNonIT(DemandeCalculImpactOperationNonIT demandeCalcul) throws CalculImpactException { + MetadataCalcul metadataCalcul = switch (demandeCalcul.getTypeItem().getCategorie()) { + case CATEGORIE_RESEAU_MOBILE, CATEGORIE_MAINTENANCE -> getFormule(demandeCalcul); + case CATEGORIE_RESEAU_FIXE -> getFormuleReseauFixe(demandeCalcul); + case CATEGORIE_BATIMENT -> getFormuleBatiment(demandeCalcul); + case CATEGORIE_DEPLACEMENT_ELECTRIQUE -> getFormuleUtilisationDeplacementVehiculeElectrique(demandeCalcul); + case CATEGORIE_DEPLACEMENT_ESSENCE -> getFormuleUtilisationDeplacementVehiculeEssence(demandeCalcul); + case CATEGORIE_DEPLACEMENT_HYBRIDE -> getFormuleUtilisationDeplacementVehiculeHybride(demandeCalcul); + default -> + throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), "La catégorie renseignée est invalide"); + }; + if (metadataCalcul == null) { + return null; + } + var calcul = buildCalculImpactOperationNonIT(demandeCalcul, metadataCalcul.valeurImpactUnitaire(), metadataCalcul.traceCalculImpactOperationNonIT()); + calcul.setTrace(TraceUtils.getTraceFromTraceur(metadataCalcul.traceCalculImpactOperationNonIT())); + return calcul; + } + + private MetadataCalcul getFormule(DemandeCalculImpactOperationNonIT demandeCalcul) throws CalculImpactException { + if ("UTILISATION".equals(demandeCalcul.getEtape().getCode())) { + return getFormuleUtilisationDefaut(demandeCalcul); + } else { + return getFormuleDefaut(demandeCalcul); + } + } + + private MetadataCalcul getFormuleDefaut(DemandeCalculImpactOperationNonIT demandeCalcul) throws CalculImpactException { + // si l'étape n'est pas UTILISATION, base de la formule commune à toutes les catégories + Double quantite = demandeCalcul.getOperationNonIT().getQuantite(); + ReferentielFacteurCaracterisation referentielFacteurCaracterisation = getImpactItem(demandeCalcul); + Double valeurReferentiel = referentielFacteurCaracterisation.getValeur(); + Double valeurImpactUnitaire = quantite * valeurReferentiel; + TraceCalculImpactOperationNonIT traceCalculImpactOperationNonIT = TraceCalculImpactOperationNonITUtils.buildTrace(null, null, referentielFacteurCaracterisation.getValeur(), referentielFacteurCaracterisation.getSource(), null, null, null); + traceCalculImpactOperationNonIT.setFormule(getFormuleBase(quantite, valeurReferentiel)); + return new MetadataCalcul(valeurImpactUnitaire, traceCalculImpactOperationNonIT); + } + + private MetadataCalcul getFormuleUtilisationDefaut(DemandeCalculImpactOperationNonIT demandeCalcul) throws CalculImpactException { + // base de la formule commune à toutes les catégories de formule + Double quantite = demandeCalcul.getOperationNonIT().getQuantite(); + ConsoElecAnMoyenne consoElecMoyenne = getConsoElecAnMoyenne(demandeCalcul); + MixElectrique mixelec = getMixElectrique(demandeCalcul); + Double valeurImpactUnitaire = quantite * consoElecMoyenne.getValeur() * mixelec.getValeur(); + TraceCalculImpactOperationNonIT traceCalculImpactOperationNonIT = TraceCalculImpactOperationNonITUtils.buildTrace(consoElecMoyenne, mixelec, null, null, null, null, null); + traceCalculImpactOperationNonIT.setFormule(getFormuleUtilisation(quantite, consoElecMoyenne.getValeur(), mixelec.getValeur())); + traceCalculImpactOperationNonIT.setConsoElecAnMoyenne(consoElecMoyenne); + return new MetadataCalcul(valeurImpactUnitaire, traceCalculImpactOperationNonIT); + } + + private MetadataCalcul getFormuleReseauFixe(DemandeCalculImpactOperationNonIT demandeCalcul) throws CalculImpactException { + MetadataCalcul metadataCalcul = getFormule(demandeCalcul); + Hypothese hypothese = getHypothese(demandeCalcul); + Double fixedLineCapacity = hypothese.getValeur(); + Double valeurImpactUnitaire = metadataCalcul.valeurImpactUnitaire() / fixedLineCapacity; + TraceCalculImpactOperationNonIT traceCalculImpactOperationNonIT = metadataCalcul.traceCalculImpactOperationNonIT(); + String traceFormuleBase = traceCalculImpactOperationNonIT.getFormule(); + traceCalculImpactOperationNonIT.setFormule(traceFormuleBase + " / CapaciteLigneFixe(%s)".formatted(fixedLineCapacity)); + traceCalculImpactOperationNonIT.setHypothese(hypothese); + return new MetadataCalcul(valeurImpactUnitaire, traceCalculImpactOperationNonIT); + } + + private MetadataCalcul getFormuleBatiment(DemandeCalculImpactOperationNonIT demandeCalcul) throws CalculImpactException { + if ("UTILISATION".equals(demandeCalcul.getEtape().getCode())) { + return null; + } + MetadataCalcul metadataCalcul = getFormule(demandeCalcul); + DureeDeVie dureeDeVie = getDureeVie(demandeCalcul); + Double dureeDeVieValeur = (dureeDeVie.getValeur() == null) ? dureeDeVie.getDureeDeVieParDefaut().getValeur() : dureeDeVie.getValeur(); + Double valeurImpactUnitaire = metadataCalcul.valeurImpactUnitaire() / dureeDeVieValeur; + TraceCalculImpactOperationNonIT traceCalculImpactOperationNonIT = metadataCalcul.traceCalculImpactOperationNonIT(); + String traceFormuleBase = traceCalculImpactOperationNonIT.getFormule(); + traceCalculImpactOperationNonIT.setFormule(traceFormuleBase + " / DureeDeVie(%s)".formatted(dureeDeVieValeur)); + traceCalculImpactOperationNonIT.setDureeDeVie(dureeDeVie); + return new MetadataCalcul(valeurImpactUnitaire, traceCalculImpactOperationNonIT); + } + + private MetadataCalcul getFormuleUtilisationDeplacementVehiculeEssence(DemandeCalculImpactOperationNonIT demandeCalcul) throws CalculImpactException { + if (!"UTILISATION".equals(demandeCalcul.getEtape().getCode())) { + return null; + } + Double quantite = demandeCalcul.getOperationNonIT().getQuantite(); + Hypothese hypothese = getHypothese(demandeCalcul); + Double consoMoyenne = hypothese.getValeur(); + ReferentielFacteurCaracterisation referentielFacteurCaracterisation = getImpactItem(demandeCalcul); + Double valeurReferentiel = referentielFacteurCaracterisation.getValeur(); + Double valeurImpactUnitaire = consoMoyenne * quantite * valeurReferentiel; + TraceCalculImpactOperationNonIT traceCalculImpactOperationNonIT = TraceCalculImpactOperationNonITUtils.buildTrace(null, null, referentielFacteurCaracterisation.getValeur(), referentielFacteurCaracterisation.getSource(), hypothese, null, null); + traceCalculImpactOperationNonIT.setFormule(getFormuleDeplacement(consoMoyenne, quantite) + " * ReferentielFacteurCaracterisation(%s))".formatted(valeurReferentiel)); + return new MetadataCalcul(valeurImpactUnitaire, traceCalculImpactOperationNonIT); + + } + + private MetadataCalcul getFormuleUtilisationDeplacementVehiculeHybride(DemandeCalculImpactOperationNonIT demandeCalcul) throws CalculImpactException { + if (!"UTILISATION".equals(demandeCalcul.getEtape().getCode())) { + return null; + } + Double quantite = demandeCalcul.getOperationNonIT().getQuantite(); + Hypothese hypothese = getHypothese(demandeCalcul); + Double consoMoyenne = hypothese.getValeur(); + ReferentielFacteurCaracterisation referentielFacteurCaracterisation = getImpactItem(demandeCalcul); + Double valeurReferentiel = referentielFacteurCaracterisation.getValeur(); + Double valeurImpactUnitaire = consoMoyenne * quantite * valeurReferentiel; + TraceCalculImpactOperationNonIT traceCalculImpactOperationNonIT = TraceCalculImpactOperationNonITUtils.buildTrace(null, null, referentielFacteurCaracterisation.getValeur(), referentielFacteurCaracterisation.getSource(), hypothese, null, null); + Hypothese hypotheseTauxHybride = getTauxHybride(demandeCalcul); + valeurImpactUnitaire = valeurImpactUnitaire * hypotheseTauxHybride.getValeur(); + traceCalculImpactOperationNonIT.setFormule(getFormuleDeplacement(consoMoyenne, quantite) + " * ReferentielFacteurCaracterisation(%s) * TauxHybride(%s))".formatted(valeurReferentiel, hypotheseTauxHybride.getValeur())); + return new MetadataCalcul(valeurImpactUnitaire, traceCalculImpactOperationNonIT); + } + + private MetadataCalcul getFormuleUtilisationDeplacementVehiculeElectrique(DemandeCalculImpactOperationNonIT demandeCalcul) throws CalculImpactException { + if (!"UTILISATION".equals(demandeCalcul.getEtape().getCode())) { + return null; + } + Double quantite = demandeCalcul.getOperationNonIT().getQuantite(); + Hypothese hypothese = getHypothese(demandeCalcul); + Double consoMoyenne = hypothese.getValeur(); + MixElectrique mixelec = getMixElectrique(demandeCalcul); + Double valeurImpactUnitaire = consoMoyenne * quantite * mixelec.getValeur(); + TraceCalculImpactOperationNonIT traceCalculImpactOperationNonIT = TraceCalculImpactOperationNonITUtils.buildTrace(null, mixelec, null, null, null, null, null); + traceCalculImpactOperationNonIT.setFormule(getFormuleDeplacement(consoMoyenne, quantite) + " * MixElectrique(%s))".formatted(mixelec.getValeur())); + return new MetadataCalcul(valeurImpactUnitaire, traceCalculImpactOperationNonIT); + } + + private ImpactOperationNonIT buildCalculImpactOperationNonIT(DemandeCalculImpactOperationNonIT demandeCalcul, Double valeurImpactUnitaire, TraceCalculImpactOperationNonIT traceCalculImpactOperationNonIT) { + ImpactOperationNonIT result = ImpactOperationNonIT + .builder() + .nomItemNonIT(demandeCalcul.getOperationNonIT().getNomItemNonIT()) + .etapeACV(demandeCalcul.getEtape().getCode()) + .critere(demandeCalcul.getCritere().getNomCritere()) + .dateCalcul(demandeCalcul.getDateCalcul()) + .versionCalcul(VERSION_CALCUL) + .typeItem(demandeCalcul.getOperationNonIT().getType()) + .quantite(demandeCalcul.getOperationNonIT().getQuantite()) + .statutIndicateur("OK") + .impactUnitaire(valeurImpactUnitaire) + .unite(demandeCalcul.getCritere().getUnite()) + .nomLot(demandeCalcul.getOperationNonIT().getNomLot()) + .nomSourceDonnee(demandeCalcul.getOperationNonIT().getNomSourceDonnee()) + .dateLot(demandeCalcul.getOperationNonIT().getDateLot()) + .nomEntite(demandeCalcul.getOperationNonIT().getNomEntite()) + .nomOrganisation(demandeCalcul.getOperationNonIT().getNomOrganisation()) + .build(); + if (traceCalculImpactOperationNonIT.getConsoElecAnMoyenne() != null) { + result.setConsoElecMoyenne(traceCalculImpactOperationNonIT.getConsoElecAnMoyenne().getValeur()); + } + return result; + } + + private ImpactOperationNonIT buildCalculImpactForError(DemandeCalculImpactOperationNonIT demandeCalcul, CalculImpactException exception) { + + return ImpactOperationNonIT + .builder() + .nomItemNonIT(demandeCalcul.getOperationNonIT().getNomItemNonIT()) + .etapeACV(demandeCalcul.getEtape().getCode()) + .critere(demandeCalcul.getCritere().getNomCritere()) + .dateCalcul(demandeCalcul.getDateCalcul()) + .versionCalcul(VERSION_CALCUL) + .typeItem(demandeCalcul.getOperationNonIT().getType()) + .quantite(demandeCalcul.getOperationNonIT().getQuantite()) + .statutIndicateur("ERREUR") + .impactUnitaire(null) + .unite(demandeCalcul.getCritere().getUnite()) + .consoElecMoyenne(null) + .nomLot(demandeCalcul.getOperationNonIT().getNomLot()) + .nomSourceDonnee(demandeCalcul.getOperationNonIT().getNomSourceDonnee()) + .dateLot(demandeCalcul.getOperationNonIT().getDateLot()) + .nomEntite(demandeCalcul.getOperationNonIT().getNomEntite()) + .nomOrganisation(demandeCalcul.getOperationNonIT().getNomOrganisation()) + .trace(TraceUtils.getTraceFromTraceur(TraceCalculImpactOperationNonITUtils.buildTraceErreur(exception))) + .build(); + } + + private Hypothese getHypothese(DemandeCalculImpactOperationNonIT demandeCalcul) throws CalculImpactException { + Optional<ReferentielHypothese> hypothese = demandeCalcul.getHypotheseFromCode(demandeCalcul.getTypeItem().getRefHypothese()); + if (hypothese.isPresent() && hypothese.get().getValeur() != null) { + return Hypothese.builder() + .valeur(hypothese.get().getValeur()) + .nom_hypothese(hypothese.get().getCode()) + .source(hypothese.get().getSource()) + .build(); + } + throw new CalculImpactException( + TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), + "Il n'y a pas d'hypothese pour l'item pour la refHypothese '" + demandeCalcul.getTypeItem().getRefHypothese() + "' de l'item " + demandeCalcul.getOperationNonIT().getNomItemNonIT()); + + } + + private Hypothese getTauxHybride(DemandeCalculImpactOperationNonIT demandeCalcul) throws CalculImpactException { + var hypothese = demandeCalcul.getHypotheseFromCode("TAUX_VEHICULE_HYBRIDE"); + if (hypothese.isPresent() && hypothese.get().getValeur() != null) { + return Hypothese.builder() + .valeur(hypothese.get().getValeur()) + .nom_hypothese(hypothese.get().getCode()) + .source(hypothese.get().getSource()) + .build(); + } + throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), "Il n'y a pas de taux renseigné pour les véhicules hybrides dans la table des références"); + } + + private ReferentielFacteurCaracterisation getImpactItem(DemandeCalculImpactOperationNonIT demandeCalcul) throws CalculImpactException { + Optional<ReferentielFacteurCaracterisation> facteurCaracterisation = demandeCalcul.getFacteurCaracterisation(demandeCalcul.getTypeItem().getRefItemParDefaut()); + if (facteurCaracterisation.isPresent() && facteurCaracterisation.get().getValeur() != null) { + return facteurCaracterisation.get(); + } else { + throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), "Référentiel Facteur Caractérisation inconnu"); + } + } + + private ConsoElecAnMoyenne getConsoElecAnMoyenne(DemandeCalculImpactOperationNonIT demandeCalcul) throws CalculImpactException { + if (demandeCalcul.getOperationNonIT().getConsoElecAnnuelle() != null) { + var valeur = demandeCalcul.getOperationNonIT().getConsoElecAnnuelle(); + return ConsoElecAnMoyenne.builder() + .valeurItemConsoElecAnnuelle(valeur) + .valeur(valeur) + .build(); + } + if (StringUtils.isBlank(demandeCalcul.getRefItemParDefaut())) { + throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), "Référentiel Facteur Caractérisation inconnu"); + } + + var referentielFacteurCaracterisation = getImpactItem(demandeCalcul); + if (referentielFacteurCaracterisation.getConsoElecMoyenne() == null) { + throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), + "Donnée de consommation electrique manquante : operationNonIT : " + demandeCalcul.getOperationNonIT().getNomItemNonIT() + + ", RefItemParDefaut : " + demandeCalcul.getTypeItem().getRefItemParDefaut() + + ); + } + + var valeur = referentielFacteurCaracterisation.getConsoElecMoyenne(); + return ConsoElecAnMoyenne.builder() + .sourceReferentielFacteurCaracterisation(referentielFacteurCaracterisation.getSource()) + .valeurReferentielConsoElecMoyenne(valeur) + .valeur(valeur) + .build(); + + } + + private MixElectrique getMixElectrique(DemandeCalculImpactOperationNonIT demandeCalcul) throws CalculImpactException { + if (StringUtils.isNotBlank(demandeCalcul.getOperationNonIT().getLocalisation())) { + Optional<ReferentielFacteurCaracterisation> refMixElecOpt = demandeCalcul.getMixElectriqueFromFacteurCaracterisation(demandeCalcul.getOperationNonIT().getLocalisation()); + if (refMixElecOpt.isPresent()) { + var refMixElec = refMixElecOpt.get(); + return MixElectrique.builder() + .valeur(refMixElec.getValeur()) + .valeurReferentielMixElectrique(refMixElec.getValeur()) + .sourceReferentielMixElectrique(refMixElec.getSource()) + .build(); + } + } + throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), + "Il n'existe pas de Mix électrique pour cet item non it : critere: " + demandeCalcul.getCritere().getNomCritere() + + " - operation non it: " + demandeCalcul.getOperationNonIT().getNomItemNonIT() + + " - Localisation: " + demandeCalcul.getOperationNonIT().getLocalisation() + ); + + } + + /** + * Si la duree de vie est renseignée dans l'opérationNonIT, on retourne cette valeur + * Sinon, si la valeur est renseignée dans la table ref_typeitem correspondant à cet item, on retourne cette valeur + * Sinon, si dans la table ref_hypothèse on a une valeur pour la clé "dureeVieDatacenter", on utilise cette valeur + * Sinon, on renvoie une erreur + * + * @param demandeCalcul la demande de calcul + * @return dureeDeVie + * @throws CalculImpactException + */ + public DureeDeVie getDureeVie(DemandeCalculImpactOperationNonIT demandeCalcul) throws CalculImpactException { + var refHypotheseOpt = demandeCalcul.getHypotheseFromCode("dureeVieBatimentParDefaut"); + var dureeDeVie = DureeDeVie.builder().build(); + + if (demandeCalcul.getOperationNonIT().getDureeDeVie() != null) { + dureeDeVie.setValeur(demandeCalcul.getOperationNonIT().getDureeDeVie()); + + } else if (demandeCalcul.getTypeItem() != null && demandeCalcul.getTypeItem().getDureeVieDefaut() != null) { + dureeDeVie.setDureeDeVieParDefaut(DureeDeVieParDefaut.builder() + .valeurTypeItemDureeVieDefaut(demandeCalcul.getTypeItem().getDureeVieDefaut()) + .valeur(demandeCalcul.getTypeItem().getDureeVieDefaut()) + .sourceTypeItemDureeVieDefaut(demandeCalcul.getTypeItem().getSource()) + .build()); + + } else if (refHypotheseOpt.isPresent() && refHypotheseOpt.get().getValeur() != null) { + ReferentielHypothese hypothese = refHypotheseOpt.get(); + dureeDeVie.setDureeDeVieParDefaut(DureeDeVieParDefaut.builder() + .valeurReferentielHypothese(hypothese.getValeur()) + .sourceReferentielHypothese(hypothese.getSource()) + .valeur(hypothese.getValeur()) + .build()); + } else { + throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), "La durée de vie par défaut de l'item n'a pas pu être déterminée"); + + } + return dureeDeVie; + } +} diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactReseauServiceImpl.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactReseauServiceImpl.java index d9fe16ac9451b6a4778464733aa0624de5932d33..74f449d0d5325d86b4ff41b78e17e9c89b4e4c16 100644 --- a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactReseauServiceImpl.java +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/CalculImpactReseauServiceImpl.java @@ -1,6 +1,5 @@ package org.mte.numecoeval.calculs.domain.port.input.service.impl; -import com.fasterxml.jackson.databind.ObjectMapper; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactReseau; @@ -20,8 +19,6 @@ public class CalculImpactReseauServiceImpl implements CalculImpactReseauService private static final String VERSION_CALCUL = "1.0"; - private final ObjectMapper objectMapper; - @Override public ImpactReseau calculerImpactReseau(DemandeCalculImpactReseau demandeCalcul) { try { @@ -106,7 +103,6 @@ public class CalculImpactReseauServiceImpl implements CalculImpactReseauService .unite(referentielImpactReseau.getUnite()) .trace( TraceUtils.getTraceFromTraceur( - objectMapper, TraceCalculImpactReseauUtils.buildTrace(demandeCalcul, referentielImpactReseau)) ) .build(); @@ -129,7 +125,6 @@ public class CalculImpactReseauServiceImpl implements CalculImpactReseauService .impactUnitaire(null) .unite(demandeCalcul.getCritere().getUnite()) .trace(TraceUtils.getTraceFromTraceur( - objectMapper, TraceCalculImpactReseauUtils.buildTraceErreur(exception)) ) .build(); diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/DureeDeVieEquipementPhysiqueServiceImpl.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/DureeDeVieEquipementPhysiqueServiceImpl.java index 717db5f02be59ada9e1a833dbb02339a95a34e1f..5b5f19603237534261c4e6f88174ed0865dd03c2 100644 --- a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/DureeDeVieEquipementPhysiqueServiceImpl.java +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/port/input/service/impl/DureeDeVieEquipementPhysiqueServiceImpl.java @@ -24,17 +24,17 @@ public class DureeDeVieEquipementPhysiqueServiceImpl implements DureeDeVieEquipe if (dateAchat != null && dateRetrait != null) { if (dateAchat.isBefore(dateRetrait)) { - Double valeur ; + Double valeur; if (ChronoUnit.MONTHS.between(dateAchat, dateRetrait) < 12) { - valeur= 1d; + valeur = 1d; } else { - valeur = ChronoUnit.DAYS.between(dateAchat, dateRetrait) / 365d; + valeur = ChronoUnit.DAYS.between(dateAchat, dateRetrait) / 365d; } result.setValeur(valeur); result.setDateAchat(dateAchat.format(DateTimeFormatter.ISO_DATE)); result.setDateRetrait(dateRetrait.format(DateTimeFormatter.ISO_DATE)); } else { - throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),"La durée de vie de l'équipement n'a pas pu être déterminée"); + throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), "La durée de vie de l'équipement n'a pas pu être déterminée"); } } // Taiga#864 - Si la date d'achat est présente et non la date de retrait, on prend la date du jour devient la date de retrait pour le calcul @@ -44,26 +44,26 @@ public class DureeDeVieEquipementPhysiqueServiceImpl implements DureeDeVieEquipe ); result.setDateAchat(dateAchat.format(DateTimeFormatter.ISO_DATE)); result.setDateRetrait(LocalDate.now().format(DateTimeFormatter.ISO_DATE)); - } - else { + } else { var dureeDeVieParDefaut = calculerDureeVieDefaut(demandeCalcul); result.setDureeDeVieParDefaut(dureeDeVieParDefaut); result.setValeur(dureeDeVieParDefaut.getValeur()); } - return result; + return result; } @Override public DureeDeVieParDefaut calculerDureeVieDefaut(DemandeCalculImpactEquipementPhysique demandeCalcul) throws CalculImpactException { - if(demandeCalcul.getTypeEquipement() != null && demandeCalcul.getTypeEquipement().getDureeVieDefaut() !=null){ + if (demandeCalcul.getTypeEquipement() != null && demandeCalcul.getTypeEquipement().getDureeVieDefaut() != null) { return DureeDeVieParDefaut.builder() - .valeurEquipementDureeVieDefaut(demandeCalcul.getTypeEquipement().getDureeVieDefaut()) + .valeurTypeItemDureeVieDefaut(demandeCalcul.getTypeEquipement().getDureeVieDefaut()) + .sourceTypeItemDureeVieDefaut(demandeCalcul.getTypeEquipement().getSource()) .valeur(demandeCalcul.getTypeEquipement().getDureeVieDefaut()) .build(); } - var refHypotheseOpt= demandeCalcul.getHypotheseFromCode("dureeVieParDefaut"); - if (refHypotheseOpt.isPresent() && refHypotheseOpt.get().getValeur() != null){ + var refHypotheseOpt = demandeCalcul.getHypotheseFromCode("dureeVieParDefaut"); + if (refHypotheseOpt.isPresent() && refHypotheseOpt.get().getValeur() != null) { ReferentielHypothese hypothese = refHypotheseOpt.get(); return DureeDeVieParDefaut.builder() .valeurReferentielHypothese(hypothese.getValeur()) @@ -71,7 +71,7 @@ public class DureeDeVieEquipementPhysiqueServiceImpl implements DureeDeVieEquipe .valeur(hypothese.getValeur()) .build(); } - throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(),"La durée de vie par défaut de l'équipement n'a pas pu être déterminée"); + throw new CalculImpactException(TypeErreurCalcul.ERREUR_FONCTIONNELLE.getCode(), "La durée de vie par défaut de l'équipement n'a pas pu être déterminée"); } } diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactEquipementPhysiqueUtils.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactEquipementPhysiqueUtils.java index d1aafb978376547ebca7a9c1ce70c12a64223142..152029304044a0c7755521d5f2112bb4c055c89c 100644 --- a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactEquipementPhysiqueUtils.java +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactEquipementPhysiqueUtils.java @@ -43,7 +43,7 @@ public class TraceCalculImpactEquipementPhysiqueUtils { } public static String getFormuleSecondScenario(Double quantite, Double valeurRefrentiel, Double dureeVie, Double taux_utilisation) { - return "ImpactEquipementPhysique = (Quantité(%s) * referentielImpactEquipement(%s) * TauxUtilisation(%s)) / dureeVie(%s)".formatted(quantite, valeurRefrentiel, taux_utilisation, dureeVie); + return "ImpactEquipementPhysique = (Quantité(%s) * referentielFacteurCaracterisation(%s) * TauxUtilisation(%s)) / dureeVie(%s)".formatted(quantite, valeurRefrentiel, taux_utilisation, dureeVie); } } diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactOperationNonITUtils.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactOperationNonITUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..8d25e9c67c64a000c1c1985905934511cba3ef90 --- /dev/null +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceCalculImpactOperationNonITUtils.java @@ -0,0 +1,45 @@ +package org.mte.numecoeval.calculs.domain.traceur; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.mte.numecoeval.calculs.domain.data.trace.*; +import org.mte.numecoeval.calculs.domain.exception.CalculImpactException; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class TraceCalculImpactOperationNonITUtils { + public static TraceCalculImpactOperationNonIT buildTraceErreur(CalculImpactException exception) { + var message = "Erreur lors du calcul de l'impact de l'opération non IT"; + if (exception != null) { + message = exception.getErrorType() + " : " + exception.getMessage(); + } + return TraceCalculImpactOperationNonIT.builder() + .erreur(message) + .build(); + } + + public static TraceCalculImpactOperationNonIT buildTrace(ConsoElecAnMoyenne consoElecAnMoyenne, MixElectrique mixElectrique, Double valeurReferentielFacteurCaracterisation, String sourceReferentielFacteurCaracterisation, Hypothese hypothese, DureeDeVie dureeDeVie, String erreur) { + return TraceCalculImpactOperationNonIT.builder() + .consoElecAnMoyenne(consoElecAnMoyenne) + .mixElectrique(mixElectrique) + .valeurReferentielFacteurCaracterisation(valeurReferentielFacteurCaracterisation) + .sourceReferentielFacteurCaracterisation(sourceReferentielFacteurCaracterisation) + .hypothese(hypothese) + .dureeDeVie(dureeDeVie) + .erreur(erreur) + .build(); + } + + public static String getFormuleUtilisation(Double quantite, Double consoElecAnMoyenne, Double mixElectriqueValeur) { + return "ImpactOperationNonIT = (Quantité(%s) * ConsoElecAnMoyenne(%s) * MixElectrique(%s))".formatted(quantite, consoElecAnMoyenne, mixElectriqueValeur); + } + + public static String getFormuleBase(Double quantite, Double valeurReferentiel) { + return "ImpactOperationNonIT = (Quantité(%s) * ReferentielFacteurCaracterisation(%s))".formatted(quantite, valeurReferentiel); + } + + public static String getFormuleDeplacement(Double consoMoyenne, Double quantite) { + return "ImpactOperationNonIT = (ConsoMoyenne(%s) * NbKmParcourus(%s)".formatted(consoMoyenne, quantite); + } + + +} diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceUtils.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceUtils.java index 28f04788ccd899082d5dcbb5f329b2a67832ed33..e78427b2997095f45f4f32a98afa254bf193fdf2 100644 --- a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceUtils.java +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/traceur/TraceUtils.java @@ -7,12 +7,14 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class TraceUtils { + private static final ObjectMapper objectMapper = new ObjectMapper(); + private TraceUtils() { // private constructor } - public static String getTraceFromTraceur(ObjectMapper objectMapper, Object traceur) { - String trace= ""; + public static String getTraceFromTraceur(Object traceur) { + String trace = ""; try { trace = objectMapper.writeValueAsString(traceur); } catch (JsonProcessingException e) { diff --git a/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/utils/Constants.java b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/utils/Constants.java new file mode 100644 index 0000000000000000000000000000000000000000..0283c2756ed341ea5cab0df780466725a8b7261f --- /dev/null +++ b/services/calculs/src/main/java/org/mte/numecoeval/calculs/domain/utils/Constants.java @@ -0,0 +1,20 @@ +package org.mte.numecoeval.calculs.domain.utils; + +import java.util.List; + +public class Constants { + + public static final String ELECTRICITY_MIX_CATEGORY = "electricity-mix"; + public static final String CATEGORIE_RESEAU_FIXE = "RESEAU_FIXE"; + public static final String CATEGORIE_RESEAU_MOBILE = "RESEAU_MOBILE"; + public static final String CATEGORIE_BATIMENT = "BATIMENT"; + public static final String CATEGORIE_MAINTENANCE = "MAINTENANCE"; + public static final String CATEGORIE_DEPLACEMENT_ELECTRIQUE = "DEPLACEMENT_ELECTRIQUE"; + public static final String CATEGORIE_DEPLACEMENT_HYBRIDE = "DEPLACEMENT_HYBRIDE"; + public static final String CATEGORIE_DEPLACEMENT_ESSENCE = "DEPLACEMENT_ESSENCE"; + public static final List<String> CATEGORIES_INDIRECT_FABRICATION = List.of( + CATEGORIE_DEPLACEMENT_HYBRIDE, + CATEGORIE_DEPLACEMENT_ESSENCE + ); + +} diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/TestJsonUtils.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/TestJsonUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..43590feacf1cefc18c49138fe0c89cb82b885090 --- /dev/null +++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/TestJsonUtils.java @@ -0,0 +1,19 @@ +package org.mte.numecoeval.calculs; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class TestJsonUtils { + public static String format(String json) { + var mapper = new ObjectMapper().configure(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS, true); + try { + return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(mapper.readValue(json, Object.class)); + } catch (JsonProcessingException e) { + log.error("Cannot format json string", e); + } + return null; + } +} diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactApplicationServiceImplTest.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactApplicationServiceImplTest.java index ee8972137ef2d085a1fa861a1a09bc9b88175311..e6acd91211c7e09be1f6bc025806303059c6c728 100644 --- a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactApplicationServiceImplTest.java +++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactApplicationServiceImplTest.java @@ -1,6 +1,5 @@ package org.mte.numecoeval.calculs.domain.service; -import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -22,16 +21,16 @@ import static org.junit.jupiter.api.Assertions.*; @ExtendWith(MockitoExtension.class) class CalculImpactApplicationServiceImplTest { - CalculImpactApplicationServiceImpl calculImpactApplicatifService ; + CalculImpactApplicationServiceImpl calculImpactApplicatifService; @BeforeEach - void setUp(){ - calculImpactApplicatifService = new CalculImpactApplicationServiceImpl(new ObjectMapper()); + void setUp() { + calculImpactApplicatifService = new CalculImpactApplicationServiceImpl(); } @Test void whenImpactEquipementVirtuelIsInError_ShouldReturnImpactError() { - String applicationName ="MS-Word"; + String applicationName = "MS-Word"; String environnement = "Production"; LocalDate dateLot = LocalDate.of(2023, 4, 1); Application application = Application.builder() @@ -80,7 +79,7 @@ class CalculImpactApplicationServiceImplTest { @Test void whenImpactEquipementVirtuelIsNull_ShouldReturnImpactError() { - String applicationName ="MS-Word"; + String applicationName = "MS-Word"; String environnement = "Production"; LocalDate dateLot = LocalDate.of(2023, 4, 1); Application application = Application.builder() @@ -130,7 +129,7 @@ class CalculImpactApplicationServiceImplTest { @ParameterizedTest @ValueSource(ints = 0) void whenNbApplicationIs0_ShouldApplyRatio1AndReturnImpactOK(Integer nbApplications) { - String applicationName ="MS-Word"; + String applicationName = "MS-Word"; String environnement = "Production"; LocalDate dateLot = LocalDate.of(2023, 4, 1); Application application = Application.builder() @@ -178,7 +177,7 @@ class CalculImpactApplicationServiceImplTest { @ParameterizedTest @NullSource void whenNbApplicationIsNull_ShouldApplyRatio1AndReturnImpactOK(Integer nbApplications) { - String applicationName ="MS-Word"; + String applicationName = "MS-Word"; String environnement = "Production"; LocalDate dateLot = LocalDate.of(2023, 4, 1); Application application = Application.builder() @@ -225,7 +224,7 @@ class CalculImpactApplicationServiceImplTest { @Test void whenImpactEquipementVirtuelIsOK_ShouldReturnImpactOK() { - String applicationName ="MS-Word"; + String applicationName = "MS-Word"; String environnement = "Production"; LocalDate dateLot = LocalDate.of(2023, 4, 1); Application application = Application.builder() @@ -272,7 +271,7 @@ class CalculImpactApplicationServiceImplTest { @Test void taiga1025_whenNbApplicationsIsMoreThan1_ThenImpactShouldBeDividedAndImpactShouldBeOK() { - String applicationName ="MS-Word"; + String applicationName = "MS-Word"; String environnement = "Production"; LocalDate dateLot = LocalDate.of(2023, 4, 1); Application application = Application.builder() @@ -312,8 +311,8 @@ class CalculImpactApplicationServiceImplTest { assertContentIndicateur(demanceCalcul, impactApplication); - assertEquals(demanceCalcul.getImpactEquipementVirtuel().getImpactUnitaire()/demanceCalcul.getNbApplications(), impactApplication.getImpactUnitaire()); - assertEquals(demanceCalcul.getImpactEquipementVirtuel().getConsoElecMoyenne()/demanceCalcul.getNbApplications(), impactApplication.getConsoElecMoyenne()); + assertEquals(demanceCalcul.getImpactEquipementVirtuel().getImpactUnitaire() / demanceCalcul.getNbApplications(), impactApplication.getImpactUnitaire()); + assertEquals(demanceCalcul.getImpactEquipementVirtuel().getConsoElecMoyenne() / demanceCalcul.getNbApplications(), impactApplication.getConsoElecMoyenne()); assertEquals("OK", impactApplication.getStatutIndicateur()); assertEquals("{\"formule\":\"ImpactApplication = ImpactEquipementVirtuel(61.744) / nbApplications(10)\",\"nbApplications\":10}", impactApplication.getTrace()); diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactEquipementPhysiqueServiceTest.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactEquipementPhysiqueServiceTest.java index 7d644ac5b0626e4878ecd18ad61315ace5d535de..23b3477d7372073a877baf1132e26cbf5d8dc9f7 100644 --- a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactEquipementPhysiqueServiceTest.java +++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactEquipementPhysiqueServiceTest.java @@ -7,7 +7,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementPhysique; import org.mte.numecoeval.calculs.domain.data.entree.DataCenter; @@ -55,15 +54,11 @@ class CalculImpactEquipementPhysiqueServiceTest { @Mock private DureeDeVieEquipementPhysiqueServiceImpl dureeDeVieEquipementPhysiqueService; - @Spy - private ObjectMapper objectMapper; - @BeforeEach public void init() throws Exception { MockitoAnnotations.openMocks(this); calculImpactEquipementPhysiqueService = new CalculImpactEquipementPhysiqueServiceImpl( - dureeDeVieEquipementPhysiqueService, - objectMapper + dureeDeVieEquipementPhysiqueService ); etapeACV = "UTILISATION"; String etapeACV = "UTILISATION"; @@ -1137,14 +1132,14 @@ class CalculImpactEquipementPhysiqueServiceTest { var formule = TraceCalculImpactEquipementPhysiqueUtils.getFormulePremierScenario(3d, 200d, 150d, 1.0); - var consoElecAnMoyenne = ConsoElecAnMoyenne.builder().valeurEquipementConsoElecAnnuelle(200d).valeur(200d).build(); + var consoElecAnMoyenne = ConsoElecAnMoyenne.builder().valeurItemConsoElecAnnuelle(200d).valeur(200d).build(); var mixElectrique = MixElectrique.builder().valeur(150d).valeurReferentielMixElectrique(150d).sourceReferentielMixElectrique("Source-Mix").build(); TraceCalculImpactEquipementPhysique trace = TraceCalculImpactEquipementPhysique.builder() .formule(formule) .consoElecAnMoyenne(consoElecAnMoyenne) .mixElectrique(mixElectrique) .build(); - var expected = objectMapper.writeValueAsString(trace); + var expected = new ObjectMapper().writeValueAsString(trace); //WHEN var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(demandeCalcul); //THEN @@ -1211,7 +1206,7 @@ class CalculImpactEquipementPhysiqueServiceTest { var consoElecAnMoyenne = ConsoElecAnMoyenne.builder() .valeur(130d) .valeurReferentielConsoElecMoyenne(130d) - .sourceReferentielImpactEquipement("source-RefEquipement") + .sourceReferentielFacteurCaracterisation("source-RefEquipement") .build(); var mixElectrique = MixElectrique.builder() .valeur(125d) @@ -1225,7 +1220,7 @@ class CalculImpactEquipementPhysiqueServiceTest { .consoElecAnMoyenne(consoElecAnMoyenne) .mixElectrique(mixElectrique) .build(); - var expected = objectMapper.writeValueAsString(trace); + var expected = new ObjectMapper().writeValueAsString(trace); //WHEN var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(demandeCalcul); //THEN @@ -1303,7 +1298,7 @@ class CalculImpactEquipementPhysiqueServiceTest { .valeurReferentielImpactEquipement(valeurRefrentiel) .sourceReferentielImpactEquipement(sourceReferentielImpactEquipement) .build(); - var expected = objectMapper.writeValueAsString(trace); + var expected = new ObjectMapper().writeValueAsString(trace); //WHEN var actual = calculImpactEquipementPhysiqueService.calculerImpactEquipementPhysique(demandeCalcul); diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactEquipementVirtuelServiceTest.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactEquipementVirtuelServiceTest.java index c197969a76a39744bf88fc1632fa99791e2b53fd..d5c47b612f4bdfc90c0ee11b0a2d2847fa5fd78f 100644 --- a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactEquipementVirtuelServiceTest.java +++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactEquipementVirtuelServiceTest.java @@ -5,7 +5,6 @@ import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactEquipementVirtuel; import org.mte.numecoeval.calculs.domain.data.entree.EquipementVirtuel; @@ -26,13 +25,11 @@ import static org.junit.jupiter.api.Assertions.*; @ExtendWith({MockitoExtension.class, OutputCaptureExtension.class}) class CalculImpactEquipementVirtuelServiceTest { - @Spy - private ObjectMapper objectMapper; private CalculImpactEquipementVirtuelService calculImpactEquipementVirtuelService; @BeforeEach void setUp() { - calculImpactEquipementVirtuelService = new CalculImpactEquipementVirtuelServiceImpl(objectMapper); + calculImpactEquipementVirtuelService = new CalculImpactEquipementVirtuelServiceImpl(); } /** @@ -46,7 +43,7 @@ class CalculImpactEquipementVirtuelServiceTest { //GIVEN EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -96,7 +93,7 @@ class CalculImpactEquipementVirtuelServiceTest { void whenTotalVCPUIsNull_shouldReturnCalculImpactUsingTotalNumberOfVirtualEquipment() { //GIVEN EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -145,7 +142,7 @@ class CalculImpactEquipementVirtuelServiceTest { void whenTypeEqvIsNotCalculAndTotalVCPUIsNull_shouldReturnCalculImpactUsingTotalNumberOfVirtualEquipment() { //GIVEN EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -193,7 +190,7 @@ class CalculImpactEquipementVirtuelServiceTest { @Test void whenTotalVCPUAndNbrVirtualEquipementAreNull_shouldReturnImpactError() { EquipementVirtuel equipementVirtuel = EquipementVirtuel.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -230,7 +227,7 @@ class CalculImpactEquipementVirtuelServiceTest { void whenNbrVirtualEquipementIs0_shouldReturnImpactError() { //GIVEN EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -277,7 +274,7 @@ class CalculImpactEquipementVirtuelServiceTest { //GIVEN EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -324,7 +321,7 @@ class CalculImpactEquipementVirtuelServiceTest { //GIVEN EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -371,7 +368,7 @@ class CalculImpactEquipementVirtuelServiceTest { void caf5() { EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -409,7 +406,7 @@ class CalculImpactEquipementVirtuelServiceTest { void shouldGetTraceCalculVm() throws Exception { //GIVEN EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -434,13 +431,13 @@ class CalculImpactEquipementVirtuelServiceTest { .equipementVirtuel(equipementVirtuel1) .impactEquipement(impactEquipementPhysique) .nbEquipementsVirtuels(3) - .nbTotalVCPU(7+3+9) + .nbTotalVCPU(7 + 3 + 9) .build(); //WHEN var impactEquipementVirtuel = calculImpactEquipementVirtuelService.calculerImpactEquipementVirtuel(demandeCalcul); var formule = TraceCalculImpactVirtuelUtils.getFormuleWithTotalVCPU(demandeCalcul); - var expected = objectMapper.writeValueAsString(TraceCalculImpactEquipementVirtuel.builder() + var expected = new ObjectMapper().writeValueAsString(TraceCalculImpactEquipementVirtuel.builder() .nbTotalVCPU(demandeCalcul.getNbTotalVCPU()) .nbEquipementsVirtuels(demandeCalcul.getNbEquipementsVirtuels()) .formule(formule) @@ -456,7 +453,7 @@ class CalculImpactEquipementVirtuelServiceTest { void forTaiga437VM1_shouldReturnCalculImpactUsingProrataFormula() { //GIVEN EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -503,7 +500,7 @@ class CalculImpactEquipementVirtuelServiceTest { void forTaiga437VM2_shouldReturnCalculImpactUsingProrataOnCPUFormula() { //GIVEN EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -553,7 +550,7 @@ class CalculImpactEquipementVirtuelServiceTest { void forTaiga437VM4_shouldReturnCalculImpactUsingProrataFormula() { //GIVEN EquipementVirtuel equipementVirtuel1 = EquipementVirtuel.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -565,7 +562,7 @@ class CalculImpactEquipementVirtuelServiceTest { .cleRepartition(null) .build(); EquipementVirtuel equipementVirtuel2 = EquipementVirtuel.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -577,7 +574,7 @@ class CalculImpactEquipementVirtuelServiceTest { .cleRepartition(null) .build(); EquipementVirtuel equipementVirtuel3 = EquipementVirtuel.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactMessagerieServiceTest.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactMessagerieServiceTest.java index 55c55784afca89f3a94aa202ddbcf5bf6dfeb0fc..0835c7da2c0a5158c0f8e1a7439b1267ec872655 100644 --- a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactMessagerieServiceTest.java +++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactMessagerieServiceTest.java @@ -1,6 +1,5 @@ package org.mte.numecoeval.calculs.domain.service; -import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactMessagerie; import org.mte.numecoeval.calculs.domain.data.entree.Messagerie; @@ -18,10 +17,10 @@ import static org.junit.jupiter.api.Assertions.*; class CalculImpactMessagerieServiceTest { - ObjectMapper objectMapper = new ObjectMapper(); - CalculImpactMessagerieService calculImpactMessagerieService = new CalculImpactMessagerieServiceImpl(objectMapper); + CalculImpactMessagerieService calculImpactMessagerieService = new CalculImpactMessagerieServiceImpl(); + @Test - void whenValidMessagerie_shoudCalculerImpactMessagerie(){ + void whenValidMessagerie_shoudCalculerImpactMessagerie() { //GIVEN var dateCalcul = LocalDateTime.now(); ReferentielCritere critere = ReferentielCritere.builder() @@ -35,7 +34,7 @@ class CalculImpactMessagerieServiceTest { .constanteCoefficientDirecteur(30d) .build(); var messagerie = Messagerie.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -57,13 +56,13 @@ class CalculImpactMessagerieServiceTest { //THEN assertContentIndicateur(demandeCalcul, impactMessagerie); - assertEquals(468000d , impactMessagerie.getImpactMensuel()); + assertEquals(468000d, impactMessagerie.getImpactMensuel()); assertEquals("OK", impactMessagerie.getStatutIndicateur()); assertEquals("{\"critere\":\"Changement Climatique\",\"volumeTotalMailEmis\":5000.0,\"nombreMailEmis\":300.0,\"constanteCoefficientDirecteur\":30.0,\"poidsMoyenMail\":16.666666666666668,\"constanteOrdonneeOrigine\":20.0,\"nombreMailEmisXDestinataires\":900.0,\"formule\":\"poidsMoyenMail(16.666666666666668) = volumeTotalMailEmis(5000.0)/nombreMailEmis(300.0);\\nimpactMensuel = (constanteCoefficientDirecteur (30.0) * poidsMoyenMail(16.666666666666668) + constanteOrdonneeOrigine(20.0)) * nombreMailEmisXDestinataires(900.0)\\n\"}", impactMessagerie.getTrace()); } @Test - void whenNonValidMessagerie_shouldReturnEmptyResult(){ + void whenNonValidMessagerie_shouldReturnEmptyResult() { var dateCalcul = LocalDateTime.now(); @@ -78,7 +77,7 @@ class CalculImpactMessagerieServiceTest { .constanteCoefficientDirecteur(30d) .build(); var messagerie = Messagerie.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -103,7 +102,7 @@ class CalculImpactMessagerieServiceTest { } @Test - void whenReferentielIsNotFound_shouldReturnEmptyResult(){ + void whenReferentielIsNotFound_shouldReturnEmptyResult() { var dateCalcul = LocalDateTime.now(); @@ -112,7 +111,7 @@ class CalculImpactMessagerieServiceTest { .unite("kg CO_{2} eq") .build(); var messagerie = Messagerie.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactOperationNonITServiceTest.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactOperationNonITServiceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2fb5ad3ff3e133d2e588f80ca9a30ae780125120 --- /dev/null +++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactOperationNonITServiceTest.java @@ -0,0 +1,1197 @@ +package org.mte.numecoeval.calculs.domain.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; +import org.mte.numecoeval.calculs.TestJsonUtils; +import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactOperationNonIT; +import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactOperationNonIT; +import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielFacteurCaracterisation; +import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielHypothese; +import org.mte.numecoeval.calculs.domain.data.referentiel.ReferentielTypeItem; +import org.mte.numecoeval.calculs.domain.port.input.service.CalculImpactOperationNonITService; +import org.mte.numecoeval.calculs.domain.port.input.service.impl.CalculImpactOperationNonITServiceImpl; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + + +class CalculImpactOperationNonITServiceTest { + + CalculImpactOperationNonITService calculImpactOperationNonITService = new CalculImpactOperationNonITServiceImpl(); + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private DemandeCalculImpactOperationNonIT createDemande() { + try { + var res = objectMapper.readValue(""" + { + "operationNonIT": { + "nomItemNonIT": "nomItem", + "quantite": 1.0, + "localisation": "France", + "nomEntite": "nomEntite" + }, + "etape": { + "code": "FABRICATION" + }, + "critere": { + "nomCritere": "Changement Climatique", + "unite": "kg CO_{2} eq" + }, + "typeItem": {}, + "hypotheses": [], + "facteurCaracterisations": [] + } + """, DemandeCalculImpactOperationNonIT.class); + res.setDateCalcul(LocalDateTime.parse("2024-01-01T00:00:00")); + return res; + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + /** + * Tests de la fonction getFormuleDefaut() + */ + @Test + void shouldCalculerImpactOperationNonIT_reseau_mobile_fabrication() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getOperationNonIT().setType("Reseau Mobile"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "Reseau Mobile", + "categorie": "RESEAU_MOBILE", + "refItemParDefaut": "Reseau Mobile", + "dureeVieDefaut": 10.0 + } + """, ReferentielTypeItem.class)); + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "Reseau Mobile", + "etape": "FABRICATION", + "critere": "Changement Climatique", + "valeur": 10, + "source": "SSG" + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertEquals("OK", actual.getStatutIndicateur()); + assertEquals(10.0, actual.getImpactUnitaire(), 0.0001d); + assertEquals(TestJsonUtils.format(""" + { + "formule" : "ImpactOperationNonIT = (Quantité(1.0) * ReferentielFacteurCaracterisation(10.0))", + "sourceReferentielFacteurCaracterisation" : "SSG", + "valeurReferentielFacteurCaracterisation" : 10.0 + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + /** + * Tests de la fonction getFormuleUtilisationDefaut() + */ + @Test + void shouldCalculerImpactOperationNonIT_reseau_mobile_utilisation_consoElecFromItemNonIT() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getEtape().setCode("UTILISATION"); + demandeCalcul.getOperationNonIT().setType("Reseau Mobile"); + demandeCalcul.getOperationNonIT().setConsoElecAnnuelle(100.0); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "Reseau Mobile", + "categorie": "RESEAU_MOBILE", + "refItemParDefaut": "Reseau Mobile", + "dureeVieDefaut": 10.0 + } + """, ReferentielTypeItem.class)); + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "Reseau Mobile", + "etape": "UTILISATION", + "critere": "Changement Climatique", + "valeur": 10, + "source": "SSG" + }, + { + "nom": "Electricty Mix FR", + "etape": "FABRICATION", + "critere": "Changement Climatique", + "categorie" : "electricity-mix", + "localisation": "France", + "valeur" : 0.01 + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertEquals("OK", actual.getStatutIndicateur()); + assertEquals(1.0, actual.getImpactUnitaire(), 0.0001d); + assertEquals(demandeCalcul.getOperationNonIT().getConsoElecAnnuelle(), actual.getConsoElecMoyenne()); + assertEquals(TestJsonUtils.format(""" + { + "consoElecAnMoyenne" : { + "valeur" : 100.0, + "valeurItemConsoElecAnnuelle" : 100.0 + }, + "formule" : "ImpactOperationNonIT = (Quantité(1.0) * ConsoElecAnMoyenne(100.0) * MixElectrique(0.01))", + "mixElectrique" : { + "serveur" : false, + "valeur" : 0.01, + "valeurReferentielMixElectrique" : 0.01 + } + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + @Test + void shouldCalculerImpactOperationNonIT_reseau_mobile_utilisation_consoElecFromFacteurCaracterisation() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getEtape().setCode("UTILISATION"); + demandeCalcul.getOperationNonIT().setType("Reseau Mobile"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "Reseau Mobile", + "categorie": "RESEAU_MOBILE", + "refItemParDefaut": "Reseau Mobile", + "dureeVieDefaut": 10.0 + } + """, ReferentielTypeItem.class)); + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "Reseau Mobile", + "etape": "UTILISATION", + "critere": "Changement Climatique", + "consoElecMoyenne": 100.0, + "valeur": 10, + "source": "SSG" + }, + { + "nom": "Electricty Mix FR", + "etape": "FABRICATION", + "critere": "Changement Climatique", + "categorie" : "electricity-mix", + "localisation": "France", + "valeur" : 0.01 + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertEquals("OK", actual.getStatutIndicateur()); + assertEquals(1.0, actual.getImpactUnitaire(), 0.0001d); + assertEquals(TestJsonUtils.format(""" + { + "consoElecAnMoyenne" : { + "sourceReferentielFacteurCaracterisation" : "SSG", + "valeur" : 100.0, + "valeurReferentielConsoElecMoyenne" : 100.0 + }, + "formule" : "ImpactOperationNonIT = (Quantité(1.0) * ConsoElecAnMoyenne(100.0) * MixElectrique(0.01))", + "mixElectrique" : { + "serveur" : false, + "valeur" : 0.01, + "valeurReferentielMixElectrique" : 0.01 + } + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + @Test + void when_CalculerImpactOperationNonIT_reseau_mobile_Item_NotInFacteurCaracterisation_shouldReturnIndicateurWithError() { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.setTypeItem(ReferentielTypeItem.builder() + .categorie("RESEAU_MOBILE") + .build()); + demandeCalcul.setFacteurCaracterisations(null); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertNull(actual.getImpactUnitaire()); + assertEquals("ERREUR", actual.getStatutIndicateur()); + assertEquals(TestJsonUtils.format( + """ + { + "erreur": "ErrCalcFonc : Référentiel Facteur Caractérisation inconnu" + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + @Test + void when_CalculerImpactOperationNonIT_reseau_mobile_utilisation_And_NoConsoElec_shouldReturnIndicateurWithError() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getEtape().setCode("UTILISATION"); + demandeCalcul.getOperationNonIT().setType("Reseau Mobile"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "Reseau Mobile", + "categorie": "RESEAU_MOBILE", + "refItemParDefaut": "Reseau Mobile", + "dureeVieDefaut": 10.0 + } + """, ReferentielTypeItem.class)); + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "Reseau Mobile", + "etape": "UTILISATION", + "critere": "Changement Climatique", + "valeur": 10, + "source": "SSG" + }, + { + "nom": "Electricty Mix FR", + "etape": "FABRICATION", + "critere": "Changement Climatique", + "categorie" : "electricity-mix", + "localisation": "France", + "valeur" : 0.01 + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertNull(actual.getImpactUnitaire()); + assertEquals("ERREUR", actual.getStatutIndicateur()); + assertEquals(TestJsonUtils.format(""" + { + "erreur" : "ErrCalcFonc : Donnée de consommation electrique manquante : operationNonIT : nomItem, RefItemParDefaut : Reseau Mobile" + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + @Test + void when_CalculerImpactOperationNonIT_reseau_mobile_utilisation_And_MixElecNotInReferentiel_shouldReturnIndicateurWithError() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getEtape().setCode("UTILISATION"); + demandeCalcul.getOperationNonIT().setConsoElecAnnuelle(0.09); + demandeCalcul.getOperationNonIT().setType("Reseau Mobile"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "Reseau Mobile", + "categorie": "RESEAU_MOBILE", + "refItemParDefaut": "Reseau Mobile", + "dureeVieDefaut": 10.0 + } + """, ReferentielTypeItem.class)); + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "Reseau Mobile", + "etape": "UTILISATION", + "critere": "Changement Climatique", + "valeur": 10, + "source": "SSG" + }, + { + "nom": "Electricty Mix FR", + "etape": "FABRICATION", + "critere": "Changement Climatique", + "categorie" : "electricity-mix", + "localisation": "!!! PAYS INCONNU !!!", + "valeur" : 0.01 + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertNull(actual.getImpactUnitaire()); + assertEquals("ERREUR", actual.getStatutIndicateur()); + assertEquals(TestJsonUtils.format(""" + { + "erreur" : "ErrCalcFonc : Il n'existe pas de Mix électrique pour cet item non it : critere: Changement Climatique - operation non it: nomItem - Localisation: France" + } + """), + TestJsonUtils.format(actual.getTrace())); + + } + + @Test + void shouldCalculerImpactOperationNonIT_maintenance_fabrication() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getOperationNonIT().setType("Maintenance sur facture"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "Maintenance sur facture", + "categorie": "MAINTENANCE", + "refItemParDefaut": "maintenance-1", + "source": "sourceDefault" + } + """, ReferentielTypeItem.class)); + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "maintenance-1", + "etape": "FABRICATION", + "critere": "Changement Climatique", + "valeur": 10, + "source": "sourceDefault" + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertEquals("OK", actual.getStatutIndicateur()); + assertEquals(10.0, actual.getImpactUnitaire(), 0.0001d); + assertEquals(TestJsonUtils.format( + """ + { + "formule" : "ImpactOperationNonIT = (Quantité(1.0) * ReferentielFacteurCaracterisation(10.0))", + "sourceReferentielFacteurCaracterisation" : "sourceDefault", + "valeurReferentielFacteurCaracterisation" : 10.0 + } + """), + TestJsonUtils.format(actual.getTrace())); + + } + + @Test + void shouldCalculerImpactOperationNonIT_maintenance_utilisation_consoElecFromItemNonIT() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getEtape().setCode("UTILISATION"); + demandeCalcul.getOperationNonIT().setConsoElecAnnuelle(100.0); + demandeCalcul.getOperationNonIT().setType("Maintenance sur facture"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "Maintenance sur facture", + "categorie": "MAINTENANCE", + "refItemParDefaut": "maintenance-1", + "source": "sourceDefault" + } + """, ReferentielTypeItem.class)); + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "maintenance-1", + "etape": "UTILISATION", + "critere": "Changement Climatique", + "consoElecMoyenne": 100.0, + "valeur": 10, + "source": "sourceDefault" + }, + { + "nom": "Electricty Mix FR", + "etape": "FABRICATION", + "critere": "Changement Climatique", + "categorie" : "electricity-mix", + "localisation": "France", + "valeur" : 0.01 + } + ] + """, ReferentielFacteurCaracterisation[].class))); + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertEquals("OK", actual.getStatutIndicateur()); + assertEquals(1.0, actual.getImpactUnitaire(), 0.0001d); + assertEquals(TestJsonUtils.format(""" + { + "consoElecAnMoyenne" : { + "valeur" : 100.0, + "valeurItemConsoElecAnnuelle" : 100.0 + }, + "formule" : "ImpactOperationNonIT = (Quantité(1.0) * ConsoElecAnMoyenne(100.0) * MixElectrique(0.01))", + "mixElectrique" : { + "serveur" : false, + "valeur" : 0.01, + "valeurReferentielMixElectrique" : 0.01 + } + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + /** + * Tests de la fonction getFormuleReseauFixe() + */ + @Test + void shouldCalculerImpactOperationNonIT_reseau_fixe_fabrication() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getOperationNonIT().setType("Fixed Line FR"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "Fixed Line FR", + "categorie": "RESEAU_FIXE", + "refHypothese": "CAPACITE_LIGNE_FIXE_FR", + "refItemParDefaut": "fixed-line-network-1", + "source": "sourceDefault" + } + """, ReferentielTypeItem.class)); + + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "fixed-line-network-1", + "etape": "FABRICATION", + "critere": "Changement Climatique", + "valeur" : 0.01 + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + demandeCalcul.setHypotheses(List.of(objectMapper.readValue(""" + [ + { + "code": "CAPACITE_LIGNE_FIXE_FR", + "valeur": "10.0", + "source": "sourceDefault" + } + ] + """, ReferentielHypothese[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertEquals("OK", actual.getStatutIndicateur()); + assertEquals(0.001, actual.getImpactUnitaire(), 0.0001d); + assertEquals(TestJsonUtils.format(""" + { + "formule" : "ImpactOperationNonIT = (Quantité(1.0) * ReferentielFacteurCaracterisation(0.01)) / CapaciteLigneFixe(10.0)", + "hypothese" : { + "nom_hypothese" : "CAPACITE_LIGNE_FIXE_FR", + "source" : "sourceDefault", + "valeur" : 10.0 + }, + "valeurReferentielFacteurCaracterisation" : 0.01 + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + @Test + void shouldCalculerImpactOperationNonIT_reseau_fixe_utilisation_consoElecFromFacteurCaracterisation() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getEtape().setCode("UTILISATION"); + demandeCalcul.getOperationNonIT().setType("Fixed Line FR"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "Fixed Line FR", + "categorie": "RESEAU_FIXE", + "refHypothese": "CAPACITE_LIGNE_FIXE_FR", + "refItemParDefaut": "fixed-line-network-1", + "source": "sourceDefault" + } + """, ReferentielTypeItem.class)); + + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "fixed-line-network-1", + "etape": "UTILISATION", + "critere": "Changement Climatique", + "consoElecMoyenne": 100.0, + "valeur" : 0.01 + }, + { + "nom": "Electricty Mix FR", + "etape": "FABRICATION", + "critere": "Changement Climatique", + "categorie" : "electricity-mix", + "localisation": "France", + "valeur" : 0.01 + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + demandeCalcul.setHypotheses(List.of(objectMapper.readValue(""" + [ + { + "code": "CAPACITE_LIGNE_FIXE_FR", + "valeur": "10.0", + "source": "sourceDefault" + } + ] + """, ReferentielHypothese[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertEquals("OK", actual.getStatutIndicateur()); + assertEquals(0.1, actual.getImpactUnitaire(), 0.0001d); + assertEquals(TestJsonUtils.format( + """ + { + "consoElecAnMoyenne" : { + "valeur" : 100.0, + "valeurReferentielConsoElecMoyenne" : 100.0 + }, + "formule" : "ImpactOperationNonIT = (Quantité(1.0) * ConsoElecAnMoyenne(100.0) * MixElectrique(0.01)) / CapaciteLigneFixe(10.0)", + "hypothese" : { + "nom_hypothese" : "CAPACITE_LIGNE_FIXE_FR", + "source" : "sourceDefault", + "valeur" : 10.0 + }, + "mixElectrique" : { + "serveur" : false, + "valeur" : 0.01, + "valeurReferentielMixElectrique" : 0.01 + } + } + """), + TestJsonUtils.format(actual.getTrace()) + ); + } + + /** + * Tests de la fonction getFormuleBatiment() + */ + @Test + void shouldCalculerImpactOperationNonIT_batiment_fabrication_DureeDeVieFromOperationNonIT() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getOperationNonIT().setType("batiment-1"); + demandeCalcul.getOperationNonIT().setDureeDeVie(10.0); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "batiment-1", + "categorie": "BATIMENT", + "refItemParDefaut": "batiment-1", + "source": "sourceDefault" + } + """, ReferentielTypeItem.class)); + + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "batiment-1", + "etape": "FABRICATION", + "critere": "Changement Climatique", + "valeur" : 0.1 + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT( + demandeCalcul + ); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertEquals("OK", actual.getStatutIndicateur()); + assertEquals(0.01, actual.getImpactUnitaire(), 0.0001d); + assertEquals(TestJsonUtils.format(""" + { + "dureeDeVie" : { + "valeur" : 10.0 + }, + "formule" : "ImpactOperationNonIT = (Quantité(1.0) * ReferentielFacteurCaracterisation(0.1)) / DureeDeVie(10.0)", + "valeurReferentielFacteurCaracterisation" : 0.1 + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + @Test + void shouldCalculerImpactOperationNonIT_batiment_fabrication_DureeDeVieFromTypeItem() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getOperationNonIT().setType("batiment-1"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "batiment-1", + "categorie": "BATIMENT", + "refItemParDefaut": "batiment-1", + "dureeVieDefaut": 30.0, + "source": "sourceDefault" + } + """, ReferentielTypeItem.class)); + + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "batiment-1", + "etape": "FABRICATION", + "critere": "Changement Climatique", + "valeur" : 0.1 + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT( + demandeCalcul + ); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertEquals("OK", actual.getStatutIndicateur()); + assertEquals(0.0033333333333333335, actual.getImpactUnitaire(), 0.0001d); + assertEquals(TestJsonUtils.format(""" + { + "dureeDeVie" : { + "dureeDeVieParDefaut" : { + "sourceTypeItemDureeVieDefaut" : "sourceDefault", + "valeur" : 30.0, + "valeurTypeItemDureeVieDefaut" : 30.0 + } + }, + "formule" : "ImpactOperationNonIT = (Quantité(1.0) * ReferentielFacteurCaracterisation(0.1)) / DureeDeVie(30.0)", + "valeurReferentielFacteurCaracterisation" : 0.1 + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + @Test + void shouldCalculerImpactOperationNonIT_batiment_fabrication_DureeDeVieFromHypothese() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getOperationNonIT().setType("batiment-1"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "batiment-1", + "categorie": "BATIMENT", + "refItemParDefaut": "batiment-1", + "source": "sourceDefault" + } + """, ReferentielTypeItem.class)); + + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "batiment-1", + "etape": "FABRICATION", + "critere": "Changement Climatique", + "valeur" : 0.1 + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + demandeCalcul.setHypotheses(List.of(objectMapper.readValue(""" + [ + { + "code": "dureeVieBatimentParDefaut", + "valeur": "50.0", + "source": "sourceDefault" + } + ] + """, ReferentielHypothese[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertEquals("OK", actual.getStatutIndicateur()); + assertEquals(0.002, actual.getImpactUnitaire(), 0.0001d); + assertEquals(TestJsonUtils.format(""" + { + "dureeDeVie" : { + "dureeDeVieParDefaut" : { + "sourceReferentielHypothese" : "sourceDefault", + "valeur" : 50.0, + "valeurReferentielHypothese" : 50.0 + } + }, + "formule" : "ImpactOperationNonIT = (Quantité(1.0) * ReferentielFacteurCaracterisation(0.1)) / DureeDeVie(50.0)", + "valeurReferentielFacteurCaracterisation" : 0.1 + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + @Test + void calculImpactOperationNonIT_batiment_utilisation_shouldReturnNull() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getEtape().setCode("UTILISATION"); + demandeCalcul.getOperationNonIT().setType("batiment-1"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "batiment-1", + "categorie": "BATIMENT", + "refItemParDefaut": "batiment-1", + "source": "sourceDefault" + } + """, ReferentielTypeItem.class)); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertNull(actual); + } + + /** + * Tests de la fonction getFormuleDeplacement() + */ + @Test + void shouldCalculerImpactOperationNonIT_deplacementEssence_utilisation() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getEtape().setCode("UTILISATION"); + demandeCalcul.getOperationNonIT().setType("deplacement-voiture-essence"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "deplacement-voiture-essence", + "categorie": "DEPLACEMENT_ESSENCE", + "refHypothese": "CONSO_MOYENNE_VOITURE_ESSENCE", + "refItemParDefaut": "fuel", + "source": "sourceDefault" + } + """, ReferentielTypeItem.class)); + + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "fuel", + "etape": "FABRICATION", + "critere": "Changement Climatique", + "valeur": 0.1 + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + demandeCalcul.setHypotheses(List.of(objectMapper.readValue(""" + [ + { + "code": "CONSO_MOYENNE_VOITURE_ESSENCE", + "valeur": "6.5", + "source": "sourceDefault" + } + ] + """, ReferentielHypothese[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT( + demandeCalcul + ); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertEquals("OK", actual.getStatutIndicateur()); + assertEquals(0.65, actual.getImpactUnitaire(), 0.0001d); + assertEquals(TestJsonUtils.format(""" + { + "formule" : "ImpactOperationNonIT = (ConsoMoyenne(6.5) * NbKmParcourus(1.0) * ReferentielFacteurCaracterisation(0.1))", + "hypothese" : { + "nom_hypothese" : "CONSO_MOYENNE_VOITURE_ESSENCE", + "source" : "sourceDefault", + "valeur" : 6.5 + }, + "valeurReferentielFacteurCaracterisation" : 0.1 + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + @Test + void shouldCalculerImpactOperationNonIT_deplacementEssence_utilisation_withoutFacteurCaracterisation_shouldReturnIndicateurWithError() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getEtape().setCode("UTILISATION"); + demandeCalcul.getOperationNonIT().setType("deplacement-voiture-essence"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "deplacement-voiture-essence", + "categorie": "DEPLACEMENT_ESSENCE", + "refHypothese": "CONSO_MOYENNE_VOITURE_ESSENCE", + "refItemParDefaut": "fuel", + "source": "sourceDefault" + } + """, ReferentielTypeItem.class)); + + demandeCalcul.setHypotheses(List.of(objectMapper.readValue(""" + [ + { + "code": "CONSO_MOYENNE_VOITURE_ESSENCE", + "valeur": "6.5", + "source": "sourceDefault" + } + ] + """, ReferentielHypothese[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT( + demandeCalcul + ); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertNull(actual.getImpactUnitaire()); + assertEquals("ERREUR", actual.getStatutIndicateur()); + assertEquals(TestJsonUtils.format(""" + { + "erreur": "ErrCalcFonc : Référentiel Facteur Caractérisation inconnu" + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + @Test + void shouldCalculerImpactOperationNonIT_deplacementEssence_utilisation_withoutRefHypotheses_shouldReturnIndicateurWithError() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getEtape().setCode("UTILISATION"); + demandeCalcul.getOperationNonIT().setType("deplacement-voiture-essence"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "deplacement-voiture-essence", + "categorie": "DEPLACEMENT_ESSENCE", + "refHypothese": "CONSO_MOYENNE_VOITURE_ESSENCE", + "refItemParDefaut": "fuel", + "source": "sourceDefault" + } + """, ReferentielTypeItem.class)); + + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "fuel", + "etape": "FABRICATION", + "critere": "Changement Climatique", + "valeur" : 0.1 + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT( + demandeCalcul + ); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertNull(actual.getImpactUnitaire()); + assertEquals("ERREUR", actual.getStatutIndicateur()); + assertEquals(TestJsonUtils.format(""" + { + "erreur": "ErrCalcFonc : Il n'y a pas d'hypothese pour l'item pour la refHypothese 'CONSO_MOYENNE_VOITURE_ESSENCE' de l'item nomItem" + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + @Test + void shouldCalculerImpactOperationNonIT_deplacementHybride_utilisation() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getEtape().setCode("UTILISATION"); + demandeCalcul.getOperationNonIT().setType("deplacement-voiture-hybride"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "deplacement-voiture-hybride", + "categorie": "DEPLACEMENT_HYBRIDE", + "refHypothese": "CONSO_MOYENNE_VOITURE_ESSENCE", + "refItemParDefaut": "fuel", + "source": "sourceDefault" + } + """, ReferentielTypeItem.class)); + + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "fuel", + "etape": "FABRICATION", + "critere": "Changement Climatique", + "valeur" : 0.1 + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + demandeCalcul.setHypotheses(List.of(objectMapper.readValue(""" + [ + { + "code": "CONSO_MOYENNE_VOITURE_ESSENCE", + "valeur": "6.5", + "source": "sourceDefault" + }, + { + "code": "TAUX_VEHICULE_HYBRIDE", + "valeur": "0.85", + "source": "NosGestesClimat.com" + } + ] + """, ReferentielHypothese[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertEquals("OK", actual.getStatutIndicateur()); + assertEquals(0.5525, actual.getImpactUnitaire(), 0.0001d); + assertEquals(TestJsonUtils.format(""" + { + "formule" : "ImpactOperationNonIT = (ConsoMoyenne(6.5) * NbKmParcourus(1.0) * ReferentielFacteurCaracterisation(0.1) * TauxHybride(0.85))", + "hypothese" : { + "nom_hypothese" : "CONSO_MOYENNE_VOITURE_ESSENCE", + "source" : "sourceDefault", + "valeur" : 6.5 + }, + "valeurReferentielFacteurCaracterisation" : 0.1 + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + @Test + void shouldCalculerImpactOperationNonIT_deplacementHybride_utilisation_whithoutHypotheseTaux_shouldReturnIndicateurWithError() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getEtape().setCode("UTILISATION"); + demandeCalcul.getOperationNonIT().setType("deplacement-voiture-hybride"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "deplacement-voiture-hybride", + "categorie": "DEPLACEMENT_HYBRIDE", + "refHypothese": "CONSO_MOYENNE_VOITURE_ESSENCE", + "refItemParDefaut": "fuel", + "source": "sourceDefault" + } + """, ReferentielTypeItem.class)); + + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "fuel", + "etape": "FABRICATION", + "critere": "Changement Climatique", + "valeur" : 0.1 + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + demandeCalcul.setHypotheses(List.of(objectMapper.readValue(""" + [ + { + "code": "CONSO_MOYENNE_VOITURE_ESSENCE", + "valeur": "6.5", + "source": "sourceDefault" + } + ] + """, ReferentielHypothese[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertNull(actual.getImpactUnitaire()); + assertEquals("ERREUR", actual.getStatutIndicateur()); + assertEquals(TestJsonUtils.format(""" + { + "erreur": "ErrCalcFonc : Il n'y a pas de taux renseigné pour les véhicules hybrides dans la table des références" + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + @Test + void shouldCalculerImpactOperationNonIT_deplacementElectrique_utilisation() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getEtape().setCode("UTILISATION"); + demandeCalcul.getOperationNonIT().setType("deplacement-trot-elec"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "deplacement-trot-elec", + "categorie": "DEPLACEMENT_ELECTRIQUE", + "refHypothese": "CONSO_MOYENNE_TROTINETTE_ELECTRIQUE", + "source": "sourceDefault" + } + """, ReferentielTypeItem.class)); + + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "Electricty Mix France", + "etape": "FABRICATION", + "categorie": "electricity-mix", + "critere": "Changement Climatique", + "localisation": "France", + "valeur" : 0.1 + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + demandeCalcul.setHypotheses(List.of(objectMapper.readValue(""" + [ + { + "code": "CONSO_MOYENNE_TROTINETTE_ELECTRIQUE", + "valeur": "1.5", + "source": "sourceDefault" + } + ] + """, ReferentielHypothese[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertEquals("OK", actual.getStatutIndicateur()); + assertEquals(0.15000, actual.getImpactUnitaire(), 0.0001d); + assertEquals(TestJsonUtils.format(""" + { + "formule" : "ImpactOperationNonIT = (ConsoMoyenne(1.5) * NbKmParcourus(1.0) * MixElectrique(0.1))", + "mixElectrique" : { + "serveur" : false, + "valeur" : 0.1, + "valeurReferentielMixElectrique" : 0.1 + } + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + @Test + void shouldCalculerImpactOperationNonIT_deplacementElectrique_utilisation_whithoutMixElec_shouldReturnIndicateurWithError() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getEtape().setCode("UTILISATION"); + demandeCalcul.getOperationNonIT().setType("deplacement-trot-elec"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "deplacement-trot-elec", + "categorie": "DEPLACEMENT_ELECTRIQUE", + "refHypothese": "CONSO_MOYENNE_TROTINETTE_ELECTRIQUE", + "source": "sourceDefault" + } + """, ReferentielTypeItem.class)); + + demandeCalcul.setHypotheses(List.of(objectMapper.readValue(""" + [ + { + "code": "CONSO_MOYENNE_TROTINETTE_ELECTRIQUE", + "valeur": "1.5", + "source": "sourceDefault" + } + ] + """, ReferentielHypothese[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertNull(actual.getImpactUnitaire()); + assertEquals("ERREUR", actual.getStatutIndicateur()); + assertEquals(TestJsonUtils.format(""" + { + "erreur" : "ErrCalcFonc : Il n'existe pas de Mix électrique pour cet item non it : critere: Changement Climatique - operation non it: nomItem - Localisation: France" + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + @Test + void shouldCalculerImpactOperationNonIT_deplacementElectrique_utilisation_whithoutRefConso_shouldReturnIndicateurWithError() throws JsonProcessingException { + // Given + DemandeCalculImpactOperationNonIT demandeCalcul = createDemande(); + demandeCalcul.getEtape().setCode("UTILISATION"); + demandeCalcul.getOperationNonIT().setType("deplacement-trot-elec"); + demandeCalcul.setTypeItem(objectMapper.readValue(""" + { + "type": "deplacement-trot-elec", + "categorie": "DEPLACEMENT_ELECTRIQUE", + "refHypothese": "CONSO_MOYENNE_TROTINETTE_ELECTRIQUE", + "source": "sourceDefault" + } + """, ReferentielTypeItem.class)); + + demandeCalcul.setFacteurCaracterisations(List.of(objectMapper.readValue(""" + [ + { + "nom": "Electricty Mix France", + "etape": "FABRICATION", + "categorie": "electricity-mix", + "critere": "Changement Climatique", + "localisation": "France", + "valeur" : 0.1 + } + ] + """, ReferentielFacteurCaracterisation[].class))); + + // When + var actual = calculImpactOperationNonITService.calculerImpactOperationNonIT(demandeCalcul); + + // Then + assertContentIndicateur(demandeCalcul, actual); + assertNull(actual.getImpactUnitaire()); + assertEquals("ERREUR", actual.getStatutIndicateur()); + assertEquals(TestJsonUtils.format(""" + { + "erreur" : "ErrCalcFonc : Il n'y a pas d'hypothese pour l'item pour la refHypothese 'CONSO_MOYENNE_TROTINETTE_ELECTRIQUE' de l'item nomItem" + } + """), + TestJsonUtils.format(actual.getTrace())); + } + + private void assertContentIndicateur(DemandeCalculImpactOperationNonIT source, ImpactOperationNonIT result) { + assertNotNull(result); + assertEquals(source.getOperationNonIT().getNomItemNonIT(), result.getNomItemNonIT()); + assertEquals(source.getOperationNonIT().getType(), result.getTypeItem()); + assertEquals(source.getOperationNonIT().getQuantite(), result.getQuantite()); + + + assertEquals(source.getOperationNonIT().getNomLot(), result.getNomLot()); + assertEquals(source.getOperationNonIT().getDateLot(), result.getDateLot()); + assertEquals(source.getOperationNonIT().getNomOrganisation(), result.getNomOrganisation()); + assertEquals(source.getOperationNonIT().getNomEntite(), result.getNomEntite()); + + assertEquals(source.getDateCalcul(), result.getDateCalcul()); + + assertEquals(source.getCritere().getNomCritere(), result.getCritere()); + assertEquals(source.getEtape().getCode(), result.getEtapeACV()); + assertEquals(source.getCritere().getUnite(), result.getUnite()); + + assertEquals("1.0", result.getVersionCalcul()); + } +} \ No newline at end of file diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactReseauServiceTest.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactReseauServiceTest.java index b20da91b6a9a25f4002b55a72f0a85b3e4a8a339..5ae06bb4b352c4a42b7706847253c733192f4163 100644 --- a/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactReseauServiceTest.java +++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/domain/service/CalculImpactReseauServiceTest.java @@ -1,9 +1,7 @@ package org.mte.numecoeval.calculs.domain.service; -import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.MockitoAnnotations; import org.mte.numecoeval.calculs.domain.data.demande.DemandeCalculImpactReseau; import org.mte.numecoeval.calculs.domain.data.entree.EquipementPhysique; import org.mte.numecoeval.calculs.domain.data.indicateurs.ImpactReseau; @@ -25,12 +23,9 @@ class CalculImpactReseauServiceTest { private CalculImpactReseauService calculImpactService; - ObjectMapper objectMapper = new ObjectMapper(); - @BeforeEach void setUp() { - MockitoAnnotations.openMocks(this); - calculImpactService = new CalculImpactReseauServiceImpl(objectMapper); + calculImpactService = new CalculImpactReseauServiceImpl(); } @Test @@ -45,7 +40,7 @@ class CalculImpactReseauServiceTest { .unite("kg CO_{2} eq") .build(); EquipementPhysique equipementPhysique = EquipementPhysique.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -92,7 +87,7 @@ class CalculImpactReseauServiceTest { .unite("kg CO_{2} eq") .build(); EquipementPhysique equipementPhysique = EquipementPhysique.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -121,7 +116,7 @@ class CalculImpactReseauServiceTest { void shouldReturnError_whenInvalidReference() { //Given EquipementPhysique equipementPhysique = EquipementPhysique.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") @@ -162,13 +157,13 @@ class CalculImpactReseauServiceTest { void shouldReturnError_whenReferenceNotFound() { //Given EquipementPhysique equipementPhysique = EquipementPhysique.builder() - .dateLot(LocalDate.of(2022,1,1)) + .dateLot(LocalDate.of(2022, 1, 1)) .nomOrganisation("Test") .nomLot("Test|20220101") .nomSourceDonnee("Source_Test") .nomEquipementPhysique("Equipement 1") .goTelecharge(4.0f) - .dateLot(LocalDate.of(2023,1,1)) + .dateLot(LocalDate.of(2023, 1, 1)) .build(); ReferentielEtapeACV etapeACV = ReferentielEtapeACV.builder() .code("UTILISATION") diff --git a/services/calculs/src/test/java/org/mte/numecoeval/calculs/steps/CalculImpactEquipementVirtuelStepDefinitions.java b/services/calculs/src/test/java/org/mte/numecoeval/calculs/steps/CalculImpactEquipementVirtuelStepDefinitions.java index fb172819f5c5d2bd15810f9bbde0b8583df10607..7cc4872c731bb0e968382bec43f21ea365005a98 100644 --- a/services/calculs/src/test/java/org/mte/numecoeval/calculs/steps/CalculImpactEquipementVirtuelStepDefinitions.java +++ b/services/calculs/src/test/java/org/mte/numecoeval/calculs/steps/CalculImpactEquipementVirtuelStepDefinitions.java @@ -1,6 +1,5 @@ package org.mte.numecoeval.calculs.steps; -import com.fasterxml.jackson.databind.ObjectMapper; import io.cucumber.datatable.DataTable; import io.cucumber.java.fr.Alors; import io.cucumber.java.fr.Soit; @@ -16,7 +15,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; public class CalculImpactEquipementVirtuelStepDefinitions { DemandeCalculImpactEquipementVirtuel demandeCalculCourante; - + @Soit("Une demande de calcul pour un équipement virtuel tel que") public void initDemandeCalculEquipementVirtuel(DemandeCalculImpactEquipementVirtuel demande) { demandeCalculCourante = demande; @@ -24,7 +23,7 @@ public class CalculImpactEquipementVirtuelStepDefinitions { @Alors("l'impact d'équipement virtuel résultant est tel que") public void checkImpactEquipementVirtuel(DataTable dataTable) { - CalculImpactEquipementVirtuelService service = new CalculImpactEquipementVirtuelServiceImpl(new ObjectMapper()); + CalculImpactEquipementVirtuelService service = new CalculImpactEquipementVirtuelServiceImpl(); var result = assertDoesNotThrow(() -> service.calculerImpactEquipementVirtuel(demandeCalculCourante)); assertNotNull(result); diff --git a/services/common/src/main/resources/static/api-event-calculs-async-openapi.yaml b/services/common/src/main/resources/static/api-event-calculs-async-openapi.yaml index 2d849a925c872dd0f334a5e254848b81868a0379..c5c6fe06d77dc68ef443f8457454cc116c7e00cb 100644 --- a/services/common/src/main/resources/static/api-event-calculs-async-openapi.yaml +++ b/services/common/src/main/resources/static/api-event-calculs-async-openapi.yaml @@ -13,6 +13,8 @@ tags: description: Endpoints liés aux calculs pour un équipement virtuel - name: Calculs Application description: Endpoints liés aux calculs pour une application + - name: Calculs OperationNonIT + description: Endpoints liés aux calculs pour une opération non IT - name: Calculs Messagerie description: Endpoints liés aux calculs pour un élément de messagerie - name: Calculs Reseau @@ -152,6 +154,39 @@ paths: 'application/json': schema: $ref: "#/components/schemas/IndicateurImpactApplicationRest" + /calculs/operationNonIT: + post: + summary: Endpoint pour le calcul unitaire d'impact écologique pour une opération Non IT. + description: | + Endpoint pour le calcul unitaire d'impact écologique pour une opération Non IT. + tags: + - Calculs OperationNonIT + operationId: calculerImpactOperationNonIT + requestBody: + required: true + content: + 'application/json': + schema: + $ref: "#/components/schemas/DemandeCalculImpactOperationNonITRest" + responses: + "500": + description: Erreur interne du service + content: + 'application/json': + schema: + $ref: "#/components/schemas/ErreurRest" + "400": + description: Indicateur en erreur + content: + 'application/json': + schema: + $ref: "#/components/schemas/IndicateurImpactOperationNonITRest" + "200": + description: Indicateur calculé. + content: + 'application/json': + schema: + $ref: "#/components/schemas/IndicateurImpactOperationNonITRest" /calculs/messagerie: post: summary: Endpoint pour le calcul unitaire d'impact écologique pour un élément de messagerie. @@ -345,6 +380,42 @@ components: sousDomaine: description: "" type: string + OperationNonITRest: + description: Représentation d'opérations non IT dans NumEcoEval + properties: + nomItemNonIT: + description: "" + type: string + quantite: + description: "" + type: number + format: double + type: + description: "" + type: string + dureeDeVie: + description: "" + type: number + format: double + localisation: + description: "" + type: string + nomEntite: + description: "" + type: string + nomSourceDonnee: + description: "Nom de la source de la donnée" + type: string + nomCourtDatacenter: + description: "" + type: string + description: + description: "" + type: string + consoElecAnnuelle: + description: "" + type: number + format: double MessagerieRest: description: Représentation d'éléments de messagerie dans NumEcoEval properties: @@ -393,6 +464,27 @@ components: refEquipementParDefaut: type: string description: Référentiel de type d'équipement physique. + TypeItemRest: + type: object + properties: + type: + type: string + categorie: + type: string + serveur: + type: boolean + commentaire: + type: string + dureeVieDefaut: + type: number + format: double + refCosoMoyenne: + type: string + source: + type: string + refItemParDefaut: + type: string + description: Référentiel des types d'item. HypotheseRest: type: object properties: @@ -467,6 +559,36 @@ components: type: number format: double description: Référentiel d'impact écologique pour un équipement physique + FacteurCaracterisationRest: + type: object + description: Référentiel des facteurs de caractérisation pour un item + properties: + nom: + type: string + etape: + type: string + critere: + type: string + niveau: + type: string + tiers: + type: string + categorie: + type: string + source: + type: string + valeur: + type: number + format: double + unite: + type: string + consoElecMoyenne: + type: number + format: double + localisation: + type: string + description: + type: string ImpactMessagerieRest: type: object description: Référentiel - L'équation d'impact est une fonction affine de la forme a * x + b @@ -649,6 +771,49 @@ components: consoElecMoyenne: type: number format: double + IndicateurImpactOperationNonITRest: + type: object + properties: + dateCalcul: + type: string + description: "Date et Heure du calcul, même valeur pour tous les indicateurs\ + \ créés avec le même lot d'objets d'entrées" + format: date-time + versionCalcul: + type: string + etapeACV: + type: string + description: "Code de l'étape ACV associé à l'indicateur, peut être null\ + \ pour certains indicateurs" + critere: + type: string + description: "Nom du critère associé à l'indicateur, peut être null pour\ + \ certains indicateurs" + statutIndicateur: + type: string + description: "Statut de l'indicateur, vaut \"OK\" si l'indicateur est calcul\ + \ et \"ERREUR\" si l'indicateur est en erreur" + trace: + type: string + description: Trace du calcul ayant produit l'indicateur + unite: + type: string + description: "Unite du critère associé, peut être null" + nomItemNonIT: + type: string + typeItem: + type: string + impactUnitaire: + type: number + format: double + consoElecMoyenne: + type: number + format: double + quantite: + type: integer + format: int32 + statutItem: + type: string IndicateurImpactMessagerieRest: description: Indicateur d'impact de messagerie properties: @@ -775,6 +940,27 @@ components: type: integer impactEquipementVirtuel: $ref: "#/components/schemas/IndicateurImpactEquipementVirtuelRest" + DemandeCalculImpactOperationNonITRest: + description: Objet regroupant toutes les données pour le calcul des indicateurs d'impact des opérations non it dans NumEcoEval + type: object + properties: + operationNonIT: + $ref: "#/components/schemas/OperationNonITRest" + typeItem: + $ref: "#/components/schemas/TypeItemRest" + hypotheses: + type: array + items: + $ref: "#/components/schemas/HypotheseRest" + etape: + $ref: "#/components/schemas/EtapeRest" + critere: + $ref: "#/components/schemas/CritereRest" + facteurCaracterisations: + description: Facteur de caractérisation de l'item + type: array + items: + $ref: "#/components/schemas/FacteurCaracterisationRest" DemandeCalculMessagerieRest: description: Objet regroupant toutes les données pour le calcul des indicateurs d'impact de messagerie dans NumEcoEval type: object diff --git a/services/common/src/main/resources/static/api-event-calculs-sync-openapi.yaml b/services/common/src/main/resources/static/api-event-calculs-sync-openapi.yaml index fc99e3ad7b1bc92c41175d0d6c21fd576af7237c..f91664302e28929444f4589cc729456a4346e6e4 100644 --- a/services/common/src/main/resources/static/api-event-calculs-sync-openapi.yaml +++ b/services/common/src/main/resources/static/api-event-calculs-sync-openapi.yaml @@ -9,11 +9,11 @@ info: paths: /sync/calculs: post: - summary: Endpoint pour le calcul unitaire d'impact écologique synchrone pour une liste d'id d'équipements physiques et de messageries. + summary: Endpoint pour le calcul unitaire d'impact écologique synchrone pour une liste d'id d'équipements physiques, d'opérations non IT et de messageries. description: | - Endpoint pour le calcul unitaire d'impact écologique pour un équipement physique. + Endpoint pour le calcul unitaire d'impact écologique pour un équipement physique, une opération non IT et une messagerie. tags: - - Calculs Equipement Physique et Messagerie + - Calculs Equipement Physique et Operation non IT et Messagerie operationId: syncCalculByIds requestBody: required: true @@ -55,7 +55,7 @@ components: format: date-time # Entrées SyncCalculRest: - description: Représentation d'un équipement physique dans NumEcoEval + description: Représentation d'un équipement physique, d'une opération non IT et d'une messagerie dans NumEcoEval type: object properties: equipementPhysiqueIds: @@ -64,6 +64,12 @@ components: items: type: integer format: int64 + operationNonITIds: + description: "" + type: array + items: + type: integer + format: int64 messagerieIds: description: "" type: array @@ -85,8 +91,12 @@ components: nbrApplication: type: integer format: int64 - description: "Nombre total d'applications traités" + description: "Nombre total d'applications traitées" + nbrOperationNonIT: + type: integer + format: int64 + description: "Nombre total d'opérations non IT traitées" nbrMessagerie: type: integer format: int64 - description: "Nombre total de messageries traités" + description: "Nombre total de messageries traitées" diff --git a/services/common/src/main/resources/static/api-referentiels-openapi.yaml b/services/common/src/main/resources/static/api-referentiels-openapi.yaml index d6e764c017f0a83ce97f2515f85222f9281eab4a..9a754523437ec3bbb716886b1a673e2104e081d5 100644 --- a/services/common/src/main/resources/static/api-referentiels-openapi.yaml +++ b/services/common/src/main/resources/static/api-referentiels-openapi.yaml @@ -20,6 +20,86 @@ externalDocs: description: NumEcoEval Documentation url: https://gitlab-forge.din.developpement-durable.gouv.fr/pub/numeco/m4g/docs paths: + /referentiel/typeItem/csv: + get: + tags: + - Export Référentiels + summary: Exporter les impacts des types d'items sous format csv + description: | + <ul> + <li>Entrée : Aucune </li> + <li>Sortie : Renvoie la liste des étapes de ref_TypeItem </li> + </ul> + operationId: exportTypeItemCSV + responses: + '200': + description: OK + '400': + description: Bad Request + content: + application/hal+json: + schema: + $ref: '#/components/schemas/ErrorResponseDTO' + '404': + description: Not Found + content: + application/hal+json: + schema: + $ref: '#/components/schemas/ErrorResponseDTO' + '500': + description: Internal Server Error + content: + application/hal+json: + schema: + $ref: '#/components/schemas/ErrorResponseDTO' + post: + tags: + - Import Référentiels + summary: 'Alimentation du référentiel Type Item par csv : annule et remplace.' + description: | + Le référentiel est global à tout le système. L’import se fait uniquement avec un fichier CSV. + Lors de l’import, les données précédentes sont supprimées. + <ul> + <li>Entrée : Le fichier CSV du référentiel</li> + <li>Sortie : Rapport du fichier CSV (nombre de lignes totales, nombre de lignes en erreur, nombre de lignes traitées, liste des erreurs par lignes).</li> + </ul> + operationId: importTypeItemCSV + requestBody: + content: + multipart/form-data: + schema: + required: + - file + type: object + properties: + file: + type: string + format: binary + responses: + '200': + description: Rapport d'import du fichier CSV + content: + application/hal+json: + schema: + $ref: '#/components/schemas/RapportImportDTO' + '400': + description: Invalid request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponseDTO' + '404': + description: Not Found + content: + application/hal+json: + schema: + $ref: '#/components/schemas/ErrorResponseDTO' + '500': + description: Internal Server Error + content: + application/hal+json: + schema: + $ref: '#/components/schemas/ErrorResponseDTO' /referentiel/typeEquipement/csv: get: tags: @@ -862,6 +942,86 @@ paths: application/hal+json: schema: $ref: '#/components/schemas/ErrorResponseDTO' + /referentiel/typesItem: + get: + tags: + - Interne NumEcoEval + summary: Endpoint interne à NumEcoEval - Récupération de tous les types d'items + description: | + Endpoint interne utilisé à la réception de données d'entrées par le module api-expositiondonneesentrees de NumEcoEval. + Renvoie l'intégralité des types d'items utilisables par NumEcoEval. + + Les types d'items servent notamment à alimenter la durée de vie par défaut des items + reçues. + operationId: getAllTypeItem + responses: + '200': + description: Types Item + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/TypeItemDTO' + '400': + description: Invalid request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponseDTO' + '404': + description: Types Item non trouvé + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponseDTO' + '500': + description: Internal Server Error + content: + application/hal+json: + schema: + $ref: '#/components/schemas/ErrorResponseDTO' + /referentiel/typesItem/{type}: + get: + tags: + - Interne NumEcoEval + summary: Endpoint interne à NumEcoEval - Récupération d'items via leur type + description: | + Endpoint interne utilisé à la réception de données d'entrées par le module api-expositiondonneesentrees de NumEcoEval. Renvoie l'intégralité des types d'items d'un certain type. + operationId: getTypeItem + parameters: + - name: type + in: path + description: type recherché + required: true + schema: + type: string + description: type recherché + responses: + '200': + description: Types Item + content: + application/json: + schema: + $ref: '#/components/schemas/TypeItemDTO' + '400': + description: Invalid request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponseDTO' + '404': + description: Types Item non trouvé + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponseDTO' + '500': + description: Internal Server Error + content: + application/hal+json: + schema: + $ref: '#/components/schemas/ErrorResponseDTO' /referentiel/typesEquipement: get: tags: @@ -1292,46 +1452,64 @@ paths: get: tags: - Interne NumEcoEval - summary: Endpoint interne à NumEcoEval - Récupération d'un Facteur de Caractérisation + summary: Endpoint interne à NumEcoEval - Récupération des Facteurs de Caractérisation description: | Endpoint interne utilisé dans la génération des indicateurs par le module api-calcul de NumEcoEval. - Récupération d'un impact équipement en fonction de 3 paramètres: + Récupération des Facteurs de Caractérisation en fonction de 5 paramètres: <ul> - <li>Le nom du facteur de caractérisation: nom</li> - <li>L'étape ACV: etape</li> - <li>Le critère d'impact: critere</li> + <li>Le nom du critère d'impact écologique: critere</li> + <li>Le code de l'étape ACV: etapeacv</li> + <li>Le nom du facteur de caractérisation recherché: nom</li> + <li>La localisation: localisation</li> + <li>La catégorie: categorie</li> </ul> . operationId: getFacteurCaracterisation parameters: - - name: nom - in: query - description: Nom du facteur de caractérisation recherché - required: true - schema: - type: string - description: Nom du facteur de caractérisation recherché - name: critere in: query description: Nom du critère d'impact écologique - required: true + required: false schema: type: string description: Nom du critère d'impact écologique - name: etapeacv in: query description: Code de l'étape ACV - required: true + required: false schema: type: string description: Code de l'étape ACV + - name: nom + in: query + description: Nom du facteur de caractérisation recherché + required: false + schema: + type: string + description: Nom du facteur de caractérisation recherché + - name: localisation + in: query + description: Nom de la localisation + required: false + schema: + type: string + description: Nom de la localisation + - name: categorie + in: query + description: Nom de la catégorie + required: false + schema: + type: string + description: Nom de la catégorie responses: '200': - description: Facteur Caractérisation trouvé + description: Liste des Facteurs de Caractérisation trouvés content: application/json: schema: - $ref: '#/components/schemas/FacteurCaracterisationDTO' + type: array + items: + $ref: '#/components/schemas/FacteurCaracterisationDTO' '400': description: Invalid request content: @@ -1567,6 +1745,35 @@ components: type: string description: La version description: Version applicative + TypeItemDTO: + type: object + properties: + type: + type: string + description: Type d'item, clé du référentiel + categorie: + type: string + description: Catégorie de l'item + serveur: + type: boolean + description: Flag indiquant si l'item est un serveur + commentaire: + type: string + description: Commentaire de l'entrée dans le référentiel + dureeVieDefaut: + type: number + description: Durée de vie par défaut de ce type d'item + format: double + refHypothese: + type: string + description: Référence vers l'hypothèse nécessaire pour le calcul d'impact de cet item + source: + type: string + description: Source de l'information du référentiel + refItemParDefaut: + type: string + description: Référence de l'item par défaut, permet des correspondances en cas d'absence de correspondance directe + description: Référentiel des types d'items utilisables dans le système. La clé du référentiel est le champ type. TypeEquipementDTO: type: object properties: @@ -1698,6 +1905,9 @@ components: source: type: string description: Source de l'hypothèse + description: + type: string + description: Description de l'hypothèse description: Référentiel des hypothèses utilisées pour les calculs FacteurCaracterisationDTO: type: object diff --git a/services/common/src/main/resources/static/asyncapi_merge.yaml b/services/common/src/main/resources/static/asyncapi_merge.yaml index b92b45a095c8ac4a977d6e0e92d074a78edccbc9..b8c6c9dad75e007b4f94456613ebbc7d6ddd1181 100644 --- a/services/common/src/main/resources/static/asyncapi_merge.yaml +++ b/services/common/src/main/resources/static/asyncapi_merge.yaml @@ -22,5 +22,9 @@ components: $ref: "./asyncapi_equipement_physique.yaml#/components/schemas/EquipementPhysiqueDTO" DataCenterDTO: $ref: "./asyncapi_equipement_physique.yaml#/components/schemas/DataCenterDTO" + CalculOperationNonITDTO: + $ref: "./asyncapi_operation_non_it.yaml#/components/schemas/CalculOperationNonITDTO" + OperationNonITDTO: + $ref: "./asyncapi_operation_non_it.yaml#/components/schemas/OperationNonITDTO" MessagerieDTO: $ref: "./asyncapi_messagerie.yaml#/components/schemas/MessagerieDTO" diff --git a/services/common/src/main/resources/static/asyncapi_operation_non_it.yaml b/services/common/src/main/resources/static/asyncapi_operation_non_it.yaml new file mode 100644 index 0000000000000000000000000000000000000000..594eb70c3ed1f427420df364f8c449ac614c8aa6 --- /dev/null +++ b/services/common/src/main/resources/static/asyncapi_operation_non_it.yaml @@ -0,0 +1,208 @@ +asyncapi: 2.6.0 +info: + title: api-event-calcul-enrichissement-opnonit + version: '1.0' + description: | + Lecture d'une opération non it + puis récupération des référentiels nécessaires au calcul via REST + puis production d'un message pour demande de calcul d'impacts de l'opération non IT +servers: + bootstrap: + url: localhost:9092 + protocol: kafka +channels: + entree_operationNonIT: + description: Topic d'envoi des données d'entrées pour les opérations non IT à enrichir + publish: + message: + $ref: '#/components/messages/EntreeOperationNonIT' + calcul_operationNonIT: + description: Topic d'envoi des données d'entrées pour les opérations non IT à calculer + subscribe: + message: + $ref: '#/components/messages/CalculOperationNonIT' +components: + messages: + EntreeOperationNonIT: + name: EntreeOperationNonIT + title: Message des données d'entrée pour une opération non IT dans NumEcoEval + summary: Données d'une opération non it pour un calcul dans NumEcoEval + contentType: application/json + payload: + $ref: "#/components/schemas/OperationNonITDTO" + CalculOperationNonIT: + name: CalculOperationNonIT + title: Message pour le calcul d'impact d'une opération non it + summary: Intégralité des données permettant le calcul d'une opération non it pour un calcul dans NumEcoEval + contentType: application/json + payload: + $ref: "#/components/schemas/CalculOperationNonITDTO" + schemas: + CalculOperationNonITDTO: + $id: CalculOperationNonITDTO + description: Objet regroupant toutes les données pour le calcul des indicateurs d'une opération non it dans NumEcoEval + type: object + properties: + operationNonIT: + $ref: "#/components/schemas/OperationNonITDTO" + typeItem: + description: Référentiel rattaché au type d'item de l'opération non it + $ref: "#/components/schemas/TypeItemDTO" + hypotheses: + description: Hypothèses disponibles pour le calcul + type: array + items: + $ref: "#/components/schemas/HypotheseDTO" + etapes: + description: Référentiels des Étapes ACV + type: array + items: + $ref: "#/components/schemas/EtapeDTO" + criteres: + description: Référentiels des Critères d'impact écologiques + type: array + items: + $ref: "#/components/schemas/CritereDTO" + facteurCaracterisation: + description: Facteur de caracterisation de l'item + type: array + items: + $ref: "#/components/schemas/FacteurCaracterisationDTO" + OperationNonITDTO: + $id: OperationNonITDTO + description: Représentation d'une opération non it dans NumEcoEval + type: object + properties: + id: + description: "" + type: integer + format: int64 + nomItemNonIT: + description: "" + type: string + quantite: + description: "" + type: number + format: double + type: + description: "" + type: string + dureeDeVie: + description: "" + type: number + format: double + localisation: + description: "" + type: string + nomEntite: + description: "" + type: string + nomSourceDonnee: + description: "Nom de la source de la donnée" + type: string + nomCourtDatacenter: + description: "" + type: string + description: + description: "" + type: string + consoElecAnnuelle: + description: "" + type: number + format: double + nomLot: + description: "Nom du lot rattaché" + type: string + dateLot: + description: "" + type: string + format: date + nomOrganisation: + description: "" + type: string + TypeItemDTO: + type: object + properties: + type: + type: string + categorie: + type: string + serveur: + type: boolean + commentaire: + type: string + dureeVieDefaut: + type: number + format: double + refCosoMoyenne: + type: string + source: + type: string + refItemParDefaut: + type: string + description: Référentiel des types d'item. + HypotheseDTO: + type: object + properties: + code: + type: string + valeur: + type: string + source: + type: string + description: + type: string + EtapeDTO: + type: object + properties: + code: + type: string + libelle: + type: string + CritereDTO: + type: object + properties: + nomCritere: + type: string + description: Nom du critère d'impact écologique + unite: + type: string + description: Unité du critère d'impact écologique + description: + type: string + description: Description du critère d'impact écologique + FacteurCaracterisationDTO: + type: object + properties: + nom: + type: string + etape: + type: string + critere: + type: string + niveau: + type: string + tiers: + type: string + categorie: + type: string + source: + type: string + valeur: + type: number + format: double + unite: + type: string + consoElecMoyenne: + type: number + format: double + localisation: + type: string + description: + type: string + description: Référentiel des facteurs de caractérisation pour un item + operationTraits: + kafka: + bindings: + kafka: + groupId: api-event-calcul-enrichissement-opnonit