From 73626e2311d454e50536157318c9656f32ff5eb8 Mon Sep 17 00:00:00 2001 From: Yassine R Date: Tue, 21 Nov 2023 23:05:29 +0100 Subject: [PATCH] fix: delete interaction --- .talismanrc | 2 + _scripts/dev/local-node.dockerfile | 2 +- .../interactionRepository.service.ts | 57 +--------- .../interactions/interactions.controller.ts | 1 - .../InteractionsDeletor.service.spec.ts | 101 ++++++++++++++---- .../services/InteractionsDeletor.service.ts | 84 +++++++++------ .../interactionsCreator.service.spec.ts | 13 +-- .../services/interactionsCreator.service.ts | 31 +++--- .../sms/services/message-sms.service.spec.ts | 1 - 9 files changed, 148 insertions(+), 144 deletions(-) diff --git a/.talismanrc b/.talismanrc index bc5d80e473..0bee6f9557 100644 --- a/.talismanrc +++ b/.talismanrc @@ -7,6 +7,8 @@ fileignoreconfig: checksum: bd05dd6b68f7fe2ca36ab1180a0449878cf78f4e048d2e5979b3dbe5fba1db53 - filename: packages/backend/src/_migrations/_init-db/1603812391580-pr-env-create-database.ts checksum: 586e3b26481d71256a1b7626956aaf9e68211dfbda527dd862a2aad075b5cc04 +- filename: packages/backend/src/interactions/services/InteractionsDeletor.service.spec.ts + checksum: b66659fea19859e55afaf0ed47519f0804857e486b2ecc6b01d5ae96f1a86a0b - filename: yarn.lock checksum: 4ac842f95592d194e65b208fdc4b9a78a0bb6470ad2d4950626c2ffcec831a33 version: "1.0" diff --git a/_scripts/dev/local-node.dockerfile b/_scripts/dev/local-node.dockerfile index baa6f476e0..06feda2fe5 100644 --- a/_scripts/dev/local-node.dockerfile +++ b/_scripts/dev/local-node.dockerfile @@ -1,4 +1,4 @@ -FROM node:16.18-bullseye +FROM node:18.20.0-bullseye USER root diff --git a/packages/backend/src/database/services/interaction/interactionRepository.service.ts b/packages/backend/src/database/services/interaction/interactionRepository.service.ts index 6024b3a34a..9e56026928 100644 --- a/packages/backend/src/database/services/interaction/interactionRepository.service.ts +++ b/packages/backend/src/database/services/interaction/interactionRepository.service.ts @@ -1,11 +1,7 @@ import { In, IsNull } from "typeorm"; import { getDateForMonthInterval } from "../../../stats/services"; import { FranceRegion } from "../../../util/territoires"; -import { - Structure, - Usager, - UserStructureAuthenticated, -} from "../../../_common/model"; +import { Usager, UserStructureAuthenticated } from "../../../_common/model"; import { INTERACTION_OK_LIST, Interactions, @@ -13,8 +9,6 @@ import { import { InteractionsTable } from "../../entities"; import { myDataSource } from "../_postgres"; import { InteractionType } from "@domifa/common"; -import { userUsagerLoginRepository } from "../user-usager"; -import { differenceInMinutes } from "date-fns"; export const interactionRepository = myDataSource .getRepository(InteractionsTable) @@ -117,15 +111,12 @@ async function countPendingInteraction({ async function countPendingInteractionsIn({ usager, - structure, }: { usager: Pick; - structure: Pick; }): Promise<{ courrierIn: number; recommandeIn: number; colisIn: number; - dateInteraction: Date | null; }> { // NOTE: cette requête ne renvoit pas de résultats pour les usagers de cette structure qui n'ont pas d'interaction const results: { @@ -145,55 +136,11 @@ async function countPendingInteractionsIn({ ) .where({ usagerUUID: usager.uuid, interactionOutUUID: IsNull() }) .getRawOne(); - - const lastInteractionDate = await interactionRepository.findOne({ - where: { - usagerUUID: usager.uuid, - type: In(INTERACTION_OK_LIST), - }, - select: { - dateInteraction: true, - }, - order: { dateInteraction: "DESC" }, - }); - - const lastInteractions = { + return { courrierIn: parseInt(results.courrierIn, 10), recommandeIn: parseInt(results.recommandeIn, 10), colisIn: parseInt(results.colisIn, 10), - // Si aucune interaction, on récupère la date de début du statut actuel (domicilié, radié, etc) - dateInteraction: - lastInteractionDate?.dateInteraction ?? usager.decision.dateDebut, }; - - // Si le portail est activé, on récupère la date de dernière connexion - if ( - structure.portailUsager.usagerLoginUpdateLastInteraction && - usager.options.portailUsagerEnabled - ) { - const lastUserUsagerLogin = await userUsagerLoginRepository.findOne({ - where: { - usagerUUID: usager.uuid, - }, - select: { - createdAt: true, - }, - order: { createdAt: "DESC" }, - }); - - if (lastUserUsagerLogin?.createdAt) { - if ( - differenceInMinutes( - lastInteractions.dateInteraction, - lastUserUsagerLogin.createdAt - ) > 0 - ) { - lastInteractions.dateInteraction = lastUserUsagerLogin.createdAt; - } - } - } - - return lastInteractions; } async function countInteractionsByMonth( diff --git a/packages/backend/src/interactions/interactions.controller.ts b/packages/backend/src/interactions/interactions.controller.ts index bc0778b078..579f4cccfd 100644 --- a/packages/backend/src/interactions/interactions.controller.ts +++ b/packages/backend/src/interactions/interactions.controller.ts @@ -142,7 +142,6 @@ export class InteractionsController { ) { return this.interactionDeletor.deleteInteraction({ interaction, - user, usager, structure: user.structure, }); diff --git a/packages/backend/src/interactions/services/InteractionsDeletor.service.spec.ts b/packages/backend/src/interactions/services/InteractionsDeletor.service.spec.ts index 0f96ead8f0..cabff78888 100644 --- a/packages/backend/src/interactions/services/InteractionsDeletor.service.spec.ts +++ b/packages/backend/src/interactions/services/InteractionsDeletor.service.spec.ts @@ -7,7 +7,11 @@ import { import { StructuresModule } from "../../structures/structure.module"; import { UsagersModule } from "../../usagers/usagers.module"; import { UsersModule } from "../../users/users.module"; -import { AppTestContext, AppTestHelper } from "../../util/test"; +import { + AppTestContext, + AppTestHelper, + JEST_FAKE_TIMER, +} from "../../util/test"; import { Structure, Usager, UserStructure } from "../../_common/model"; import { InteractionDto } from "../dto"; import { InteractionsModule } from "../interactions.module"; @@ -20,8 +24,14 @@ describe("InteractionsDeletor", () => { let user: UserStructure; let usager: Usager; let structure: Structure; + let firstDateInteraction: Date; + const MOCKED_NEW_DATE = "2022-12-12T19:45:30.000Z"; beforeAll(async () => { + jest + .useFakeTimers(JEST_FAKE_TIMER) + .setSystemTime(new Date(MOCKED_NEW_DATE)); + context = await AppTestHelper.bootstrapTestApp({ imports: [ InteractionsModule, @@ -37,12 +47,15 @@ describe("InteractionsDeletor", () => { id: 1, }); usager = await usagerRepository.findOneBy({ - ref: 2, + ref: 6, structureId: 1, }); structure = await structureRepository.findOneBy({ id: 1, }); + user.structure = structure; + const lastInteraction = { ...usager.lastInteraction }; + firstDateInteraction = new Date(lastInteraction.dateInteraction); }); afterAll(async () => { @@ -53,14 +66,7 @@ describe("InteractionsDeletor", () => { expect(interactionsDeletor).toBeDefined(); }); - it("Réception, suppression et restauration de 5 colis", async () => { - const usagerBefore = await usagerRepository.findOneBy({ - ref: 2, - structureId: 1, - }); - - user.structure = await structureRepository.findOneBy({ id: 5 }); - + it("Réception, suppression de 5 colis", async () => { const interaction1 = new InteractionDto(); interaction1.type = "colisIn"; interaction1.content = "Colis d'un distributeur"; @@ -72,20 +78,69 @@ describe("InteractionsDeletor", () => { user, }); - expect(usagerAfterCreate.lastInteraction.colisIn).toEqual( - usagerBefore.lastInteraction.colisIn + 5 + expect(usagerAfterCreate.lastInteraction.colisIn).toEqual(5); + + const usagerAfterDelete = await interactionsDeletor.deleteInteraction({ + interaction: interactionCreated, + usager: usagerAfterCreate, + structure, + }); + expect(usagerAfterDelete.lastInteraction.colisIn).toEqual( + usager.lastInteraction.colisIn ); + }); - { - const usagerAfterDelete = await interactionsDeletor.deleteInteraction({ - interaction: interactionCreated, - usager: usagerAfterCreate, - user, - structure, - }); - expect(usagerAfterDelete.lastInteraction.colisIn).toEqual( - usagerBefore.lastInteraction.colisIn - ); - } + it("Distribution: doit mettre à jour la date de dernier passage", async () => { + usager = await usagerRepository.findOneBy({ + ref: 6, + structureId: 1, + }); + + const interaction1 = new InteractionDto(); + interaction1.type = "colisIn"; + interaction1.nbCourrier = 9; + const { usager: newUsager } = await interactionsCreator.createInteraction({ + interaction: interaction1, + usager, + user, + }); + + // Changement de la date par défaut pour la distribution + jest + .useFakeTimers(JEST_FAKE_TIMER) + .setSystemTime(new Date("2023-01-12T19:45:30.000Z")); + + const interaction: InteractionDto = { + type: "colisOut", + content: "Distribution de colis sans procuration", + nbCourrier: 9, + structureId: 1, + userId: 1, + usagerRef: usager.ref, + userName: "Nom", + dateInteraction: new Date(), + }; + + const resultat = await interactionsCreator.createInteraction({ + usager: newUsager, + user, + interaction, + }); + + expect(resultat.usager.lastInteraction.colisIn).toEqual(0); + expect(new Date(resultat.usager.lastInteraction.dateInteraction)).toEqual( + new Date() + ); + + const test = await interactionsDeletor.deleteInteraction({ + usager: resultat.usager, + structure, + interaction: resultat.interaction, + }); + + expect(new Date(test.lastInteraction.dateInteraction)).toEqual( + firstDateInteraction + ); + expect(test.lastInteraction.colisIn).toEqual(9); }); }); diff --git a/packages/backend/src/interactions/services/InteractionsDeletor.service.ts b/packages/backend/src/interactions/services/InteractionsDeletor.service.ts index 89e2fdea45..67efd76ddc 100644 --- a/packages/backend/src/interactions/services/InteractionsDeletor.service.ts +++ b/packages/backend/src/interactions/services/InteractionsDeletor.service.ts @@ -1,16 +1,21 @@ import { Injectable, Inject, forwardRef } from "@nestjs/common"; -import { interactionRepository, usagerRepository } from "../../database"; +import { + interactionRepository, + usagerRepository, + userUsagerLoginRepository, +} from "../../database"; import { MessageSmsService } from "../../sms/services/message-sms.service"; import { Interactions, Usager, - UserStructure, Structure, UsagerLight, INTERACTION_OK_LIST, } from "../../_common/model"; import { interactionsCreator } from "./interactionsCreator.service"; import { interactionsTypeManager } from "./interactionsTypeManager.service"; +import { In } from "typeorm"; +import { differenceInCalendarDays } from "date-fns"; @Injectable() export class InteractionsDeletor { @@ -22,18 +27,18 @@ export class InteractionsDeletor { public async deleteInteraction({ interaction, usager, - user, structure, }: { interaction: Interactions; usager: Usager; - user: Pick< - UserStructure, - "id" | "structureId" | "nom" | "prenom" | "structure" - >; - structure: Pick; + structure: Pick; }): Promise { const direction = interactionsTypeManager.getDirection(interaction); + + await interactionRepository.delete({ + uuid: interaction.uuid, + }); + if (direction === "in") { // Suppression du SMS en file d'attente await this.smsService.deleteSmsInteraction( @@ -53,6 +58,21 @@ export class InteractionsDeletor { structure, usager, }); + + // + const lastInteractionOut = await interactionRepository.findOne({ + where: { + usagerUUID: usager.uuid, + type: In(INTERACTION_OK_LIST), + }, + select: { + dateInteraction: true, + }, + order: { dateInteraction: "DESC" }, + }); + + usager.lastInteraction.dateInteraction = + lastInteractionOut?.dateInteraction ?? usager.decision.dateDebut; } else if (interaction.type === "npai") { usager.options.npai.actif = false; usager.options.npai.dateDebut = null; @@ -62,35 +82,35 @@ export class InteractionsDeletor { }); } - await interactionRepository.delete({ - uuid: interaction.uuid, - }); - - const dateInteractionWithGoodTimeZone = new Date( - usager.lastInteraction.dateInteraction - ); - - // Récupération de la bonne date de dernière interaction - if (INTERACTION_OK_LIST.indexOf(interaction.type) !== -1) { - // Seulement si aucun autre évènement n'a déjà changé la date de dernier passage - // C'est possible si un renouvellement a été effectué après la saisie de ce courrier - if (dateInteractionWithGoodTimeZone <= interaction.dateInteraction) { - const lastInteractionOk = - await interactionRepository.findLastInteractionOk({ - user, - usager, - }); + // Si le portail est activé, on récupère la date de dernière connexion + if ( + structure.portailUsager.usagerLoginUpdateLastInteraction && + usager.options.portailUsagerEnabled + ) { + const lastUserUsagerLogin = await userUsagerLoginRepository.findOne({ + where: { + usagerUUID: usager.uuid, + }, + select: { + createdAt: true, + }, + order: { createdAt: "DESC" }, + }); - // Si aucune interaction est trouvée, on remet la date de la décision actuelle - usager.lastInteraction.dateInteraction = lastInteractionOk - ? lastInteractionOk.dateInteraction - : usager.decision.dateDebut; + if (lastUserUsagerLogin?.createdAt) { + if ( + differenceInCalendarDays( + usager.lastInteraction.dateInteraction, + lastUserUsagerLogin.createdAt + ) > 0 + ) { + usager.lastInteraction.dateInteraction = + lastUserUsagerLogin.createdAt; + } } } - return await interactionsCreator.updateUsagerAfterCreation({ usager, - structure: user.structure, }); } } diff --git a/packages/backend/src/interactions/services/interactionsCreator.service.spec.ts b/packages/backend/src/interactions/services/interactionsCreator.service.spec.ts index 529f1135d4..7f94b514a3 100644 --- a/packages/backend/src/interactions/services/interactionsCreator.service.spec.ts +++ b/packages/backend/src/interactions/services/interactionsCreator.service.spec.ts @@ -89,10 +89,9 @@ describe("interactionsCreator", () => { { sms: user.structure.sms } ); await interactionRepository.delete({ - usagerRef: 2, + usagerUUID: usager.uuid, structureId: 1, }); - await usagerRepository.update({}, { contactByPhone: false }); await messageSmsRepository.delete({ structureId: user.structureId }); await AppTestHelper.tearDownTestApp(context); }); @@ -151,23 +150,19 @@ describe("interactionsCreator", () => { newusager.lastInteraction.dateInteraction ); - // clean const deleteSecondInteraction = await interactionsDeletor.deleteInteraction({ interaction: secondResult.interaction, structure: user.structure, usager, - user, }); expect(deleteSecondInteraction.lastInteraction.courrierIn).toEqual(10); - // clean const deletedFirstInteraction = await interactionsDeletor.deleteInteraction({ interaction: firstResult.interaction, structure: user.structure, usager, - user, }); expect(deletedFirstInteraction.lastInteraction.courrierIn).toEqual(0); }); @@ -208,7 +203,6 @@ describe("interactionsCreator", () => { interaction: resultat.interaction, structure: user.structure, usager, - user, }); }); }); @@ -255,7 +249,6 @@ describe("interactionsCreator", () => { interaction: resultat.interaction, structure: user.structure, usager, - user, }); }); }); @@ -299,7 +292,6 @@ describe("interactionsCreator", () => { interaction: resultat.interaction, structure: user.structure, usager, - user, }); // Après suppression, date de dernier passage doit être la même qu'au début expect(usagerAfterDelete.lastInteraction.dateInteraction).toBeDefined(); @@ -355,7 +347,6 @@ describe("interactionsCreator", () => { interaction: resultat.interaction, structure: user.structure, usager, - user, }); const diffHours = differenceInHours( @@ -423,14 +414,12 @@ describe("interactionsCreator", () => { interaction: createdInteractionIn.interaction, structure: user.structure, usager, - user, }); // clean await interactionsDeletor.deleteInteraction({ interaction: resultat.interaction, structure: user.structure, usager, - user, }); }); }); diff --git a/packages/backend/src/interactions/services/interactionsCreator.service.ts b/packages/backend/src/interactions/services/interactionsCreator.service.ts index e286de20c7..5331b60e16 100644 --- a/packages/backend/src/interactions/services/interactionsCreator.service.ts +++ b/packages/backend/src/interactions/services/interactionsCreator.service.ts @@ -3,12 +3,7 @@ import { InteractionsTable, usagerRepository, } from "../../database"; -import { - Usager, - UserStructure, - Interactions, - Structure, -} from "../../_common/model"; +import { Usager, UserStructure, Interactions } from "../../_common/model"; import { InteractionDto } from "../dto"; import { interactionsTypeManager } from "./interactionsTypeManager.service"; @@ -121,7 +116,6 @@ async function createInteraction({ // Mise à jour des infos de dernier passage pour l'usager const usagerUpdated = await updateUsagerAfterCreation({ usager, - structure: user.structure, }); return { usager: usagerUpdated, interaction: interactionCreated }; @@ -129,26 +123,25 @@ async function createInteraction({ async function updateUsagerAfterCreation({ usager, - structure, }: { - structure: Pick; usager: Pick; }): Promise { - const lastInteractions = + const pendingInteractionsIn = await interactionRepository.countPendingInteractionsIn({ usager, - structure, }); - usager.lastInteraction = { - ...lastInteractions, - enAttente: - usager.lastInteraction.courrierIn > 0 || - usager.lastInteraction.colisIn > 0 || - usager.lastInteraction.recommandeIn > 0, - }; return usagerRepository.updateOneAndReturn(usager.uuid, { updatedAt: new Date(), - lastInteraction: usager.lastInteraction, + lastInteraction: { + ...usager.lastInteraction, + courrierIn: pendingInteractionsIn.courrierIn, + colisIn: pendingInteractionsIn.colisIn, + recommandeIn: pendingInteractionsIn.recommandeIn, + enAttente: + pendingInteractionsIn.courrierIn > 0 || + pendingInteractionsIn.colisIn > 0 || + pendingInteractionsIn.recommandeIn > 0, + }, }); } diff --git a/packages/backend/src/sms/services/message-sms.service.spec.ts b/packages/backend/src/sms/services/message-sms.service.spec.ts index d2f331e2dc..92a635a6db 100644 --- a/packages/backend/src/sms/services/message-sms.service.spec.ts +++ b/packages/backend/src/sms/services/message-sms.service.spec.ts @@ -135,7 +135,6 @@ describe("MessageSmsService", () => { interaction: created.interaction, structure: user.structure, usager, - user, }); expect(deletedFirstInteraction.lastInteraction.courrierIn).toEqual(0); });