Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ajoute l'entrée tRPC de lecture/màj des valeurs d'indicateur #3517

Merged
merged 6 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions backend/src/indicateurs/indicateurs.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import TrajectoiresXlsxService from './trajectoires/trajectoires-xlsx.service';
import { TrajectoiresController } from './trajectoires/trajectoires.controller';
import { TrajectoiresRouter } from './trajectoires/trajectoires.router';
import { IndicateursController } from './valeurs/crud-valeurs.controller';
import { IndicateurValeursRouter } from './valeurs/crud-valeurs.router';
import CrudValeursService from './valeurs/crud-valeurs.service';

@Module({
Expand All @@ -25,6 +26,7 @@ import CrudValeursService from './valeurs/crud-valeurs.service';
CrudValeursService,
IndicateurFiltreService,
IndicateurFiltreRouter,
IndicateurValeursRouter,
TrajectoiresDataService,
TrajectoiresSpreadsheetService,
TrajectoiresXlsxService,
Expand All @@ -37,6 +39,7 @@ import CrudValeursService from './valeurs/crud-valeurs.service';
TrajectoiresRouter,
IndicateurFiltreService,
IndicateurFiltreRouter,
IndicateurValeursRouter,
],
controllers: [
IndicateursController,
Expand Down
Original file line number Diff line number Diff line change
@@ -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
>;
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,4 @@ export interface IndicateurValeurAvecMetadonnesDefinition {

indicateur_source_metadonnee: SourceMetadonnee | null;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { z } from 'zod';
import { indicateurValeurSchemaInsert } from './indicateur-valeur.table';

/** Upsert d'une valeur d'indicateur pour une collectivité */
export const upsertValeurIndicateurSchema = indicateurValeurSchemaInsert
.pick({
collectiviteId: true,
indicateurId: true,
id: true,
resultat: true,
resultatCommentaire: true,
objectif: true,
objectifCommentaire: true,
})
.extend({
dateValeur: indicateurValeurSchemaInsert.shape.dateValeur.optional(),
});

export type UpsertValeurIndicateur = z.infer<
typeof upsertValeurIndicateurSchema
>;
216 changes: 216 additions & 0 deletions backend/src/indicateurs/valeurs/crud-valeurs.router.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
import { INestApplication } from '@nestjs/common';
import { inferProcedureInput } from '@trpc/server';
import { and, eq } from 'drizzle-orm';
import { getTestApp } from '../../../test/app-utils';
import { getAuthUser } from '../../../test/auth-utils';
import { AuthenticatedUser } from '../../auth/models/auth.models';
import { DatabaseService } from '../../utils';
import { AppRouter, TrpcRouter } from '../../utils/trpc/trpc.router';
import { indicateurValeurTable } from '../index-domain';
import { getIndicateursValeursResponseSchema } from '../shared/models/get-indicateurs.response';

type InputList = inferProcedureInput<
AppRouter['indicateurs']['valeurs']['list']
>;

type InputUpsert = inferProcedureInput<
AppRouter['indicateurs']['valeurs']['upsert']
>;

const collectiviteId = 1;
const indicateurId = 1;

describe("Route de lecture/écriture des valeurs d'indicateurs", () => {
let app: INestApplication;
let router: TrpcRouter;
let yoloDodoUser: AuthenticatedUser;
let databaseService: DatabaseService;

beforeAll(async () => {
app = await getTestApp();
router = app.get(TrpcRouter);
yoloDodoUser = await getAuthUser();
databaseService = app.get<DatabaseService>(DatabaseService);
});

beforeEach(async () => {
// reset les données avant de commencer les tests
await databaseService.db
.delete(indicateurValeurTable)
.where(
and(
eq(indicateurValeurTable.collectiviteId, collectiviteId),
eq(indicateurValeurTable.indicateurId, indicateurId)
)
);
});

test(`Renvoi des valeurs`, async () => {
const caller = router.createCaller({ user: yoloDodoUser });

const input: InputList = {
collectiviteId,
identifiantsReferentiel: 'cae_8',
};
const result = await caller.indicateurs.valeurs.list(input);
expect(result.indicateurs.length).not.toBe(0);
expect(result.indicateurs[0].sources.collectivite.valeurs.length).not.toBe(
0
);
const toCheck = getIndicateursValeursResponseSchema.safeParse(result);
expect(toCheck.success).toBeTruthy;
});

test("Permet d'insérer une valeur", async () => {
const caller = router.createCaller({ user: yoloDodoUser });

// vérifie le nombre de valeurs avant insertion
const inputBefore: InputList = {
collectiviteId,
indicateurIds: [indicateurId],
};
const resultBefore = await caller.indicateurs.valeurs.list(inputBefore);
expect(resultBefore.indicateurs.length).toBe(0);

// insère une valeur
const input: InputUpsert = {
collectiviteId,
indicateurId,
dateValeur: '2021-01-01',
resultat: 42,
resultatCommentaire: 'commentaire',
};
const result = await caller.indicateurs.valeurs.upsert(input);
expect(result).not.toBe(null);

// vérifie le nombre de valeurs après insertion
const resultAfter = await caller.indicateurs.valeurs.list(inputBefore);
expect(resultAfter.indicateurs[0].sources.collectivite.valeurs.length).toBe(
1
);
});

test('Permet de mettre à jour 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 mise à jour
const inputBefore: InputList = {
collectiviteId,
indicateurIds: [indicateurId],
};
const resultBefore = await caller.indicateurs.valeurs.list(inputBefore);
expect(
resultBefore.indicateurs[0].sources.collectivite.valeurs.length
).toBe(1);

// met à jour que la valeur
const inputUpdate: InputUpsert = {
collectiviteId,
indicateurId,
id: resultBefore.indicateurs[0].sources.collectivite.valeurs[0].id,
resultat: 43,
};
const result = await caller.indicateurs.valeurs.upsert(inputUpdate);
expect(result).not.toBe(null);

// vérifie le nombre de valeurs après mise à jour
const resultAfter = await caller.indicateurs.valeurs.list(inputBefore);
expect(resultAfter.indicateurs[0].sources.collectivite.valeurs.length).toBe(
1
);
expect(
resultAfter.indicateurs[0].sources.collectivite.valeurs[0].resultat
).toBe(43);
expect(
resultAfter.indicateurs[0].sources.collectivite.valeurs[0]
.resultatCommentaire
).toBe('commentaire');

// met à jour la valeur objectif pour la même date
const inputUpdateObjectif: InputUpsert = {
collectiviteId,
indicateurId,
id: resultBefore.indicateurs[0].sources.collectivite.valeurs[0].id,
objectif: 44,
};
const resultObjectif = await caller.indicateurs.valeurs.upsert(
inputUpdateObjectif
);
expect(resultObjectif).not.toBe(null);

// vérifie le nombre de valeurs après mise à jour
const resultAfterObjectif = await caller.indicateurs.valeurs.list(
inputBefore
);
expect(
resultAfterObjectif.indicateurs[0].sources.collectivite.valeurs.length
).toBe(1);
expect(
resultAfterObjectif.indicateurs[0].sources.collectivite.valeurs[0]
.resultat
).toBe(43);
expect(
resultAfterObjectif.indicateurs[0].sources.collectivite.valeurs[0]
.objectif
).toBe(44);
});

test("Ne permet pas d'insérer une valeur si on n'a pas le droit requis", async () => {
const caller = router.createCaller({ user: yoloDodoUser });

const input: InputUpsert = {
collectiviteId: 100,
indicateurId: 1,
dateValeur: '2021-01-01',
resultat: 42,
};
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);
});
});
32 changes: 32 additions & 0 deletions backend/src/indicateurs/valeurs/crud-valeurs.router.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { TrpcService } from '@/backend/utils/trpc/trpc.service';
import { Injectable } from '@nestjs/common';
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';

@Injectable()
export class IndicateurValeursRouter {
constructor(
private readonly trpc: TrpcService,
private readonly service: IndicateurValeursService
) {}

router = this.trpc.router({
list: this.trpc.authedProcedure
.input(getIndicateursValeursRequestSchema)
.query(({ ctx, input }) => {
return this.service.getIndicateurValeursGroupees(input, ctx.user);
}),
upsert: this.trpc.authedProcedure
.input(upsertValeurIndicateurSchema)
.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);
}),
});
}
Loading
Loading