From 5e1e6fe2b39061c522ff4319305d0312e1da033c Mon Sep 17 00:00:00 2001 From: "Yassine R." Date: Wed, 29 Nov 2023 23:42:33 +0100 Subject: [PATCH] fix(interaction): fix date of last interaction --- .../auth/services/structures-auth.service.ts | 4 + .../interactionRepository.service.ts | 47 +++++----- .../services/InteractionsDeletor.service.ts | 60 ++----------- .../getLastInteractionDate.service.ts | 86 +++++++++++++++++++ .../src/sms/services/message-sms.service.ts | 15 ++-- .../usagers-decision.controller.ts | 26 ++---- packages/frontend/src/assets/files/news.json | 2 +- 7 files changed, 142 insertions(+), 98 deletions(-) create mode 100644 packages/backend/src/interactions/services/getLastInteractionDate.service.ts diff --git a/packages/backend/src/auth/services/structures-auth.service.ts b/packages/backend/src/auth/services/structures-auth.service.ts index 72cbebe9e2..9f9f5932c9 100644 --- a/packages/backend/src/auth/services/structures-auth.service.ts +++ b/packages/backend/src/auth/services/structures-auth.service.ts @@ -25,6 +25,8 @@ export const APP_USER_PUBLIC_ATTRIBUTES: (keyof UserStructurePublic)[] = [ "lastLogin", "acceptTerms", "role", + "lastLogin", + "createdAt", ]; @Injectable() @@ -129,6 +131,8 @@ export class StructuresAuthService { "responsable", "structureType", "ville", + "lastLogin", + "createdAt", "sms", "portailUsager", "acceptTerms", diff --git a/packages/backend/src/database/services/interaction/interactionRepository.service.ts b/packages/backend/src/database/services/interaction/interactionRepository.service.ts index 9e56026928..74178887f6 100644 --- a/packages/backend/src/database/services/interaction/interactionRepository.service.ts +++ b/packages/backend/src/database/services/interaction/interactionRepository.service.ts @@ -1,4 +1,4 @@ -import { In, IsNull } from "typeorm"; +import { In, IsNull, Like, Not } from "typeorm"; import { getDateForMonthInterval } from "../../../stats/services"; import { FranceRegion } from "../../../util/territoires"; import { Usager, UserStructureAuthenticated } from "../../../_common/model"; @@ -13,7 +13,6 @@ import { InteractionType } from "@domifa/common"; export const interactionRepository = myDataSource .getRepository(InteractionsTable) .extend({ - findLastInteractionOk, findLastInteractionInWithContent, countInteractionsByMonth, countPendingInteraction, @@ -21,6 +20,7 @@ export const interactionRepository = myDataSource countVisiteOut, updateInteractionAfterDistribution, totalInteractionAllUsagersStructure, + getLastInteractionOut, }); async function updateInteractionAfterDistribution( @@ -40,25 +40,6 @@ async function updateInteractionAfterDistribution( ); } -async function findLastInteractionOk({ - user, - usager, -}: { - user: Pick; - usager: Pick; -}): Promise { - const lastInteractions = await interactionRepository.findOne({ - where: { - structureId: user.structureId, - usagerUUID: usager.uuid, - type: In(INTERACTION_OK_LIST), - }, - order: { dateInteraction: "DESC" }, - }); - - return lastInteractions ?? undefined; -} - async function findLastInteractionInWithContent({ user, usager, @@ -265,3 +246,27 @@ async function totalInteractionAllUsagersStructure({ }) ); } + +async function getLastInteractionOut( + usager: Pick +): Promise | null> { + return interactionRepository.findOne({ + where: [ + { + usagerUUID: usager.uuid, + type: In(INTERACTION_OK_LIST), + content: Not(Like(`'%Courrier remis au mandataire%' `)), + }, + { + usagerUUID: usager.uuid, + type: In(INTERACTION_OK_LIST), + content: IsNull(), + }, + ], + select: { + dateInteraction: true, + uuid: true, + }, + order: { dateInteraction: "DESC" }, + }); +} diff --git a/packages/backend/src/interactions/services/InteractionsDeletor.service.ts b/packages/backend/src/interactions/services/InteractionsDeletor.service.ts index ca682a19a1..42fd129728 100644 --- a/packages/backend/src/interactions/services/InteractionsDeletor.service.ts +++ b/packages/backend/src/interactions/services/InteractionsDeletor.service.ts @@ -1,21 +1,15 @@ import { Injectable, Inject, forwardRef } from "@nestjs/common"; -import { - interactionRepository, - usagerRepository, - userUsagerLoginRepository, -} from "../../database"; +import { interactionRepository, usagerRepository } from "../../database"; import { MessageSmsService } from "../../sms/services/message-sms.service"; import { Interactions, Usager, Structure, UsagerLight, - INTERACTION_OK_LIST, } from "../../_common/model"; import { interactionsCreator } from "./interactionsCreator.service"; import { interactionsTypeManager } from "./interactionsTypeManager.service"; -import { In, Like, Not } from "typeorm"; -import { differenceInCalendarDays } from "date-fns"; +import { getLastInteractionOut } from "./getLastInteractionDate.service"; @Injectable() export class InteractionsDeletor { @@ -67,51 +61,11 @@ export class InteractionsDeletor { }); } - if (INTERACTION_OK_LIST.indexOf(interaction.type) !== -1) { - const lastInteractionOut = await interactionRepository.findOne({ - where: { - usagerUUID: usager.uuid, - type: In(INTERACTION_OK_LIST), - content: Not(Like("%Courrier remis au mandataire%")), - uuid: Not(interaction.uuid), - }, - select: { - dateInteraction: true, - }, - order: { dateInteraction: "DESC" }, - }); - - usager.lastInteraction.dateInteraction = - lastInteractionOut?.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 ( - differenceInCalendarDays( - usager.lastInteraction.dateInteraction, - lastUserUsagerLogin.createdAt - ) > 0 - ) { - usager.lastInteraction.dateInteraction = - lastUserUsagerLogin.createdAt; - } - } - } + usager.lastInteraction.dateInteraction = await getLastInteractionOut( + usager, + structure, + interaction + ); return await interactionsCreator.updateUsagerAfterCreation({ usager, diff --git a/packages/backend/src/interactions/services/getLastInteractionDate.service.ts b/packages/backend/src/interactions/services/getLastInteractionDate.service.ts new file mode 100644 index 0000000000..be72f7415a --- /dev/null +++ b/packages/backend/src/interactions/services/getLastInteractionDate.service.ts @@ -0,0 +1,86 @@ +import { differenceInCalendarDays } from "date-fns"; +import { + INTERACTION_OK_LIST, + Interactions, + Structure, + Usager, +} from "../../_common/model"; + +import { + interactionRepository, + userUsagerLoginRepository, +} from "../../database"; +export const getLastInteractionOut = async ( + usager: Usager, + structure: Pick, + interaction?: Interactions +) => { + let dateInteraction = await getDateFromInteraction(usager, interaction); + dateInteraction = await getDateFromUserLogin( + usager, + structure, + dateInteraction + ); + + return shouldReturnDateInteraction(usager, dateInteraction) + ? dateInteraction + : usager.decision.dateDebut; +}; + +const getDateFromInteraction = async ( + usager: Usager, + interaction: Interactions +): Promise => { + if ( + (interaction && INTERACTION_OK_LIST.includes(interaction.type)) || + !interaction + ) { + const lastInteractionOut = + await interactionRepository.getLastInteractionOut(usager); + return lastInteractionOut ? lastInteractionOut.dateInteraction : null; + } + return null; +}; + +const getDateFromUserLogin = async ( + usager: Usager, + structure: Pick, + dateInteraction: Date | null +): Promise => { + 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 ( + !dateInteraction || + differenceInCalendarDays( + lastUserUsagerLogin.createdAt, + dateInteraction + ) > 0 + ) { + return lastUserUsagerLogin.createdAt; + } + } + } + return dateInteraction; +}; + +const shouldReturnDateInteraction = ( + usager: Usager, + dateInteraction: Date | null +): boolean => { + return ( + dateInteraction && + differenceInCalendarDays( + dateInteraction, + new Date(usager.decision.dateDebut) + ) > 0 + ); +}; diff --git a/packages/backend/src/sms/services/message-sms.service.ts b/packages/backend/src/sms/services/message-sms.service.ts index 4c88c2e2fc..a8de32434c 100644 --- a/packages/backend/src/sms/services/message-sms.service.ts +++ b/packages/backend/src/sms/services/message-sms.service.ts @@ -18,7 +18,11 @@ import { generateScheduleSendDate } from "./generators/generateScheduleSendDate" import { getPhoneString } from "../../util/phone/phoneUtils.service"; import { interactionsTypeManager } from "../../interactions/services"; import { PhoneNumberFormat } from "google-libphonenumber"; -import { INTERACTIONS_IN, INTERACTIONS_OUT } from "@domifa/common"; +import { + INTERACTIONS_IN, + INTERACTIONS_OUT, + InteractionType, +} from "@domifa/common"; @Injectable() export class MessageSmsService { @@ -26,7 +30,7 @@ export class MessageSmsService { public async deleteSmsInteractionOut( usager: Pick, structure: Pick, - interaction: InteractionDto + interactionType: InteractionType ) { if (!structure.sms.enabledByDomifa && !structure.sms.enabledByStructure) { return null; @@ -35,7 +39,7 @@ export class MessageSmsService { const smsOnHold = await messageSmsRepository.findSmsOnHold({ usagerRef: usager.ref, structureId: structure.id, - interactionType: interaction.type, + interactionType, }); if (smsOnHold) { @@ -145,7 +149,7 @@ export class MessageSmsService { if ( structure.sms.enabledByDomifa && structure.sms.enabledByStructure && - usager.contactByPhone === true + usager.contactByPhone ) { // Courrier / Colis / Recommandé entrant = Envoi de SMS à prévoir if (INTERACTIONS_IN.includes(interaction.type)) { @@ -156,8 +160,7 @@ export class MessageSmsService { const inType = interactionsTypeManager.getOppositeDirectionalType({ type: interaction.type, }); - interaction.type = inType; - await this.deleteSmsInteractionOut(usager, structure, interaction); + await this.deleteSmsInteractionOut(usager, structure, inType); } } return null; diff --git a/packages/backend/src/usagers/controllers/usagers-decision.controller.ts b/packages/backend/src/usagers/controllers/usagers-decision.controller.ts index 022da18b29..359eee0bb4 100644 --- a/packages/backend/src/usagers/controllers/usagers-decision.controller.ts +++ b/packages/backend/src/usagers/controllers/usagers-decision.controller.ts @@ -14,11 +14,7 @@ import { AuthGuard } from "@nestjs/passport"; import { ApiBearerAuth, ApiTags } from "@nestjs/swagger"; import { Response } from "express"; -import { - interactionRepository, - usagerNotesRepository, - usagerRepository, -} from "../../database"; +import { usagerNotesRepository, usagerRepository } from "../../database"; import { Usager, @@ -41,6 +37,7 @@ import { UsagerDecision, } from "@domifa/common"; import { format } from "date-fns"; +import { getLastInteractionOut } from "../../interactions/services/getLastInteractionDate.service"; @Controller("usagers-decision") @ApiTags("usagers-decision") @@ -145,20 +142,15 @@ export class UsagersDecisionController { // On récupère la dernière décision usager.decision = usager.historique[usager.historique.length - 1]; - const lastInteractionOk = await interactionRepository.findLastInteractionOk( - { - user, - usager, - } + usager.lastInteraction.dateInteraction = await getLastInteractionOut( + usager, + user.structure ); - // Si aucune interaction est trouvée, on remet la date de la décision actuelle - usager.lastInteraction.dateInteraction = lastInteractionOk - ? lastInteractionOk.dateInteraction - : usager.decision.dateDebut - ? usager.decision.dateDebut - : // Cas extrême, aucune date définie - usager.decision.dateDecision; + if (!usager.lastInteraction.dateInteraction) { + usager.lastInteraction.dateInteraction = + usager.decision.dateDebut ?? usager.decision.dateDecision; + } const createdBy = { userId: user.id, diff --git a/packages/frontend/src/assets/files/news.json b/packages/frontend/src/assets/files/news.json index 4990ee7292..1575afbadc 100644 --- a/packages/frontend/src/assets/files/news.json +++ b/packages/frontend/src/assets/files/news.json @@ -1,7 +1,7 @@ [ { "date": "2023-11-30", - "description": "Nouveautés du 30 Novembre 2023", + "description": "", "content": [ { "type": "new",