diff --git a/README.md b/README.md
index 8372941..1ac059a 100644
--- a/README.md
+++ b/README.md
@@ -1,73 +1,64 @@
-
-
-
-
-[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
-[circleci-url]: https://circleci.com/gh/nestjs/nest
-
- A progressive Node.js framework for building efficient and scalable server-side applications.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+# VigiEau Admin - Backend
## Description
-[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
-
## Installation
-```bash
-$ yarn install
-```
+### Pré-requis
-## Running the app
+Vous aurez besoin de [NodeJS](https://nodejs.org/) v18+ et [Yarn](https://yarnpkg.com/) pour lancer ce projet.
-```bash
-# development
-$ yarn run start
+Nous vous recommandons de regarder la [documentation de NestJS](https://nestjs.com/).
-# watch mode
-$ yarn run start:dev
+### Variables d'environnement
-# production mode
-$ yarn run start:prod
+```bash
+cp env.example .env
```
-## Test
+- NODE_ENV : local / dev / prod
+- PORT : Port sur lequel tournera le serveur
+- OAUTH2_CLIENT : Se référer à la documentation de [ProConnect](https://www.proconnect.gouv.fr/)
+- SESSION_SECRET : Token JWT
+- DATABASE : Informations pour se connecter à la DB (Postgres)
+- WEBSITE_URL : Site web du frontend (http://localhost:3000 en local)
+- DOMAIN : Domaine sur lequel tourne le serveur (localhost en local)
+- API_DATAGOUV : Informations pour se connecter à Datagouv et pouvoir upload automatiquement les données de VigiEau
+- ADMINJS : User / password pour accéder au backend AdminJS
+- S3 : Informations pour se connecter aux buckets S3
+- MAIL : Informations pour se connecter à la boite mail
+- MAIL_MTE : Mail générique à renseigner pour l'envoi de mail systématique à une adresse
+- DOMAIN_NAME : Domaine du frontend (localhost:3000 en local)
+- PATH_TO_WRITE_FILE : Dossier pour stocker les fichiers temporaires ou le serveur peut lire / écrire
+
+### Installation des dépendances
```bash
-# unit tests
-$ yarn run test
+yarn install
+```
-# e2e tests
-$ yarn run test:e2e
+### Lancer nuxt en mode développement
-# test coverage
-$ yarn run test:cov
+Démarre le serveur sur http://localhost:3001
+
+```bash
+yarn start:dev
```
-## Support
+### Générer le code de production
+
+Génère le code de production de l’application:
+
+```bash
+yarn build
+```
-Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
+## Contribution
-## Stay in touch
+Les Pull Requests sont les bienvenues. Pour des changements majeurs merci d'ouvrir auparavant une issue pour en discuter.
-- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
-- Website - [https://nestjs.com](https://nestjs.com/)
-- Twitter - [@nestframework](https://twitter.com/nestframework)
+Assurez-vous de mettre à jour les tests en conséquence.
## License
-Nest is [MIT licensed](LICENSE).
+[MIT](https://choosealicense.com/licenses/mit/)
diff --git a/env.example b/env.example
index 04d3cc7..78a1865 100644
--- a/env.example
+++ b/env.example
@@ -17,9 +17,9 @@ DATABASE_NAME=regleau
WEBSITE_URL=http://localhost:3000
DOMAIN=localhost
-API_SANDRE=
-API_GEO=
-API_DATAGOUV=
+API_SANDRE=https://services.sandre.eaufrance.fr/
+API_GEO=https://geo.api.gouv.fr
+API_DATAGOUV=https://www.data.gouv.fr/api/1/
API_DATAGOUV_KEY=
API_DATAGOUV_DATASET=
@@ -39,4 +39,10 @@ MAIL_PASSWORD=
MAIL_HOST=
MAIL_PORT=
+MAIL_MTE=
+
DOMAIN_NAME=
+
+PATH_TO_WRITE_FILE=
+
+NODE_TLS_REJECT_UNAUTHORIZED=0
diff --git a/src/admin.module.ts b/src/admin.module.ts
index 2a1d0e6..bc214b6 100644
--- a/src/admin.module.ts
+++ b/src/admin.module.ts
@@ -7,6 +7,11 @@ import { Departement } from './departement/entities/departement.entity';
import { BassinVersant } from './bassin_versant/entities/bassin_versant.entity';
import { Region } from './core/entities/region.entity';
+/**
+ * Désactivé pour l'instant car au final pas utilisé
+ * Pour le réactiver il suffit de réimporter AdminModule dans AppModule
+ */
+
const DEFAULT_ADMIN = {
email: process.env.ADMINJS_USER,
password: process.env.ADMINJS_PASSWORD,
diff --git a/src/app.module.ts b/src/app.module.ts
index 572c622..173fe8f 100644
--- a/src/app.module.ts
+++ b/src/app.module.ts
@@ -15,7 +15,6 @@ import { ScheduleModule } from '@nestjs/schedule';
import { DepartementModule } from './departement/departement.module';
import { UsageModule } from './usage/usage.module';
import { ThematiqueModule } from './thematique/thematique.module';
-import { AdminModule } from './admin.module';
import { ArreteRestrictionModule } from './arrete_restriction/arrete_restriction.module';
import { AppController } from './app.controller';
import { LoggerModule } from './logger/logger.module';
@@ -36,6 +35,7 @@ import { UsageFeedbackModule } from './usage_feedback/usage_feedback.module';
import { StatisticModule } from './statistic/statistic.module';
import { ArreteMunicipalModule } from './arrete_municipal/arrete_municipal.module';
import { AbonnementMailModule } from './abonnement_mail/abonnement_mail.module';
+import { isArray, isObject } from './mail_templates/helpers/handlebars_helpers';
// @ts-ignore
@Module({
@@ -101,13 +101,20 @@ import { AbonnementMailModule } from './abonnement_mail/abonnement_mail.module';
preview: process.env.NODE_ENV === 'local',
template: {
dir: __dirname + '/mail_templates',
- adapter: new HandlebarsAdapter(),
+ adapter: new HandlebarsAdapter({'isObject': isObject, 'isArray': isArray}),
options: {
strict: true,
},
},
+ options: {
+ partials: {
+ dir: __dirname + '/mail_templates/partials',
+ options: {
+ strict: true,
+ },
+ },
+ },
}),
- AdminModule,
HealthModule,
ArreteCadreModule,
AuthModule,
diff --git a/src/arrete_cadre/arrete_cadre.module.ts b/src/arrete_cadre/arrete_cadre.module.ts
index 8f8e236..0d1f656 100644
--- a/src/arrete_cadre/arrete_cadre.module.ts
+++ b/src/arrete_cadre/arrete_cadre.module.ts
@@ -11,6 +11,9 @@ import { UserModule } from '../user/user.module';
import { FichierModule } from '../fichier/fichier.module';
import { RestrictionModule } from '../restriction/restriction.module';
import { UsageModule } from '../usage/usage.module';
+import {
+ ArreteCadreZoneAlerteCommunesModule
+} from '../arrete_cadre_zone_alerte_communes/arrete_cadre_zone_alerte_communes.module';
@Module({
imports: [
@@ -23,6 +26,7 @@ import { UsageModule } from '../usage/usage.module';
FichierModule,
RestrictionModule,
UsageModule,
+ ArreteCadreZoneAlerteCommunesModule,
],
controllers: [ArreteCadreController],
providers: [ArreteCadreService],
diff --git a/src/arrete_cadre/arrete_cadre.service.ts b/src/arrete_cadre/arrete_cadre.service.ts
index 2b462b4..a6c060a 100644
--- a/src/arrete_cadre/arrete_cadre.service.ts
+++ b/src/arrete_cadre/arrete_cadre.service.ts
@@ -30,6 +30,9 @@ import { FichierService } from '../fichier/fichier.service';
import { RestrictionService } from '../restriction/restriction.service';
import { UsageService } from '../usage/usage.service';
import moment from 'moment/moment';
+import {
+ ArreteCadreZoneAlerteCommunesService,
+} from '../arrete_cadre_zone_alerte_communes/arrete_cadre_zone_alerte_communes.service';
@Injectable()
export class ArreteCadreService {
@@ -46,6 +49,7 @@ export class ArreteCadreService {
private readonly fichierService: FichierService,
private readonly restrictionService: RestrictionService,
private readonly usageService: UsageService,
+ private readonly arreteCadreZoneAlerteCommunesService: ArreteCadreZoneAlerteCommunesService,
) {
}
@@ -80,7 +84,7 @@ export class ArreteCadreService {
: In(currentUser.role_departements),
},
};
- const acToReturn = await this.arreteCadreRepository.find( {
+ const acToReturn = await this.arreteCadreRepository.find({
select: {
id: true,
numero: true,
@@ -157,63 +161,30 @@ export class ArreteCadreService {
code: In(currentUser.role_departements),
},
};
- const [arreteCadre, usagesArreteCadre, departements]: any = await Promise.all( [
- this.arreteCadreRepository.findOne( {
- select: {
- id: true,
- numero: true,
- dateDebut: true,
- dateFin: true,
- statut: true,
- fichier: {
- id: true,
- nom: true,
- url: true,
- size: true,
- },
- departementPilote: {
- id: true,
- code: true,
- nom: true,
- },
- zonesAlerte: {
- id: true,
- code: true,
- nom: true,
- type: true,
- disabled: true,
- departement: {
- id: true,
- code: true,
- },
- },
- arretesRestriction: {
- id: true,
- numero: true,
- statut: true,
- },
- arreteCadreAbroge: {
- id: true,
- numero: true,
- dateDebut: true,
- dateFin: true,
- },
- },
- relations: [
- 'departementPilote',
- 'zonesAlerte',
- 'zonesAlerte.departement',
- 'arretesRestriction',
- 'fichier',
- 'arreteCadreAbroge',
- ],
- where: whereClause,
- order: {
- zonesAlerte: {
- code: 'ASC',
- },
- },
- }),
+
+ const qb = this.arreteCadreRepository.createQueryBuilder('arreteCadre')
+ .select([
+ 'arreteCadre.id', 'arreteCadre.numero', 'arreteCadre.dateDebut', 'arreteCadre.dateFin', 'arreteCadre.statut',
+ 'fichier.id', 'fichier.nom', 'fichier.url', 'fichier.size',
+ 'departementPilote.id', 'departementPilote.code', 'departementPilote.nom',
+ 'zonesAlerte.id', 'zonesAlerte.code', 'zonesAlerte.nom', 'zonesAlerte.type', 'zonesAlerte.disabled', 'zonesAlerte.ressourceInfluencee',
+ 'departement.id', 'departement.code',
+ 'arretesRestriction.id', 'arretesRestriction.numero', 'arretesRestriction.statut',
+ 'arreteCadreAbroge.id', 'arreteCadreAbroge.numero', 'arreteCadreAbroge.dateDebut', 'arreteCadreAbroge.dateFin',
+ 'aczac.id', 'communes.id', 'communes.code', 'communes.nom',
+ ])
+ .leftJoin('arreteCadre.departementPilote', 'departementPilote')
+ .leftJoin('arreteCadre.zonesAlerte', 'zonesAlerte')
+ .leftJoin('zonesAlerte.departement', 'departement')
+ .leftJoin('arreteCadre.arretesRestriction', 'arretesRestriction')
+ .leftJoin('arreteCadre.fichier', 'fichier')
+ .leftJoin('arreteCadre.arreteCadreAbroge', 'arreteCadreAbroge')
+ .leftJoin('zonesAlerte.arreteCadreZoneAlerteCommunes', 'aczac', 'aczac.arreteCadreId = arreteCadre.id')
+ .leftJoin('aczac.communes', 'communes')
+ .where(whereClause)
+ .orderBy('zonesAlerte.code', 'ASC');
+ const [arreteCadre, usagesArreteCadre, departements]: any = await Promise.all([
+ qb.getOne(),
this.usageService.findByArreteCadre(id),
this.departementService.findByArreteCadreId(id),
]);
@@ -224,6 +195,13 @@ export class ArreteCadreService {
);
}
arreteCadre.usages = usagesArreteCadre;
+ arreteCadre.zonesAlerte.map(za => {
+ if (za.arreteCadreZoneAlerteCommunes[0] && za.arreteCadreZoneAlerteCommunes[0].communes?.length > 0) {
+ za.communes = structuredClone(za.arreteCadreZoneAlerteCommunes[0].communes);
+ }
+ delete za.arreteCadreZoneAlerteCommunes;
+ return za;
+ });
if (departements) {
arreteCadre.departements = departements;
}
@@ -231,7 +209,7 @@ export class ArreteCadreService {
}
async findDatagouv(): Promise {
- return this.arreteCadreRepository.find( {
+ return this.arreteCadreRepository.find({
select: {
id: true,
numero: true,
@@ -271,7 +249,7 @@ export class ArreteCadreService {
}
findByArreteRestrictionId(id: number): Promise {
- return this.arreteCadreRepository.find( {
+ return this.arreteCadreRepository.find({
select: {
id: true,
numero: true,
@@ -326,7 +304,7 @@ export class ArreteCadreService {
}
findByDepartement(depCode: string): Promise {
- return this.arreteCadreRepository.find( {
+ return this.arreteCadreRepository.find({
select: {
id: true,
numero: true,
@@ -355,8 +333,9 @@ export class ArreteCadreService {
await this.checkAci(createArreteCadreDto, false, currentUser);
const arreteCadre =
await this.arreteCadreRepository.save(createArreteCadreDto);
- arreteCadre.usages =
- await this.usageService.updateAllByArreteCadre(arreteCadre);
+ arreteCadre.usages = await this.usageService.updateAllByArreteCadre(arreteCadre);
+ await this.arreteCadreZoneAlerteCommunesService.updateAllByArreteCadre(arreteCadre.id, createArreteCadreDto);
+
this.sendAciMails(null, arreteCadre, currentUser);
return arreteCadre;
}
@@ -378,8 +357,8 @@ export class ArreteCadreService {
id,
...updateArreteCadreDto,
});
- arreteCadre.usages =
- await this.usageService.updateAllByArreteCadre(arreteCadre);
+ arreteCadre.usages = await this.usageService.updateAllByArreteCadre(arreteCadre);
+ await this.arreteCadreZoneAlerteCommunesService.updateAllByArreteCadre(arreteCadre.id, updateArreteCadreDto);
await this.repercussionOnAr(oldAc, arreteCadre);
this.sendAciMails(oldAc, arreteCadre, currentUser);
@@ -558,7 +537,7 @@ export class ArreteCadreService {
},
);
const oldUsagesUpdates = oldAc.usages.filter(u => usagesUpdated.some(uu => uu.id === u.id));
- await Promise.all( [
+ await Promise.all([
this.restrictionService.deleteZonesByArreteCadreId(
zonesDeleted.map((z) => z.id),
oldAc.id,
diff --git a/src/arrete_cadre/dto/create_update_arrete_cadre.dto.ts b/src/arrete_cadre/dto/create_update_arrete_cadre.dto.ts
index 270b966..d17e35d 100644
--- a/src/arrete_cadre/dto/create_update_arrete_cadre.dto.ts
+++ b/src/arrete_cadre/dto/create_update_arrete_cadre.dto.ts
@@ -19,6 +19,19 @@ class UpdateLinkNestedObjectDto {
id: number;
}
+class UpdateZoneAlerteDto {
+ @IsNumber()
+ @ApiProperty({ example: 1, description: 'Identifiant BDD' })
+ id: number;
+
+ @IsArray()
+ @ValidateNested({ each: true })
+ @IsOptional()
+ @Type(() => UpdateLinkNestedObjectDto)
+ @ApiProperty({ type: [UpdateLinkNestedObjectDto] })
+ communes: UpdateLinkNestedObjectDto[];
+}
+
export class CreateUpdateArreteCadreDto {
@IsString()
@IsNotEmpty()
@@ -35,9 +48,9 @@ export class CreateUpdateArreteCadreDto {
@IsArray()
@ValidateNested({ each: true })
@IsOptional()
- @Type(() => UpdateLinkNestedObjectDto)
- @ApiProperty({ type: [UpdateLinkNestedObjectDto] })
- zonesAlerte: UpdateLinkNestedObjectDto[];
+ @Type(() => UpdateZoneAlerteDto)
+ @ApiProperty({ type: [UpdateZoneAlerteDto] })
+ zonesAlerte: UpdateZoneAlerteDto[];
@IsArray()
@ValidateNested({ each: true })
diff --git a/src/arrete_cadre/entities/arrete_cadre.entity.ts b/src/arrete_cadre/entities/arrete_cadre.entity.ts
index e9bd58f..f9375a9 100644
--- a/src/arrete_cadre/entities/arrete_cadre.entity.ts
+++ b/src/arrete_cadre/entities/arrete_cadre.entity.ts
@@ -21,6 +21,7 @@ import { ArreteRestriction } from '../../arrete_restriction/entities/arrete_rest
import { Fichier } from '../../fichier/entities/fichier.entity';
import { Restriction } from '../../restriction/entities/restriction.entity';
import { Usage } from '../../usage/entities/usage.entity';
+import { ArreteCadreZoneAlerteCommunes } from '../../arrete_cadre_zone_alerte_communes/entities/arrete_cadre_zone_alerte_communes.entity';
@Entity()
export class ArreteCadre extends BaseEntity {
@@ -88,6 +89,9 @@ export class ArreteCadre extends BaseEntity {
@OneToMany(() => Restriction, (restriction) => restriction.arreteCadre)
restrictions: Restriction[];
+ @OneToMany(() => ArreteCadreZoneAlerteCommunes, (arreteCadreZoneAlerteCommunes) => arreteCadreZoneAlerteCommunes.arreteCadre)
+ arreteCadreZoneAlerteCommunes: ArreteCadreZoneAlerteCommunes[];
+
@CreateDateColumn({ select: false, type: 'timestamp' })
created_at: number;
diff --git a/src/arrete_cadre_zone_alerte_communes/arrete_cadre_zone_alerte_communes.module.ts b/src/arrete_cadre_zone_alerte_communes/arrete_cadre_zone_alerte_communes.module.ts
new file mode 100644
index 0000000..cd56435
--- /dev/null
+++ b/src/arrete_cadre_zone_alerte_communes/arrete_cadre_zone_alerte_communes.module.ts
@@ -0,0 +1,14 @@
+import { Module } from '@nestjs/common';
+import { TypeOrmModule } from '@nestjs/typeorm';
+import { ArreteCadreZoneAlerteCommunes } from './entities/arrete_cadre_zone_alerte_communes.entity';
+import { ArreteCadreZoneAlerteCommunesService } from './arrete_cadre_zone_alerte_communes.service';
+
+@Module({
+ imports: [
+ TypeOrmModule.forFeature([ArreteCadreZoneAlerteCommunes]),
+ ],
+ providers: [ArreteCadreZoneAlerteCommunesService],
+ exports: [ArreteCadreZoneAlerteCommunesService],
+})
+export class ArreteCadreZoneAlerteCommunesModule {
+}
\ No newline at end of file
diff --git a/src/arrete_cadre_zone_alerte_communes/arrete_cadre_zone_alerte_communes.service.ts b/src/arrete_cadre_zone_alerte_communes/arrete_cadre_zone_alerte_communes.service.ts
new file mode 100644
index 0000000..b924bd5
--- /dev/null
+++ b/src/arrete_cadre_zone_alerte_communes/arrete_cadre_zone_alerte_communes.service.ts
@@ -0,0 +1,36 @@
+import { Injectable } from '@nestjs/common';
+import { InjectRepository } from '@nestjs/typeorm';
+import { In, Not, Repository } from 'typeorm';
+import { ArreteCadreZoneAlerteCommunes } from './entities/arrete_cadre_zone_alerte_communes.entity';
+import { CreateUpdateArreteCadreDto } from '../arrete_cadre/dto/create_update_arrete_cadre.dto';
+import { FindOptionsWhere } from 'typeorm/find-options/FindOptionsWhere';
+
+@Injectable()
+export class ArreteCadreZoneAlerteCommunesService {
+ constructor(@InjectRepository(ArreteCadreZoneAlerteCommunes)
+ private readonly arreteCadreZoneAlerteCommunesRepository: Repository) {
+ }
+
+ async updateAllByArreteCadre(acId: number, arreteCadre: CreateUpdateArreteCadreDto) {
+ const zonesWithCommunes = arreteCadre.zonesAlerte.filter(z => z.communes && z.communes.length > 0);
+
+ // SUPPRESSION DES ANCIENNES ZONES / COMMUNES
+ await this.arreteCadreZoneAlerteCommunesRepository.delete(>{
+ arreteCadre: {
+ id: acId,
+ },
+ id: Not(In(zonesWithCommunes.map(z => z.id))),
+ });
+
+ const arreteCadreZoneAlerteCommunes: ArreteCadreZoneAlerteCommunes[] = [];
+ zonesWithCommunes.forEach(z => {
+ arreteCadreZoneAlerteCommunes.push( {
+ arreteCadre: { id: acId },
+ zoneAlerte: { id: z.id },
+ communes: z.communes
+ });
+ });
+
+ return this.arreteCadreZoneAlerteCommunesRepository.save(arreteCadreZoneAlerteCommunes);
+ }
+}
\ No newline at end of file
diff --git a/src/arrete_cadre_zone_alerte_communes/entities/arrete_cadre_zone_alerte_communes.entity.ts b/src/arrete_cadre_zone_alerte_communes/entities/arrete_cadre_zone_alerte_communes.entity.ts
new file mode 100644
index 0000000..7194c83
--- /dev/null
+++ b/src/arrete_cadre_zone_alerte_communes/entities/arrete_cadre_zone_alerte_communes.entity.ts
@@ -0,0 +1,22 @@
+import { BaseEntity, Entity, JoinTable, ManyToMany, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
+import { ZoneAlerte } from '../../zone_alerte/entities/zone_alerte.entity';
+import { ArreteCadre } from '../../arrete_cadre/entities/arrete_cadre.entity';
+import { Commune } from '../../commune/entities/commune.entity';
+
+@Entity()
+export class ArreteCadreZoneAlerteCommunes extends BaseEntity {
+ @PrimaryGeneratedColumn()
+ id: number;
+
+ @ManyToOne(() => ZoneAlerte, (zoneAlerte) => zoneAlerte.arreteCadreZoneAlerteCommunes, { nullable: false })
+ zoneAlerte: ZoneAlerte;
+
+ @ManyToOne(() => ArreteCadre, (arreteCadre) => arreteCadre.arreteCadreZoneAlerteCommunes, { nullable: false })
+ arreteCadre: ArreteCadre;
+
+ @ManyToMany(() => Commune, (commune) => commune.arreteCadreZoneAlerteCommunes)
+ @JoinTable({
+ name: 'ac_za_communes'
+ })
+ communes: Commune[];
+}
\ No newline at end of file
diff --git a/src/arrete_restriction/arrete_restriction.service.ts b/src/arrete_restriction/arrete_restriction.service.ts
index 5ccec69..bbd512d 100644
--- a/src/arrete_restriction/arrete_restriction.service.ts
+++ b/src/arrete_restriction/arrete_restriction.service.ts
@@ -1219,9 +1219,9 @@ export class ArreteRestrictionService {
userEmail: currentUser.email,
userDepartement: currentUser.role_departements?.join(', '),
arreteNumero: oldAr.numero,
- oldAr: JSON.stringify(oldArLight),
- newAr: JSON.stringify(newArLight),
- diffAr: JSON.stringify(diff),
+ oldAr: oldArLight,
+ newAr: newArLight,
+ diffAr: diff,
arreteLien: `https://${process.env.DOMAIN_NAME}/arrete-restriction/${oldAr.id}/edition`,
},
);
diff --git a/src/commune/commune.service.ts b/src/commune/commune.service.ts
index 3e8810d..46133ba 100644
--- a/src/commune/commune.service.ts
+++ b/src/commune/commune.service.ts
@@ -135,6 +135,7 @@ export class CommuneService {
.addSelect('zac.id', 'zac_id')
.addSelect('zac.nom', 'zac_nom')
.addSelect('zac.type', 'zac_type')
+ .addSelect('zac.ressourceInfluencee', 'zac_ressource_influencee')
.addSelect('zac.niveauGravite', 'zac_niveau_gravite')
.addSelect('ST_Area(commune.geom)', 'area')
.addSelect('ST_Area(zac.geom)', 'zac_area')
@@ -159,6 +160,7 @@ export class CommuneService {
id: c.zac_id,
nom: c.zac_nom,
type: c.zac_type,
+ ressourceInfluencee: c.zac_ressource_influencee,
niveauGravite: c.zac_niveau_gravite,
area: c.zac_area,
areaCommune: c.zac_commune_area,
@@ -177,6 +179,7 @@ export class CommuneService {
.addSelect('zac.id', 'zac_id')
.addSelect('zac.nom', 'zac_nom')
.addSelect('zac.type', 'zac_type')
+ .addSelect('zac.ressourceInfluencee', 'zac_ressource_influencee')
.addSelect('zac.niveauGravite', 'zac_niveau_gravite')
.addSelect('ST_Area(commune.geom)', 'area')
.addSelect('ST_Area(zac.geom)', 'zac_area')
diff --git a/src/commune/entities/commune.entity.ts b/src/commune/entities/commune.entity.ts
index 0104cae..2f162b4 100644
--- a/src/commune/entities/commune.entity.ts
+++ b/src/commune/entities/commune.entity.ts
@@ -15,6 +15,7 @@ import { ZoneAlerteComputed } from '../../zone_alerte_computed/entities/zone_ale
import { ZoneAlerteComputedHistoric } from '../../zone_alerte_computed/entities/zone_alerte_computed_historic.entity';
import { StatisticCommune } from '../../statistic_commune/entities/statistic_commune.entity';
import { ArreteMunicipal } from '../../arrete_municipal/entities/arrete_municipal.entity';
+import { ArreteCadreZoneAlerteCommunes } from '../../arrete_cadre_zone_alerte_communes/entities/arrete_cadre_zone_alerte_communes.entity';
@Entity()
export class Commune extends BaseEntity {
@@ -66,6 +67,11 @@ export class Commune extends BaseEntity {
})
arretesMunicipaux: ArreteMunicipal[];
+ @ManyToMany(() => ArreteCadreZoneAlerteCommunes, (arreteCadreZoneAlerteCommunes) => arreteCadreZoneAlerteCommunes.communes, {
+ persistence: false,
+ })
+ arreteCadreZoneAlerteCommunes: ArreteCadreZoneAlerteCommunes[];
+
@Column({ nullable: false, default: false })
disabled: boolean;
diff --git a/src/config/config.service.ts b/src/config/config.service.ts
index 11ae527..d56a17b 100644
--- a/src/config/config.service.ts
+++ b/src/config/config.service.ts
@@ -27,7 +27,6 @@ export class ConfigService {
}
async setConfig(computeMapDate: string, computeStatsDate: string) {
- console.log('SET CONFIG', computeMapDate, computeStatsDate);
await this.configRepository.createQueryBuilder()
.update()
.set({ computeMapDate })
diff --git a/src/datagouv/datagouv.service.ts b/src/datagouv/datagouv.service.ts
index 6bec9d9..41ffa1f 100644
--- a/src/datagouv/datagouv.service.ts
+++ b/src/datagouv/datagouv.service.ts
@@ -42,7 +42,7 @@ export class DatagouvService {
'restrictions': 'e403a885-5eaf-411d-a03e-751a9c22930d',
'pmtiles_archive': 'b0b246c3-f724-4eb2-a83a-c516e0044aa2',
'geojson_archive': '3972a125-2372-41f1-b3f5-25794f860414',
- 'arretes_cadre': '',
+ 'arretes_cadre': '0732e970-c12c-4e6a-adca-5ac9dbc3fdfa',
};
constructor(private readonly httpService: HttpService,
@@ -209,7 +209,7 @@ export class DatagouvService {
date_debut: arrete.dateDebut,
date_fin: arrete.dateFin,
statut: arrete.statut,
- departement_pilote: arrete.departementPilote?.code,
+ departement_pilote: arrete.departementPilote ? arrete.departementPilote.code : '',
departements: arrete.departements.map(d => d.code),
chemin_fichier: arrete.fichier ? arrete.fichier?.url : '',
zones_alerte: arrete.zonesAlerte.map(zone => {
@@ -316,7 +316,7 @@ export class DatagouvService {
const dateDebut = date ? date : moment();
for (let y = dateDebut.year(); y <= moment().year(); y++) {
- // await this.generateMapsArchive(dateDebut, y, true);
+ await this.generateMapsArchive(dateDebut, y, true);
await this.generateMapsArchive(dateDebut, y, false);
}
}
@@ -331,13 +331,13 @@ export class DatagouvService {
try {
const { data } = await firstValueFrom(
this.httpService.get(
- `${this.configService.get('S3_VHOST')}${this.configService.get('S3_PREFIX')}${geojsonOrPmtiles}/zones_${geojsonOrPmtiles}_${year}.zip`,
+ `${this.configService.get('S3_VHOST')}${this.configService.get('S3_PREFIX') ? this.configService.get('S3_PREFIX') : ''}${geojsonOrPmtiles}/zones_${geojsonOrPmtiles}_${year}.zip`,
{ responseType: 'arraybuffer' },
),
);
dataZip = data;
} catch (e) {
- this.logger.error(`ARCHIVE ${this.configService.get('S3_VHOST')}${this.configService.get('S3_PREFIX')}${geojsonOrPmtiles}/zones_${geojsonOrPmtiles}_${year}.zip non accessible`, e);
+ this.logger.error(`ARCHIVE ${this.configService.get('S3_VHOST')}${this.configService.get('S3_PREFIX') ? this.configService.get('S3_PREFIX') : ''}${geojsonOrPmtiles}/zones_${geojsonOrPmtiles}_${year}.zip non accessible`, e);
}
const zip = dataZip ? await JSZip.loadAsync(dataZip) : new JSZip();
diff --git a/src/departement/departement.service.ts b/src/departement/departement.service.ts
index 1e62ed7..7b299ea 100644
--- a/src/departement/departement.service.ts
+++ b/src/departement/departement.service.ts
@@ -40,6 +40,7 @@ export class DepartementService {
'zonesAlerte.nom',
'zonesAlerte.code',
'zonesAlerte.type',
+ 'zonesAlerte.ressourceInfluencee',
'arretesCadre.id',
])
.leftJoin('departement.zonesAlerte', 'zonesAlerte')
diff --git a/src/mail_templates/helpers/handlebars_helpers.ts b/src/mail_templates/helpers/handlebars_helpers.ts
new file mode 100644
index 0000000..b198cbe
--- /dev/null
+++ b/src/mail_templates/helpers/handlebars_helpers.ts
@@ -0,0 +1,7 @@
+export function isObject(value) {
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
+}
+
+export function isArray(value) {
+ return Array.isArray(value);
+}
\ No newline at end of file
diff --git a/src/mail_templates/maj_ar.hbs b/src/mail_templates/maj_ar.hbs
index a6ca10b..fb2bfd8 100644
--- a/src/mail_templates/maj_ar.hbs
+++ b/src/mail_templates/maj_ar.hbs
@@ -298,11 +298,20 @@
l’arrêté {{ arreteNumero }}.
Voici les modifications effectuées :
- {{ diffAr }}
- Ancien AR:
- {{ oldAr }}
- Nouvel AR:
- {{ newAr }}
+
+ {{> recursiveTree diffAr }}
+
+
+ Ancien AR:
+
+ {{> recursiveTree oldAr }}
+
+
+ Nouvel AR:
+
+ {{> recursiveTree newAr }}
+
+
diff --git a/src/mail_templates/partials/recursiveTree.hbs b/src/mail_templates/partials/recursiveTree.hbs
new file mode 100644
index 0000000..e7052f5
--- /dev/null
+++ b/src/mail_templates/partials/recursiveTree.hbs
@@ -0,0 +1,28 @@
+{{! Partiel : recursiveTree }}
+{{#each this}}
+
+ {{@key}} :
+ {{#if (isObject this)}}
+
+ {{> recursiveTree this }}
+
+ {{else if (isArray this)}}
+ <{{@key}} :
+
+ {{#each this}}
+ -
+ {{#if (isObject this)}}
+
+ {{> recursiveTree this }}
+
+ {{else}}
+ {{this}}
+ {{/if}}
+
+ {{/each}}
+
+ {{else}}
+ {{this}}
+ {{/if}}
+
+{{/each}}
\ No newline at end of file
diff --git a/src/usage/usage.service.ts b/src/usage/usage.service.ts
index 1ace007..08ed8f2 100644
--- a/src/usage/usage.service.ts
+++ b/src/usage/usage.service.ts
@@ -1,11 +1,12 @@
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
-import { In, Not, Repository } from 'typeorm';
+import { FindManyOptions, In, Not, Repository } from 'typeorm';
import { Usage } from './entities/usage.entity';
import { User } from '../user/entities/user.entity';
import { CreateUpdateUsageDto } from './dto/create_usage.dto';
import { Restriction } from '../restriction/entities/restriction.entity';
import { ArreteCadre } from '../arrete_cadre/entities/arrete_cadre.entity';
+import { FindOptionsWhere } from 'typeorm/find-options/FindOptionsWhere';
@Injectable()
export class UsageService {
@@ -69,14 +70,14 @@ export class UsageService {
.flat();
// SUPPRESSION DES ANCIENS USAGES
if(usagesId.length > 0) {
- await this.usageRepository.delete({
+ await this.usageRepository.delete(> {
restriction: {
id: restriction.id,
},
id: Not(In(usagesId)),
});
} else {
- await this.usageRepository.delete({
+ await this.usageRepository.delete(> {
restriction: {
id: restriction.id,
},
@@ -96,7 +97,7 @@ export class UsageService {
.map((u) => u.id)
.flat();
// SUPPRESSION DES ANCIENS USAGES
- await this.usageRepository.delete({
+ await this.usageRepository.delete(> {
arreteCadre: {
id: arreteCadre.id,
},
@@ -112,7 +113,7 @@ export class UsageService {
}
findByArreteCadre(arreteCadreId: number) {
- return this.usageRepository.find({
+ return this.usageRepository.find( {
select: {
id: true,
nom: true,
@@ -148,7 +149,7 @@ export class UsageService {
const updates = [];
for (const u of usagesAc) {
const oldUsage = oldUsagesAc.find(ou => ou.id === u.id);
- const tmp = await this.usageRepository.find({
+ const tmp = await this.usageRepository.find( {
where: {
restriction: {
arreteRestriction: {
diff --git a/src/zone_alerte/dto/zone_alerte.dto.ts b/src/zone_alerte/dto/zone_alerte.dto.ts
index e7738b9..c0e7ee3 100644
--- a/src/zone_alerte/dto/zone_alerte.dto.ts
+++ b/src/zone_alerte/dto/zone_alerte.dto.ts
@@ -1,12 +1,15 @@
import {
+ IsArray,
IsBoolean,
IsJSON,
IsNumber,
- IsObject,
- IsString,
+ IsObject, IsOptional,
+ IsString, ValidateNested,
} from 'class-validator';
import { DepartementDto } from '../../departement/dto/departement.dto';
import { ApiProperty } from '@nestjs/swagger';
+import { Type } from 'class-transformer';
+import { CommuneDto } from '../../commune/dto/commune.dto';
export class ZoneAlerteDto {
@IsNumber()
@@ -25,6 +28,13 @@ export class ZoneAlerteDto {
})
type: string;
+ @IsBoolean()
+ @ApiProperty({
+ example: false,
+ description: "Est-ce que la zone d'alerte est une ressource stockéee / regulée ?",
+ })
+ ressourceInfluencee: boolean;
+
@IsString()
@ApiProperty({
example: 'Zone superficielle Ain 01',
@@ -48,6 +58,13 @@ export class ZoneAlerteDto {
@IsObject()
departement: DepartementDto;
+
+ @IsArray()
+ @ValidateNested({ each: true })
+ @IsOptional()
+ @Type(() => CommuneDto)
+ @ApiProperty({ type: [CommuneDto] })
+ communes: CommuneDto[];
}
export class ZoneAlertGeomDto extends ZoneAlerteDto {
diff --git a/src/zone_alerte/entities/zone_alerte.entity.ts b/src/zone_alerte/entities/zone_alerte.entity.ts
index d2d3199..e2be7e0 100644
--- a/src/zone_alerte/entities/zone_alerte.entity.ts
+++ b/src/zone_alerte/entities/zone_alerte.entity.ts
@@ -13,6 +13,7 @@ import { ArreteCadre } from '../../arrete_cadre/entities/arrete_cadre.entity';
import { BassinVersant } from '../../bassin_versant/entities/bassin_versant.entity';
import { Departement } from '../../departement/entities/departement.entity';
import { Restriction } from '../../restriction/entities/restriction.entity';
+import { ArreteCadreZoneAlerteCommunes } from '../../arrete_cadre_zone_alerte_communes/entities/arrete_cadre_zone_alerte_communes.entity';
@Entity()
export class ZoneAlerte extends BaseEntity {
@@ -31,6 +32,9 @@ export class ZoneAlerte extends BaseEntity {
@Column({ nullable: false, length: 50 })
type: 'SOU' | 'SUP';
+ @Column({ default: false, nullable: false })
+ ressourceInfluencee: boolean;
+
@Column({ nullable: true })
numeroVersion: number;
@@ -59,6 +63,9 @@ export class ZoneAlerte extends BaseEntity {
@OneToMany(() => Restriction, (restriction) => restriction.zoneAlerte)
restrictions: Restriction[];
+ @OneToMany(() => ArreteCadreZoneAlerteCommunes, (arreteCadreZoneAlerteCommunes) => arreteCadreZoneAlerteCommunes.zoneAlerte)
+ arreteCadreZoneAlerteCommunes: ArreteCadreZoneAlerteCommunes[];
+
@CreateDateColumn()
createdAt: Date;
diff --git a/src/zone_alerte/zone_alerte.service.ts b/src/zone_alerte/zone_alerte.service.ts
index 2c1bcfa..cdc5447 100644
--- a/src/zone_alerte/zone_alerte.service.ts
+++ b/src/zone_alerte/zone_alerte.service.ts
@@ -1,6 +1,6 @@
import { forwardRef, Inject, Injectable } from '@nestjs/common';
-import { InjectRepository } from '@nestjs/typeorm';
-import { In, IsNull, Not, Repository } from 'typeorm';
+import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
+import { DataSource, FindManyOptions, In, IsNull, Not, Repository } from 'typeorm';
import { ZoneAlerte } from './entities/zone_alerte.entity';
import { Cron, CronExpression } from '@nestjs/schedule';
import { ConfigService } from '@nestjs/config';
@@ -11,7 +11,6 @@ import { DepartementService } from '../departement/departement.service';
import { BassinVersantService } from '../bassin_versant/bassin_versant.service';
import { MailService } from '../shared/services/mail.service';
import { ArreteCadreService } from '../arrete_cadre/arrete_cadre.service';
-import { ZoneAlerteComputed } from '../zone_alerte_computed/entities/zone_alerte_computed.entity';
@Injectable()
export class ZoneAlerteService {
@@ -27,27 +26,41 @@ export class ZoneAlerteService {
private readonly mailService: MailService,
@Inject(forwardRef(() => ArreteCadreService))
private readonly arreteCadreService: ArreteCadreService,
+ @InjectDataSource()
+ private readonly dataSource: DataSource,
) {
}
- findOne(id: number): Promise {
- return this.zoneAlerteRepository
+ async findOne(id: number, acIds?: number[]): Promise {
+ const za = await this.zoneAlerteRepository
.createQueryBuilder('zone_alerte')
.select('zone_alerte.id', 'id')
.select('zone_alerte.idSandre', 'idSandre')
.addSelect('zone_alerte.code', 'code')
.addSelect('zone_alerte.nom', 'nom')
.addSelect('zone_alerte.type', 'type')
+ .addSelect('zone_alerte.ressourceInfluencee', 'ressourceInfluencee')
.addSelect(
'ST_AsGeoJSON(ST_TRANSFORM(zone_alerte.geom, 4326))',
'geom',
)
.where('zone_alerte.id = :id', { id })
.getRawOne();
+
+ za.arreteCadreZoneAlerteCommunes = (await this.zoneAlerteRepository
+ .createQueryBuilder('zone_alerte')
+ .select(['zone_alerte.id'])
+ .addSelect(['aczac.id', 'communes.id'])
+ .leftJoin('zone_alerte.arreteCadreZoneAlerteCommunes', 'aczac', 'aczac.arreteCadreId IN(:...acIds)', {acIds: acIds})
+ .leftJoin('aczac.communes', 'communes')
+ .where('zone_alerte.id = :id', { id })
+ .getOne()).arreteCadreZoneAlerteCommunes;
+
+ return za;
}
findByDepartement(departementCode: string): Promise {
- return this.zoneAlerteRepository.find({
+ return this.zoneAlerteRepository.find( {
relations: ['departement'],
where: {
departement: {
@@ -78,13 +91,14 @@ export class ZoneAlerteService {
if (!arIds || arIds.length < 1) {
return [];
}
- return this.zoneAlerteRepository.find({
+ return this.zoneAlerteRepository.find( {
select: {
id: true,
idSandre: true,
code: true,
nom: true,
type: true,
+ ressourceInfluencee: true,
departement: {
code: true,
nom: true,
@@ -220,7 +234,7 @@ export class ZoneAlerteService {
existingZone.geom = f.geometry;
promises.push(this.zoneAlerteRepository.save(existingZone));
}
- const idsToDisable = await this.zoneAlerteRepository.find({
+ const idsToDisable = await this.zoneAlerteRepository.find( {
select: {
id: true,
idSandre: true,
@@ -293,4 +307,25 @@ export class ZoneAlerteService {
.andWhere('ST_Area(ST_Intersection(ST_TRANSFORM(zone_alerte.geom, 4326), (SELECT ST_TRANSFORM(c.geom, 4326) FROM commune as c WHERE c.id = :communeId))) / ST_Area((SELECT ST_TRANSFORM(c.geom, 4326) FROM commune as c WHERE c.id = :communeId)) > 0.01', { communeId })
.getRawMany();
}
+
+ async getUnionGeomOfZoneAndCommunes(zoneId: number, communesId: number[]): Promise {
+ const result = await this.dataSource.query(
+ `
+ SELECT ST_AsGeoJSON(ST_Union(zone.geom, communes.geom)) AS combined_geom
+ FROM (
+ SELECT ST_TRANSFORM(geom, 4326) AS geom
+ FROM zone_alerte
+ WHERE id = $1
+ ) AS zone,
+ (
+ SELECT ST_Union(ST_TRANSFORM(geom, 4326)) AS geom
+ FROM commune
+ WHERE id = ANY($2)
+ ) AS communes;
+ `,
+ [zoneId, communesId]
+ );
+
+ return result[0]?.combined_geom;
+ }
}
diff --git a/src/zone_alerte_computed/entities/zone_alerte_computed.entity.ts b/src/zone_alerte_computed/entities/zone_alerte_computed.entity.ts
index 2090ffa..dbb17cc 100644
--- a/src/zone_alerte_computed/entities/zone_alerte_computed.entity.ts
+++ b/src/zone_alerte_computed/entities/zone_alerte_computed.entity.ts
@@ -30,6 +30,9 @@ export class ZoneAlerteComputed extends BaseEntity {
@Column({ nullable: false, length: 50 })
type: 'SOU' | 'SUP' | 'AEP';
+ @Column({ default: false, nullable: false })
+ ressourceInfluencee: boolean;
+
@Column({ default: false })
enabled: boolean;
diff --git a/src/zone_alerte_computed/entities/zone_alerte_computed_historic.entity.ts b/src/zone_alerte_computed/entities/zone_alerte_computed_historic.entity.ts
index ac25fab..10a9562 100644
--- a/src/zone_alerte_computed/entities/zone_alerte_computed_historic.entity.ts
+++ b/src/zone_alerte_computed/entities/zone_alerte_computed_historic.entity.ts
@@ -30,6 +30,9 @@ export class ZoneAlerteComputedHistoric extends BaseEntity {
@Column({ nullable: false, length: 50 })
type: 'SOU' | 'SUP' | 'AEP';
+ @Column({ default: false, nullable: false })
+ ressourceInfluencee: boolean;
+
@Column({ default: false })
enabled: boolean;
diff --git a/src/zone_alerte_computed/zone_alerte_computed.service.ts b/src/zone_alerte_computed/zone_alerte_computed.service.ts
index f26c6a8..2491238 100644
--- a/src/zone_alerte_computed/zone_alerte_computed.service.ts
+++ b/src/zone_alerte_computed/zone_alerte_computed.service.ts
@@ -92,6 +92,7 @@ export class ZoneAlerteComputedService {
this.isComputing = true;
await this.computeAll([...new Set(this.departementsToUpdate)], computeHistoric);
} catch (e) {
+ this.logger.error('COMPUTE ALL', e);
}
this.isComputing = false;
}
@@ -160,9 +161,13 @@ export class ZoneAlerteComputedService {
for (const ar of arretesRestrictions) {
await Promise.all(ar.restrictions.map(async (restriction) => {
if (restriction.zoneAlerte) {
- const za = await this.zoneAlerteService.findOne(restriction.zoneAlerte.id);
+ const za = await this.zoneAlerteService.findOne(restriction.zoneAlerte.id, [restriction.arreteCadre.id]);
za.restriction = { id: restriction.id, niveauGravite: restriction.niveauGravite };
za.departement = { id: departement.id };
+
+ if (za.arreteCadreZoneAlerteCommunes && za.arreteCadreZoneAlerteCommunes[0] && za.arreteCadreZoneAlerteCommunes[0].communes?.length > 0) {
+ za.geom = await this.zoneAlerteService.getUnionGeomOfZoneAndCommunes(restriction.zoneAlerte.id, za.arreteCadreZoneAlerteCommunes[0].communes.map(c => c.id));
+ }
// SAUVEGARDE ZONE ESU ou ESO
zonesToSave.push(za);
} else if (restriction.communes?.length > 0) {
@@ -294,7 +299,15 @@ export class ZoneAlerteComputedService {
const queries = [];
for (const commune of communes) {
for (const zoneType of zoneTypes) {
- const zonesSameType = commune.zones.filter(z => z.type === zoneType);
+ let zonesSameType = commune.zones.filter(z => z.type === zoneType);
+ // Gestion des zones influencées
+ // Si il y a des ressources influencées ET des ressources naturelles, on exclut les ressources influencées des calculs
+ if (zonesSameType.length > 1
+ && zonesSameType.some(z => z.ressourceInfluencee && z.areaCommunePercentage >= 5)
+ && zonesSameType.some(z => !z.ressourceInfluencee && z.areaCommunePercentage >= 5)) {
+ zonesSameType = zonesSameType.filter(z => !z.ressourceInfluencee);
+ }
+
// Quand une seule zone, on l'agrandie à la geometrie de la commune
if (zonesSameType.length === 1 && zonesSameType[0].areaCommunePercentage >= 5) {
queries.push(this.getQueryToExtendZone(zonesSameType[0].id, commune.id));
@@ -346,7 +359,12 @@ export class ZoneAlerteComputedService {
}).niveauGravite;
for (const zoneType of zoneTypes) {
// Normalement il y a au maximum une zone par type mais si ils ont fait plusieurs AR avec des règles de gestions différentes il se peut que plusieurs zones AEP se superposent
- const zonesSameType = zones.filter(z => z.type === zoneType);
+ let zonesSameType = zones.filter(z => z.type === zoneType);
+
+ // Gestion des ressources influencées
+ if(zonesSameType.some(z => z.ressourceInfluencee) && zonesSameType.some(z => !z.ressourceInfluencee)) {
+ zonesSameType = zonesSameType.filter(z => !z.ressourceInfluencee);
+ }
if (zonesSameType.length === 1 && zonesSameType[0].niveauGravite !== maxNiveauGravite) {
@@ -378,7 +396,7 @@ export class ZoneAlerteComputedService {
} else {
queries.push(this.getQueryToExtendZone(zoneToKeep.id, commune.id));
}
- zonesSameType.filter(z => z.id !== zoneToKeep.id).forEach(z => {
+ zonesSameType.filter(z => z.id !== zoneToKeep.id && !z.ressourceInfluencee).forEach(z => {
queries.push(this.getQueryToReduceZone(z.id, commune.id));
});
@@ -639,6 +657,8 @@ DELETE FROM zone_alerte_computed
// Au moins 1% de la surface en commun
.leftJoinAndSelect('commune', 'commune', 'commune.departement = departement.id AND ST_INTERSECTS(zone_alerte_computed.geom, commune.geom) AND ST_Area(ST_Intersection(zone_alerte_computed.geom, commune.geom)) / ST_AREA(commune.geom) > 0.001')
.where('departement.id = :id', { id: departement.id })
+ .andWhere('ST_IsValid(ST_TRANSFORM(zone_alerte_computed.geom, 4326))')
+ .andWhere('ST_IsValid(ST_TRANSFORM(commune.geom, 4326))')
.getRawMany();
const toSave = [];
zones.forEach(z => {
diff --git a/src/zone_alerte_computed/zone_alerte_computed_historic.service.ts b/src/zone_alerte_computed/zone_alerte_computed_historic.service.ts
index 5b41750..f6b2503 100644
--- a/src/zone_alerte_computed/zone_alerte_computed_historic.service.ts
+++ b/src/zone_alerte_computed/zone_alerte_computed_historic.service.ts
@@ -240,9 +240,13 @@ export class ZoneAlerteComputedHistoricService {
for (const ar of arretesRestrictions) {
await Promise.all(ar.restrictions.map(async (restriction) => {
if (restriction.zoneAlerte) {
- const za = await this.zoneAlerteService.findOne(restriction.zoneAlerte.id);
+ const za = await this.zoneAlerteService.findOne(restriction.zoneAlerte.id, [restriction.arreteCadre.id]);
za.restriction = { id: restriction.id, niveauGravite: restriction.niveauGravite };
za.departement = { id: departement.id };
+
+ if(za.arreteCadreZoneAlerteCommunes && za.arreteCadreZoneAlerteCommunes[0] && za.arreteCadreZoneAlerteCommunes[0].communes?.length > 0) {
+ za.geom = await this.zoneAlerteService.getUnionGeomOfZoneAndCommunes(za.id, za.arreteCadreZoneAlerteCommunes[0].communes.map(c => c.id));
+ }
// SAUVEGARDE ZONE ESU ou ESO
zonesToSave.push(za);
} else if (restriction.communes?.length > 0) {
@@ -377,7 +381,15 @@ export class ZoneAlerteComputedHistoricService {
const queries = [];
for (const commune of communes) {
for (const zoneType of zoneTypes) {
- const zonesSameType = commune.zones.filter(z => z.type === zoneType);
+ let zonesSameType = commune.zones.filter(z => z.type === zoneType);
+ // Gestion des zones influencées
+ // Si il y a des ressources influencées ET des ressources naturelles, on exclut les ressources influencées des calculs
+ if (zonesSameType.length > 1
+ && zonesSameType.some(z => z.ressourceInfluencee && z.areaCommunePercentage >= 5)
+ && zonesSameType.some(z => !z.ressourceInfluencee && z.areaCommunePercentage >= 5)) {
+ zonesSameType = zonesSameType.filter(z => !z.ressourceInfluencee);
+ }
+
// Quand une seule zone, on l'agrandie à la geometrie de la commune
if (zonesSameType.length === 1 && zonesSameType[0].areaCommunePercentage >= 5) {
queries.push(this.getQueryToExtendZone(zonesSameType[0].id, commune.id));
@@ -429,7 +441,12 @@ export class ZoneAlerteComputedHistoricService {
}).niveauGravite;
for (const zoneType of zoneTypes) {
// Normalement il y a au maximum une zone par type mais si ils ont fait plusieurs AR avec des règles de gestions différentes il se peut que plusieurs zones AEP se superposent
- const zonesSameType = zones.filter(z => z.type === zoneType);
+ let zonesSameType = zones.filter(z => z.type === zoneType);
+
+ // Gestion des ressources influencées
+ if(zonesSameType.some(z => z.ressourceInfluencee) && zonesSameType.some(z => !z.ressourceInfluencee)) {
+ zonesSameType = zonesSameType.filter(z => !z.ressourceInfluencee);
+ }
if (zonesSameType.length === 1 && zonesSameType[0].niveauGravite !== maxNiveauGravite) {
@@ -461,7 +478,7 @@ export class ZoneAlerteComputedHistoricService {
} else {
queries.push(this.getQueryToExtendZone(zoneToKeep.id, commune.id));
}
- zonesSameType.filter(z => z.id !== zoneToKeep.id).forEach(z => {
+ zonesSameType.filter(z => z.id !== zoneToKeep.id && !z.ressourceInfluencee).forEach(z => {
queries.push(this.getQueryToReduceZone(z.id, commune.id));
});
@@ -531,6 +548,8 @@ export class ZoneAlerteComputedHistoricService {
// Au moins 1% de la surface en commun
.leftJoinAndSelect('commune', 'commune', 'commune.departement = departement.id AND ST_INTERSECTS(zone_alerte_computed_historic.geom, commune.geom) AND ST_Area(ST_Intersection(zone_alerte_computed_historic.geom, commune.geom)) / ST_AREA(commune.geom) > 0.01')
.where('departement.id = :id', { id: departement.id })
+ .andWhere('ST_IsValid(ST_TRANSFORM(zone_alerte_computed_historic.geom, 4326))')
+ .andWhere('ST_IsValid(ST_TRANSFORM(commune.geom, 4326))')
.getRawMany();
const toSave = [];
zones.forEach(z => {
@@ -613,6 +632,7 @@ export class ZoneAlerteComputedHistoricService {
.addSelect('zone_alerte_computed_historic.nom', 'nom')
.addSelect('zone_alerte_computed_historic.type', 'type')
.where('zone_alerte_computed_historic.id IN(:...zonesId)', { zonesId: zones.map(z => z.id) })
+ .andWhere('ST_IsValid(zone_alerte_computed_historic.geom)')
.andWhere('ST_INTERSECTS(zone_alerte_computed_historic.geom, (SELECT c.geom FROM commune as c WHERE c.id = :communeId))', { communeId })
// Au moins 1% de la surface en commun
.andWhere('ST_Area(ST_Intersection(zone_alerte_computed_historic.geom, (SELECT c.geom FROM commune as c WHERE c.id = :communeId))) / ST_Area((SELECT c.geom FROM commune as c WHERE c.id = :communeId)) > 0.01', { communeId })