diff --git a/backend/src/indicateurs/shared/models/delete-valeur-indicateur.request.ts b/backend/src/indicateurs/shared/models/delete-valeur-indicateur.request.ts new file mode 100644 index 0000000000..d622a25008 --- /dev/null +++ b/backend/src/indicateurs/shared/models/delete-valeur-indicateur.request.ts @@ -0,0 +1,12 @@ +import { z } from 'zod'; + +/** Suppression d'une valeur d'indicateur pour une collectivité */ +export const deleteValeurIndicateurSchema = z.object({ + collectiviteId: z.number(), + indicateurId: z.number(), + id: z.number(), +}); + +export type DeleteValeurIndicateur = z.infer< + typeof deleteValeurIndicateurSchema +>; diff --git a/backend/src/indicateurs/valeurs/crud-valeurs.router.e2e-spec.ts b/backend/src/indicateurs/valeurs/crud-valeurs.router.e2e-spec.ts index 164355bcef..a24b80884c 100644 --- a/backend/src/indicateurs/valeurs/crud-valeurs.router.e2e-spec.ts +++ b/backend/src/indicateurs/valeurs/crud-valeurs.router.e2e-spec.ts @@ -176,4 +176,41 @@ describe("Route de lecture/écriture des valeurs d'indicateurs", () => { }; await expect(caller.indicateurs.valeurs.upsert(input)).rejects.toThrow(); }); + + test('Permet de supprimer une valeur', async () => { + const caller = router.createCaller({ user: yoloDodoUser }); + + // insère une valeur + const inputInsert: InputUpsert = { + collectiviteId, + indicateurId, + dateValeur: '2021-01-01', + resultat: 42, + resultatCommentaire: 'commentaire', + }; + await caller.indicateurs.valeurs.upsert(inputInsert); + + // vérifie le nombre de valeurs avant la suppression + const inputBefore: InputList = { + collectiviteId, + indicateurIds: [indicateurId], + }; + const resultBefore = await caller.indicateurs.valeurs.list(inputBefore); + expect( + resultBefore.indicateurs[0].sources.collectivite.valeurs.length + ).toBe(1); + + // supprime l'entrée + const valeurId = + resultBefore.indicateurs[0].sources.collectivite.valeurs[0].id; + await caller.indicateurs.valeurs.delete({ + collectiviteId, + indicateurId, + id: valeurId, + }); + + // vérifie le nombre de valeurs après la suppression + const resultAfter = await caller.indicateurs.valeurs.list(inputBefore); + expect(resultAfter.indicateurs.length).toBe(0); + }); }); diff --git a/backend/src/indicateurs/valeurs/crud-valeurs.router.ts b/backend/src/indicateurs/valeurs/crud-valeurs.router.ts index 05603d987c..ce6deecd90 100644 --- a/backend/src/indicateurs/valeurs/crud-valeurs.router.ts +++ b/backend/src/indicateurs/valeurs/crud-valeurs.router.ts @@ -1,6 +1,6 @@ import { TrpcService } from '@/backend/utils/trpc/trpc.service'; import { Injectable } from '@nestjs/common'; -import { upsertValeurIndicateurSchema } from '../index-domain'; +import { deleteValeurIndicateurSchema } from '../shared/models/delete-valeur-indicateur.request'; import { getIndicateursValeursRequestSchema } from '../shared/models/get-indicateurs.request'; import { upsertValeurIndicateurSchema } from '../shared/models/upsert-valeur-indicateur.request'; import IndicateurValeursService from './crud-valeurs.service'; @@ -23,5 +23,10 @@ export class IndicateurValeursRouter { .mutation(({ input, ctx }) => { return this.service.upsertValeur(input, ctx.user); }), + delete: this.trpc.authedProcedure + .input(deleteValeurIndicateurSchema) + .mutation(({ input, ctx }) => { + return this.service.deleteValeurIndicateur(input, ctx.user); + }), }); } diff --git a/backend/src/indicateurs/valeurs/crud-valeurs.service.ts b/backend/src/indicateurs/valeurs/crud-valeurs.service.ts index 59fa6ec8ab..8ca66bd504 100644 --- a/backend/src/indicateurs/valeurs/crud-valeurs.service.ts +++ b/backend/src/indicateurs/valeurs/crud-valeurs.service.ts @@ -22,6 +22,7 @@ import * as _ from 'lodash'; import { AuthenticatedUser, AuthRole } from '../../auth/models/auth.models'; import { DatabaseService } from '../../utils/database/database.service'; import { DeleteIndicateursValeursRequestType } from '../shared/models/delete-indicateurs.request'; +import { DeleteValeurIndicateur } from '../shared/models/delete-valeur-indicateur.request'; import { GetIndicateursValeursRequestType } from '../shared/models/get-indicateurs.request'; import { GetIndicateursValeursResponseType } from '../shared/models/get-indicateurs.response'; import { @@ -368,6 +369,31 @@ export default class CrudValeursService { } } + async deleteValeurIndicateur( + data: DeleteValeurIndicateur, + tokenInfo: AuthenticatedUser + ) { + const { collectiviteId, indicateurId, id } = data; + await this.permissionService.isAllowed( + tokenInfo, + PermissionOperation.INDICATEURS_EDITION, + ResourceType.COLLECTIVITE, + collectiviteId + ); + + if (tokenInfo.role === AuthRole.AUTHENTICATED && tokenInfo.id) { + await this.databaseService.db + .delete(indicateurValeurTable) + .where( + and( + eq(indicateurValeurTable.collectiviteId, collectiviteId), + eq(indicateurValeurTable.indicateurId, indicateurId), + eq(indicateurValeurTable.id, id) + ) + ); + } + } + async upsertIndicateurValeurs( indicateurValeurs: IndicateurValeurInsert[], tokenInfo: AuthenticatedUser | undefined