diff --git "a/packages/applications/legacy/src/views/components/UI/organisms/menuLegacy/AcheteurOblig\303\251MenuLegacy.tsx" "b/packages/applications/legacy/src/views/components/UI/organisms/menuLegacy/AcheteurOblig\303\251MenuLegacy.tsx" index 60c2e2f090..34fee67fa8 100644 --- "a/packages/applications/legacy/src/views/components/UI/organisms/menuLegacy/AcheteurOblig\303\251MenuLegacy.tsx" +++ "b/packages/applications/legacy/src/views/components/UI/organisms/menuLegacy/AcheteurOblig\303\251MenuLegacy.tsx" @@ -3,6 +3,7 @@ import React from 'react'; import { DropdownMenu } from '../../molecules/dropdowns/DropdownMenu'; import { Routes } from '@potentiel-applications/routes'; import { MenuLegacyProjet } from './_utils/projet.menuLegacy'; +import { Header } from '../Header'; // viovio je crois que je peux supprimer tout ça export const AcheteurObligéMenuLegacy = ( @@ -46,5 +47,11 @@ export const AcheteurObligéMenuLegacy = ( Nom projet + + + Tous les dossiers de raccordement + + + Export de données ); diff --git a/packages/applications/legacy/src/views/components/UI/organisms/menuLegacy/AdminMenuLegacy.tsx b/packages/applications/legacy/src/views/components/UI/organisms/menuLegacy/AdminMenuLegacy.tsx index 2fe91ce9dc..946e318dc9 100644 --- a/packages/applications/legacy/src/views/components/UI/organisms/menuLegacy/AdminMenuLegacy.tsx +++ b/packages/applications/legacy/src/views/components/UI/organisms/menuLegacy/AdminMenuLegacy.tsx @@ -112,6 +112,9 @@ export const AdminMenuLegacy = ( Gérer les gestionnaires de réseau + + Export de données + ); diff --git a/packages/applications/legacy/src/views/components/UI/organisms/menuLegacy/CreMenuLegacy.tsx b/packages/applications/legacy/src/views/components/UI/organisms/menuLegacy/CreMenuLegacy.tsx index 8376efffd7..fdab3d0bc2 100644 --- a/packages/applications/legacy/src/views/components/UI/organisms/menuLegacy/CreMenuLegacy.tsx +++ b/packages/applications/legacy/src/views/components/UI/organisms/menuLegacy/CreMenuLegacy.tsx @@ -58,6 +58,7 @@ export const CreMenuLegacy = ( Raccordements + Export de données Tableau de bord diff --git a/packages/applications/routes/src/export/export.routes.ts b/packages/applications/routes/src/export/export.routes.ts new file mode 100644 index 0000000000..14568629a3 --- /dev/null +++ b/packages/applications/routes/src/export/export.routes.ts @@ -0,0 +1 @@ +export const page = `/export`; diff --git a/packages/applications/routes/src/export/index.ts b/packages/applications/routes/src/export/index.ts new file mode 100644 index 0000000000..019ad7c034 --- /dev/null +++ b/packages/applications/routes/src/export/index.ts @@ -0,0 +1 @@ +export * as Export from './export.routes'; diff --git a/packages/applications/routes/src/index.ts b/packages/applications/routes/src/index.ts index 66a8d32249..413e3dcf32 100644 --- a/packages/applications/routes/src/index.ts +++ b/packages/applications/routes/src/index.ts @@ -26,6 +26,7 @@ import { Auth } from './auth'; import { StatistiquesPubliques } from './statistiques-publiques'; import { Utilisateur } from './utilisateur'; import { Accès } from './accès'; +import { Export } from './export'; export const Routes = { Abandon, @@ -55,4 +56,5 @@ export const Routes = { Installation, NatureDeLExploitation, Éliminé, + Export, }; diff --git "a/packages/applications/routes/src/laur\303\251at/raccordement.routes.ts" "b/packages/applications/routes/src/laur\303\251at/raccordement.routes.ts" index 9d8aa16cfa..9463cc1d72 100644 --- "a/packages/applications/routes/src/laur\303\251at/raccordement.routes.ts" +++ "b/packages/applications/routes/src/laur\303\251at/raccordement.routes.ts" @@ -62,3 +62,5 @@ export const modifierDateMiseEnService = ( `/laureats/${encodeParameter(identifiantProjet)}/raccordements/${encodeParameter( référenceDossierRaccordement, )}/date-mise-en-service:modifier`; + +export const exporter = `/reseaux/raccordements/exporter`; diff --git a/packages/applications/ssr/src/app/export/export.page.tsx b/packages/applications/ssr/src/app/export/export.page.tsx new file mode 100644 index 0000000000..03f10dc21f --- /dev/null +++ b/packages/applications/ssr/src/app/export/export.page.tsx @@ -0,0 +1,23 @@ +import { FC } from 'react'; + +import { Routes } from '@potentiel-applications/routes'; + +import { PageTemplate } from '@/components/templates/Page.template'; +import { Heading1 } from '@/components/atoms/headings'; +import { LinkAction } from '@/components/atoms/LinkAction'; + +export type ExportPageProps = { + actions: Array<'exporter-raccordement'>; +}; + +export const ExportPage: FC = ({ actions }) => ( + Exporter des données projets}> +
+ Cette page permet d'accéder à des liens pour exporter des données projets +
+ + {actions.includes('exporter-raccordement') && ( + + )} +
+); diff --git a/packages/applications/ssr/src/app/export/page.tsx b/packages/applications/ssr/src/app/export/page.tsx new file mode 100644 index 0000000000..0f4d642627 --- /dev/null +++ b/packages/applications/ssr/src/app/export/page.tsx @@ -0,0 +1,31 @@ +import type { Metadata } from 'next'; + +import { PotentielUtilisateur } from '@potentiel-applications/request-context'; + +import { PageWithErrorHandling } from '@/utils/PageWithErrorHandling'; +import { withUtilisateur } from '@/utils/withUtilisateur'; + +import { ExportPage, ExportPageProps } from './export.page'; + +export const metadata: Metadata = { + title: 'Export de données - Potentiel', + description: `Page d'export des données au format CSV`, +}; + +export default async function Page() { + return PageWithErrorHandling(async () => + withUtilisateur(async (utilisateur) => { + return ; + }), + ); +} + +type MapToAction = (utilisateur: PotentielUtilisateur) => ExportPageProps['actions']; + +const mapToAction: MapToAction = (utilisateur) => { + if (utilisateur.rôle.aLaPermission('raccordement.listerDossierRaccordement')) { + return ['exporter-raccordement']; + } + + return []; +}; diff --git a/packages/applications/ssr/src/app/reseaux/raccordements/exporter/route.ts b/packages/applications/ssr/src/app/reseaux/raccordements/exporter/route.ts new file mode 100644 index 0000000000..850944e4ca --- /dev/null +++ b/packages/applications/ssr/src/app/reseaux/raccordements/exporter/route.ts @@ -0,0 +1,85 @@ +import { Parser, ParserOptions } from '@json2csv/plainjs'; +import { mediator } from 'mediateur'; + +import { Lauréat } from '@potentiel-domain/projet'; + +import { withUtilisateur } from '@/utils/withUtilisateur'; +import { apiAction } from '@/utils/apiAction'; + +export const GET = async (_: Request) => + apiAction(() => + withUtilisateur(async (utilisateur) => { + const dossiers = await mediator.send({ + type: 'Lauréat.Raccordement.Query.ListerDossierRaccordementQuery', + data: { + utilisateur: utilisateur.identifiantUtilisateur.email, + }, + }); + + const fields: ParserOptions['fields'] = [ + { label: 'Identifiant projet', value: 'identifiantProjet' }, + { label: "Appel d'offre", value: 'appelOffre' }, + { label: 'Période', value: 'periode' }, + { label: 'Nom projet', value: 'nomProjet' }, + { label: 'Référence dossier', value: 'referenceDossier' }, + { label: 'Date demande complète raccordement', value: 'dateDemandeCompleteRaccordement' }, + { label: 'Date mise en service', value: 'dateMiseEnService' }, + { label: 'Gestionnaire réseau', value: 'gestionnaireReseau' }, + { label: 'Site de production', value: 'siteProduction' }, + { label: 'Société mère', value: 'societeMere' }, + { label: 'Puissance', value: 'puissance' }, + ]; + + const utilisateurPeutVoirPrix = utilisateur.rôle.aLaPermission('projet.accèsDonnées.prix'); + + if (utilisateurPeutVoirPrix) { + fields.push({ label: 'Prix de référence', value: 'prixReference' }); + } + + const csvParser = new Parser({ fields, delimiter: ';', withBOM: true }); + + const csv = csvParser.parse( + dossiers.items.map( + ({ + identifiantProjet, + nomProjet, + référenceDossier, + puissance, + unitéPuissance, + sociétéMère, + dateDemandeComplèteRaccordement, + dateMiseEnService, + raisonSocialeGestionnaireRéseau, + localité: { adresse1, adresse2, codePostal, commune, région, département }, + prixReference, + }) => ({ + identifiantProjet: identifiantProjet.formatter(), + appelOffre: identifiantProjet.appelOffre, + periode: identifiantProjet.période, + nomProjet, + referenceDossier: référenceDossier.formatter(), + dateDemandeCompleteRaccordement: dateDemandeComplèteRaccordement + ? dateDemandeComplèteRaccordement.date.toLocaleDateString('fr-FR') + : undefined, + dateMiseEnService: dateMiseEnService + ? dateMiseEnService.date.toLocaleDateString('fr-FR') + : undefined, + gestionnaireReseau: raisonSocialeGestionnaireRéseau, + siteProduction: `${adresse1} ${adresse2} ${codePostal} ${commune} - ${département} - ${région}`, + societeMere: sociétéMère, + puissance: `${puissance} ${unitéPuissance.formatter()}`, + prixReference: utilisateurPeutVoirPrix ? prixReference : undefined, + }), + ), + ); + + const fileName = `export_projet_raccordement.csv`; + + return new Response(csv, { + headers: { + 'content-type': 'text/csv', + 'content-disposition': `attachment; filename=${fileName}`, + }, + }); + }), + ); diff --git a/packages/applications/ssr/src/components/organisms/header/UserBasedRoleNavigation.tsx b/packages/applications/ssr/src/components/organisms/header/UserBasedRoleNavigation.tsx index 011fa91bfb..aa0b2f9217 100644 --- a/packages/applications/ssr/src/components/organisms/header/UserBasedRoleNavigation.tsx +++ b/packages/applications/ssr/src/components/organisms/header/UserBasedRoleNavigation.tsx @@ -248,6 +248,12 @@ const getNavigationItemsBasedOnRole = (utilisateur: Utilisateur.ValueType) => { href: Routes.Gestionnaire.lister, }, }, + { + text: 'Export de données', + linkProps: { + href: Routes.Export.page, + }, + }, ], }, ]) @@ -318,6 +324,12 @@ const getNavigationItemsBasedOnRole = (utilisateur: Utilisateur.ValueType) => { href: Routes.Raccordement.lister, }, }, + { + text: 'Export de données', + linkProps: { + href: Routes.Export.page, + }, + }, { text: 'Tableau de bord', linkProps: { @@ -416,6 +428,23 @@ const getNavigationItemsBasedOnRole = (utilisateur: Utilisateur.ValueType) => { }, ], }, + { + text: 'Raccordements', + menuLinks: [ + { + text: 'Tous les dossiers de raccordement', + linkProps: { + href: Routes.Raccordement.lister, + }, + }, + ], + }, + { + text: 'Export de données', + linkProps: { + href: Routes.Export.page, + }, + }, ]) .with('grd', () => [ { diff --git "a/packages/domain/projet/src/laur\303\251at/raccordement/lister/listerDossierRaccordement.query.ts" "b/packages/domain/projet/src/laur\303\251at/raccordement/lister/listerDossierRaccordement.query.ts" index fa8409cb93..d1e8714e8a 100644 --- "a/packages/domain/projet/src/laur\303\251at/raccordement/lister/listerDossierRaccordement.query.ts" +++ "b/packages/domain/projet/src/laur\303\251at/raccordement/lister/listerDossierRaccordement.query.ts" @@ -17,9 +17,11 @@ type DossierRaccordement = { localité: Localité.ValueType; référenceDossier: RéférenceDossierRaccordement.ValueType; dateMiseEnService?: DateTime.ValueType; + dateDemandeComplèteRaccordement?: DateTime.ValueType; identifiantGestionnaireRéseau: GestionnaireRéseau.IdentifiantGestionnaireRéseau.ValueType; raisonSocialeGestionnaireRéseau: string; puissance: number; + prixReference: number; unitéPuissance: UnitéPuissance.ValueType; nomCandidat: string; @@ -163,34 +165,39 @@ export const mapToReadModel: MapToReadModelProps = ({ identifiantGestionnaireRéseau, référence, miseEnService, + demandeComplèteRaccordement, lauréat: { nomProjet, localité, notifiéLe }, 'gestionnaire-réseau': gestionnaireRéseau, puissance: { puissance }, - candidature: { emailContact, nomCandidat, sociétéMère, unitéPuissance }, + candidature: { emailContact, nomCandidat, sociétéMère, unitéPuissance, prixReference }, achèvement, -}) => { - return { - identifiantProjet: IdentifiantProjet.convertirEnValueType(identifiantProjet), - nomProjet, - localité: Localité.bind(localité), - référenceDossier: RéférenceDossierRaccordement.convertirEnValueType(référence), - dateMiseEnService: miseEnService - ? DateTime.convertirEnValueType(miseEnService.dateMiseEnService) +}) => ({ + identifiantProjet: IdentifiantProjet.convertirEnValueType(identifiantProjet), + nomProjet, + localité: Localité.bind(localité), + référenceDossier: RéférenceDossierRaccordement.convertirEnValueType(référence), + dateDemandeComplèteRaccordement: + demandeComplèteRaccordement && demandeComplèteRaccordement.dateQualification + ? DateTime.convertirEnValueType(demandeComplèteRaccordement.dateQualification) : undefined, - identifiantGestionnaireRéseau: - GestionnaireRéseau.IdentifiantGestionnaireRéseau.convertirEnValueType( - identifiantGestionnaireRéseau, - ), - raisonSocialeGestionnaireRéseau: gestionnaireRéseau.raisonSociale, - puissance, - unitéPuissance: UnitéPuissance.convertirEnValueType(unitéPuissance), - dateNotification: DateTime.convertirEnValueType(notifiéLe), - emailContact, - nomCandidat, - sociétéMère, - statutProjet: achèvement.estAchevé ? StatutLauréat.achevé : StatutLauréat.actif, - dateAchèvement: achèvement.réel?.date - ? DateTime.convertirEnValueType(achèvement.réel.date) + dateMiseEnService: + miseEnService && miseEnService.dateMiseEnService + ? DateTime.convertirEnValueType(miseEnService.dateMiseEnService) : undefined, - }; -}; + identifiantGestionnaireRéseau: + GestionnaireRéseau.IdentifiantGestionnaireRéseau.convertirEnValueType( + identifiantGestionnaireRéseau, + ), + raisonSocialeGestionnaireRéseau: gestionnaireRéseau.raisonSociale, + puissance, + unitéPuissance: UnitéPuissance.convertirEnValueType(unitéPuissance), + dateNotification: DateTime.convertirEnValueType(notifiéLe), + emailContact, + nomCandidat, + prixReference, + sociétéMère, + statutProjet: achèvement.estAchevé ? StatutLauréat.achevé : StatutLauréat.actif, + dateAchèvement: achèvement.réel?.date + ? DateTime.convertirEnValueType(achèvement.réel.date) + : undefined, +}); diff --git a/packages/domain/utilisateur/src/role.valueType.ts b/packages/domain/utilisateur/src/role.valueType.ts index 2957165cd6..35b1f1ba6e 100644 --- a/packages/domain/utilisateur/src/role.valueType.ts +++ b/packages/domain/utilisateur/src/role.valueType.ts @@ -2153,6 +2153,9 @@ const cocontractantPolicies: ReadonlyArray = [ // Accès 'accès.consulter', + + // Raccordement + 'raccordement.listerDossierRaccordement', ]; const caisseDesDépôtsPolicies: ReadonlyArray = [