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

Fix delete interaction #3065

Merged
merged 2 commits into from
Nov 21, 2023
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
2 changes: 2 additions & 0 deletions .talismanrc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
2 changes: 1 addition & 1 deletion _scripts/dev/local-node.dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:16.18-bullseye
FROM node:18.20.0-bullseye

USER root

Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import { In } from "typeorm";
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,
} from "../../../_common/model/interaction";
import { InteractionsTable } from "../../entities";
import { myDataSource } from "../_postgres";
import { InteractionType } from "@domifa/common";
import { userUsagerLoginRepository } from "../user-usager";
import { differenceInMinutes, parseISO } from "date-fns";

export const interactionRepository = myDataSource
.getRepository<Interactions>(InteractionsTable)
Expand All @@ -34,9 +28,15 @@ async function updateInteractionAfterDistribution(
interaction: Interactions,
oppositeType: InteractionType
): Promise<void> {
return interactionRepository.query(
`UPDATE interactions SET "interactionOutUUID" = $1 where "usagerUUID" = $2 AND type = $3 AND "interactionOutUUID" is null`,
[interaction.uuid, usager.uuid, oppositeType]
await interactionRepository.update(
{
usagerUUID: usager.uuid,
type: oppositeType,
interactionOutUUID: IsNull(),
},
{
interactionOutUUID: interaction.uuid,
}
);
}

Expand Down Expand Up @@ -90,95 +90,56 @@ async function countPendingInteraction({
interactionType: InteractionType;
}): Promise<number> {
// NOTE: cette requête ne renvoit pas de résultats pour les usagers de cette structure qui n'ont pas d'interaction
const query = `
SELECT
coalesce (SUM(CASE WHEN i.type = $1 THEN "nbCourrier" END), 0) AS "nbInteractions"
FROM interactions i
WHERE i."structureId" = $2 AND i."usagerUUID" = $3 AND i."interactionOutUUID" is null
GROUP BY i."usagerUUID"`;
const results = await interactionRepository.query(query, [
interactionType,
structureId,
usagerUUID,
]);
const results:
| {
total: string;
}
| undefined = await interactionRepository
.createQueryBuilder("interactions")
.select(`SUM("nbCourrier")`, "total")
.where({
structureId,
type: interactionType,
usagerUUID,
interactionOutUUID: IsNull(),
})
.groupBy(`"usagerUUID"`)
.getRawOne();

if (typeof results[0] === "undefined") {
return 0;
}
if (results[0] === null || results[0].length === 0) {
return 0;
}
return parseInt(results[0].nbInteractions, 10);
return results?.total ? parseInt(results?.total, 10) : 0;
}

async function countPendingInteractionsIn({
usagerUUID,
structure,
usager,
}: {
usagerUUID: string;
structure: Pick<Structure, "portailUsager">;
usager: Pick<Usager, "uuid" | "options" | "decision">;
}): Promise<{
courrierIn: number;
recommandeIn: number;
colisIn: number;
lastInteractionOut: Date | null;
}> {
const INTERACTIONS_TO_CHECK = Object.assign([], INTERACTION_OK_LIST);
// NOTE: cette requête ne renvoit pas de résultats pour les usagers de cette structure qui n'ont pas d'interaction
const query = `SELECT
coalesce (SUM(CASE WHEN i.type = 'courrierIn' THEN "nbCourrier" END), 0) AS "courrierIn",
coalesce (SUM(CASE WHEN i.type = 'recommandeIn' THEN "nbCourrier" END), 0) AS "recommandeIn",
coalesce (SUM(CASE WHEN i.type = 'colisIn' THEN "nbCourrier" END), 0) AS "colisIn",
(SELECT "dateInteraction" from interactions where type IN($1) and "usagerUUID" = $2 ORDER BY "dateInteraction" DESC LIMIT 1) as "lastInteractionOut"
FROM interactions i
WHERE i."usagerUUID" = $2 AND i."interactionOutUUID" is null
GROUP BY i."usagerRef"`;

const results = await interactionRepository.query(query, [
INTERACTIONS_TO_CHECK.join(", "),
usagerUUID,
]);

if (
typeof results[0] === "undefined" ||
results[0] === null ||
results[0]?.length === 0
) {
return {
courrierIn: 0,
recommandeIn: 0,
colisIn: 0,
lastInteractionOut: null,
};
}

let lastInteractionOut: Date | null =
results[0].lastInteractionOut !== null
? results[0].lastInteractionOut === "string"
? parseISO(results[0].lastInteractionOut)
: results[0].lastInteractionOut
: null;

if (structure.portailUsager.usagerLoginUpdateLastInteraction) {
const lastUserUsagerLogin = await userUsagerLoginRepository.findOne({
where: {
usagerUUID,
},
order: { createdAt: "DESC" },
});

if (
differenceInMinutes(lastInteractionOut, lastUserUsagerLogin.createdAt) > 0
) {
lastInteractionOut = lastUserUsagerLogin.createdAt;
}
}

const results: {
courrierIn: string;
recommandeIn: string;
colisIn: string;
} = await interactionRepository
.createQueryBuilder("interactions")
.select(
`coalesce (SUM(CASE WHEN type = 'courrierIn' THEN "nbCourrier" END), 0) AS "courrierIn"`
)
.addSelect(
`coalesce (SUM(CASE WHEN type = 'recommandeIn' THEN "nbCourrier" END), 0) AS "recommandeIn"`
)
.addSelect(
`coalesce (SUM(CASE WHEN type = 'colisIn' THEN "nbCourrier" END), 0) AS "colisIn"`
)
.where({ usagerUUID: usager.uuid, interactionOutUUID: IsNull() })
.getRawOne();
return {
courrierIn: parseInt(results[0].courrierIn, 10),
recommandeIn: parseInt(results[0].recommandeIn, 10),
colisIn: parseInt(results[0].colisIn, 10),
lastInteractionOut,
courrierIn: parseInt(results.courrierIn, 10),
recommandeIn: parseInt(results.recommandeIn, 10),
colisIn: parseInt(results.colisIn, 10),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,6 @@ export class InteractionsController {
) {
return this.interactionDeletor.deleteInteraction({
interaction,
user,
usager,
structure: user.structure,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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,
Expand All @@ -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 () => {
Expand All @@ -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";
Expand All @@ -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);
});
});
Loading
Loading