From 078537f8207ebb6333f6f3293f66f16be25d9cf1 Mon Sep 17 00:00:00 2001 From: benjamin Date: Tue, 19 Nov 2024 11:11:13 +0100 Subject: [PATCH 1/2] fix(ehebrgements): refacto 2 read --- packages/backend/src/services/Hebergement.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/backend/src/services/Hebergement.js b/packages/backend/src/services/Hebergement.js index 2ce29408..017a414f 100644 --- a/packages/backend/src/services/Hebergement.js +++ b/packages/backend/src/services/Hebergement.js @@ -172,16 +172,15 @@ ${new Array(nbRows) ], getByUserId: ` SELECT - id, - nom, - coordonnees#> '{adresse, departement}' as departement, - coordonnees#> '{adresse, label}' as adresse, - supprime, - created_at as "createdAt", - edited_at as "editedAt" + h.id as "id", + nom as "nom", + a.label, + a.departement FROM front.hebergement h - JOIN front.user_organisme uo ON uo.org_id = h.organisme_id - WHERE uo.use_id = $1 AND CURRENT IS TRUE + LEFT JOIN front.user_organisme uo ON uo.org_id = h.organisme_id + LEFT JOIN front.adresse a ON a.id = h.adresse_id + WHERE uo.use_id = 1 + AND CURRENT IS TRUE `, getPreviousValueForHistory: ` SELECT From b20168e3684be75c4cbbeeaf5b3f338c9a71d0da Mon Sep 17 00:00:00 2001 From: benjamin Date: Tue, 19 Nov 2024 15:34:06 +0100 Subject: [PATCH 2/2] fix(hebergement): refacto getters --- .../src/controllers/demandeSejour/depose.js | 2 +- .../demandeSejour/getHebergement.js | 38 --- .../getHebergementsByDepartementCodes.js | 1 + .../src/controllers/demandeSejour/index.js | 1 - .../src/controllers/hebergement/get.js | 2 +- .../hebergement/getByDepartements.js | 2 +- .../src/controllers/hebergement/getById.js | 2 +- .../src/controllers/hebergement/getExtract.js | 2 +- .../src/controllers/hebergement/post.js | 2 +- .../src/controllers/hebergement/update.js | 2 +- .../checkPermissionBODeclarationSejour.js | 26 +- .../__tests__/hebergement/FU-getById.test.js | 56 ++++ .../hebergement/admin-getById.test.js | 56 ++++ .../routes/__tests__/hebergement/post.test.js | 108 +++++++ .../__tests__/hebergement/update.test.js | 105 +++++++ packages/backend/src/routes/hebergement.js | 2 - packages/backend/src/routes/sejour.js | 7 - .../backend/src/services/DemandeSejour.js | 285 ++++++++++-------- packages/backend/src/services/Document.js | 28 ++ packages/backend/src/services/adresse.js | 37 +++ packages/backend/src/services/eig.js | 9 +- .../services/{ => hebergement}/Hebergement.js | 119 +++++--- .../src/services/hebergement/helpers.js | 149 +++++++++ .../hebergements/Lies-a-des-sejours.vue | 3 +- .../frontend-bo/src/stores/demande-sejour.js | 2 +- .../src/components/DS/hebergements-sejour.vue | 2 +- .../src/components/DS/synthese.vue | 2 + .../pages/hebergements/[[hebergementId]].vue | 9 +- .../20241119135647_vehiculesAdaptes-type.js | 38 +++ ...dd-sejourItinerant-sejourEtranger-to-ds.js | 28 ++ 30 files changed, 880 insertions(+), 245 deletions(-) delete mode 100644 packages/backend/src/controllers/demandeSejour/getHebergement.js create mode 100644 packages/backend/src/routes/__tests__/hebergement/FU-getById.test.js create mode 100644 packages/backend/src/routes/__tests__/hebergement/admin-getById.test.js create mode 100644 packages/backend/src/routes/__tests__/hebergement/post.test.js create mode 100644 packages/backend/src/routes/__tests__/hebergement/update.test.js rename packages/backend/src/services/{ => hebergement}/Hebergement.js (83%) create mode 100644 packages/backend/src/services/hebergement/helpers.js create mode 100644 packages/migrations/src/migrations/20241119135647_vehiculesAdaptes-type.js create mode 100644 packages/migrations/src/migrations/20241120101643_add-sejourItinerant-sejourEtranger-to-ds.js diff --git a/packages/backend/src/controllers/demandeSejour/depose.js b/packages/backend/src/controllers/demandeSejour/depose.js index af9f7d86..c6dbc755 100644 --- a/packages/backend/src/controllers/demandeSejour/depose.js +++ b/packages/backend/src/controllers/demandeSejour/depose.js @@ -2,7 +2,7 @@ const dayjs = require("dayjs"); const yup = require("yup"); const DemandeSejour = require("../../services/DemandeSejour"); -const Hebergement = require("../../services/Hebergement"); +const Hebergement = require("../../services/hebergement/Hebergement"); const Send = require("../../services/mail").mailService.send; const PdfDeclaration2Mois = require("../../services/pdf/declaration2mois/generate"); const PdfDeclaration8jours = require("../../services/pdf/declaration8jours/generate"); diff --git a/packages/backend/src/controllers/demandeSejour/getHebergement.js b/packages/backend/src/controllers/demandeSejour/getHebergement.js deleted file mode 100644 index b07ebbc8..00000000 --- a/packages/backend/src/controllers/demandeSejour/getHebergement.js +++ /dev/null @@ -1,38 +0,0 @@ -const DemandeSejour = require("../../services/DemandeSejour"); - -const logger = require("../../utils/logger"); - -const log = logger(module.filename); - -module.exports = async function get(req, res) { - log.i("IN"); - const departements = req.departements.map((d) => d.value); - - const { sejourId, hebergementId } = req.params; - - if ([sejourId, hebergementId].includes(undefined)) { - return res.status(400).json({ - message: "Invalide requête", - }); - } - - try { - const response = await DemandeSejour.getHebergement( - sejourId, - departements, - hebergementId, - ); - if (!response.length) { - return res.status(404).json({ - message: "L'hébergement n'a pas été trouvé", - }); - } - return res.status(200).json({ ...response[0] }); - } catch (error) { - log.w("DONE with error"); - return res.status(400).json({ - message: - "une erreur est survenue durant la récupération des hebergements", - }); - } -}; diff --git a/packages/backend/src/controllers/demandeSejour/getHebergementsByDepartementCodes.js b/packages/backend/src/controllers/demandeSejour/getHebergementsByDepartementCodes.js index 96969274..75d89be6 100644 --- a/packages/backend/src/controllers/demandeSejour/getHebergementsByDepartementCodes.js +++ b/packages/backend/src/controllers/demandeSejour/getHebergementsByDepartementCodes.js @@ -43,6 +43,7 @@ module.exports = async function get(req, res) { sort: titleSorted ?? "nom", }, ); + return res.status(200).json({ count: data.total_count, hebergements: data.hebergements || [], diff --git a/packages/backend/src/controllers/demandeSejour/index.js b/packages/backend/src/controllers/demandeSejour/index.js index cef7de35..5f8bcf73 100644 --- a/packages/backend/src/controllers/demandeSejour/index.js +++ b/packages/backend/src/controllers/demandeSejour/index.js @@ -2,7 +2,6 @@ module.exports.get = require("./get"); module.exports.getAdminStats = require("./getAdminStats"); module.exports.getExtract = require("./getExtract"); module.exports.getExtractHebergement = require("./getExtractHebergement"); -module.exports.getHebergement = require("./getHebergement"); module.exports.getHebergementsByDepartementCodes = require("./getHebergementsByDepartementCodes"); module.exports.getById = require("./getById"); module.exports.getByIdBo = require("./getByIdBo"); diff --git a/packages/backend/src/controllers/hebergement/get.js b/packages/backend/src/controllers/hebergement/get.js index 5ec9b788..d198f9bd 100644 --- a/packages/backend/src/controllers/hebergement/get.js +++ b/packages/backend/src/controllers/hebergement/get.js @@ -1,4 +1,4 @@ -const Hebergement = require("../../services/Hebergement"); +const Hebergement = require("../../services/hebergement/Hebergement"); const logger = require("../../utils/logger"); diff --git a/packages/backend/src/controllers/hebergement/getByDepartements.js b/packages/backend/src/controllers/hebergement/getByDepartements.js index 29c1244a..6db58603 100644 --- a/packages/backend/src/controllers/hebergement/getByDepartements.js +++ b/packages/backend/src/controllers/hebergement/getByDepartements.js @@ -1,4 +1,4 @@ -const Hebergement = require("../../services/Hebergement"); +const Hebergement = require("../../services/hebergement/Hebergement"); const logger = require("../../utils/logger"); const Sentry = require("@sentry/node"); diff --git a/packages/backend/src/controllers/hebergement/getById.js b/packages/backend/src/controllers/hebergement/getById.js index aa7aa2ae..7a902ce2 100644 --- a/packages/backend/src/controllers/hebergement/getById.js +++ b/packages/backend/src/controllers/hebergement/getById.js @@ -1,4 +1,4 @@ -const Hebergement = require("../../services/Hebergement"); +const Hebergement = require("../../services/hebergement/Hebergement"); const AppError = require("../../utils/error"); const logger = require("../../utils/logger"); diff --git a/packages/backend/src/controllers/hebergement/getExtract.js b/packages/backend/src/controllers/hebergement/getExtract.js index 38f425f1..8306bb8b 100644 --- a/packages/backend/src/controllers/hebergement/getExtract.js +++ b/packages/backend/src/controllers/hebergement/getExtract.js @@ -1,4 +1,4 @@ -const Hebergement = require("../../services/Hebergement"); +const Hebergement = require("../../services/hebergement/Hebergement"); const logger = require("../../utils/logger"); const dayjs = require("dayjs"); diff --git a/packages/backend/src/controllers/hebergement/post.js b/packages/backend/src/controllers/hebergement/post.js index 37ae6c5b..ea1d0aa5 100644 --- a/packages/backend/src/controllers/hebergement/post.js +++ b/packages/backend/src/controllers/hebergement/post.js @@ -1,5 +1,5 @@ const yup = require("yup"); -const Hebergement = require("../../services/Hebergement"); +const Hebergement = require("../../services/hebergement/Hebergement"); const HebergementSchema = require("../../schemas/hebergement"); const logger = require("../../utils/logger"); const ValidationAppError = require("../../utils/validation-error"); diff --git a/packages/backend/src/controllers/hebergement/update.js b/packages/backend/src/controllers/hebergement/update.js index 359c0ac2..c8f7ad39 100644 --- a/packages/backend/src/controllers/hebergement/update.js +++ b/packages/backend/src/controllers/hebergement/update.js @@ -1,6 +1,6 @@ const yup = require("yup"); -const Hebergement = require("../../services/Hebergement"); +const Hebergement = require("../../services/hebergement/Hebergement"); const logger = require("../../utils/logger"); const ValidationAppError = require("../../utils/validation-error"); const HebergementSchema = require("../../schemas/hebergement"); diff --git a/packages/backend/src/middlewares/checkPermissionBODeclarationSejour.js b/packages/backend/src/middlewares/checkPermissionBODeclarationSejour.js index 2646136d..70506dc6 100644 --- a/packages/backend/src/middlewares/checkPermissionBODeclarationSejour.js +++ b/packages/backend/src/middlewares/checkPermissionBODeclarationSejour.js @@ -23,16 +23,33 @@ async function checkPermissionDeclarationSejour(req, res, next) { // Requête SQL simplifiée, ne récupérant que les informations brutes nécessaires const query = ` - SELECT ds.id, ds.hebergement, o.personne_morale, agr.region_obtention + SELECT ds.id, o.personne_morale, agr.region_obtention FROM front.demande_sejour ds INNER JOIN front.organismes o ON o.id = ds.organisme_id LEFT JOIN front.agrements agr ON agr.organisme_id = ds.organisme_id WHERE ds.id = $1 `; + const queryHebegements = ` + SELECT DISTINCT + A.DEPARTEMENT AS DEPARTEMENT + FROM + FRONT.DEMANDE_SEJOUR_TO_HEBERGEMENT DSTH + INNER JOIN FRONT.HEBERGEMENT H ON H.ID = DSTH.HEBERGEMENT_ID + INNER JOIN FRONT.ADRESSE A ON A.ID = H.ADRESSE_ID + WHERE + DEMANDE_SEJOUR_ID = $1 + `; + let sejour; + let departementsHebergements; try { const { rows } = await pool.query(query, [declarationId]); + departementsHebergements = + (await pool.query(queryHebegements, [declarationId]))?.rows.map( + (r) => r.departement, + ) ?? []; + if (!rows || rows.length === 0) { return next( new AppError( @@ -54,14 +71,9 @@ async function checkPermissionDeclarationSejour(req, res, next) { ); } - const { hebergement, personne_morale, region_obtention } = sejour; + const { personne_morale, region_obtention } = sejour; // Traitement des données JSON pour vérifier les départements - const hebergements = hebergement?.hebergements || []; - const departementsHebergements = hebergements.map( - (h) => h.coordonnees?.adresse?.departement, - ); - const hasValidDepartement = departements.some((dep) => departementsHebergements.includes(dep.value), ); diff --git a/packages/backend/src/routes/__tests__/hebergement/FU-getById.test.js b/packages/backend/src/routes/__tests__/hebergement/FU-getById.test.js new file mode 100644 index 00000000..8467bf1d --- /dev/null +++ b/packages/backend/src/routes/__tests__/hebergement/FU-getById.test.js @@ -0,0 +1,56 @@ +const request = require("supertest"); +const app = require("../../../app"); // Chemin vers ton application Express +const Hebergement = require("../../../services/hebergement/Hebergement"); +const CheckJWT = require("../../../middlewares/checkJWT"); +const checkPermissionHebergement = require("../../../middlewares/checkPermissionHebergement"); + +// Mock des services et middlewares +jest.mock("../../../services/hebergement/Hebergement"); +jest.mock("../../../middlewares/checkJWT"); +jest.mock("../../../middlewares/checkPermissionHebergement"); + +describe("GET /hebergement/:id", () => { + const user = { + id: 1, + role: "admin", + }; + + beforeEach(() => { + jest.clearAllMocks(); + + // Mock des middlewares + CheckJWT.mockImplementation((req, res, next) => { + req.decoded = { ...user }; + next(); + }); + checkPermissionHebergement.mockImplementation((req, res, next) => { + next(); + }); + }); + + it("devrait retourner un hébergement par ID avec succès", async () => { + const mockHebergement = { + id: "123", + }; + + // Mock de Hebergement.getById + Hebergement.getById.mockResolvedValue(mockHebergement); + + const response = await request(app).get("/hebergement/123"); + + // Vérification des résultats + expect(response.status).toBe(200); + expect(Hebergement.getById).toHaveBeenCalledWith("123"); + }); + + it("devrait retourner une erreur 400 si l'ID est manquant ou invalide", async () => { + CheckJWT.mockImplementationOnce((req, res, next) => { + req.decoded = { ...user }; + req.params = {}; + next(); + }); + + const response = await request(app).get("/hebergement/2"); + expect(response.status).toBe(400); + }); +}); diff --git a/packages/backend/src/routes/__tests__/hebergement/admin-getById.test.js b/packages/backend/src/routes/__tests__/hebergement/admin-getById.test.js new file mode 100644 index 00000000..6f111cae --- /dev/null +++ b/packages/backend/src/routes/__tests__/hebergement/admin-getById.test.js @@ -0,0 +1,56 @@ +const request = require("supertest"); +const app = require("../../../app"); // Chemin vers ton application Express +const Hebergement = require("../../../services/hebergement/Hebergement"); +const boCheckJWT = require("../../../middlewares/bo-check-JWT"); +const checkPermissionHebergement = require("../../../middlewares/checkPermissionHebergement"); + +// Mock des services et middlewares +jest.mock("../../../services/hebergement/Hebergement"); +jest.mock("../../../middlewares/bo-check-JWT"); +jest.mock("../../../middlewares/checkPermissionHebergement"); + +describe("GET /hebergement/admin/:id", () => { + const user = { + id: 1, + role: "admin", + }; + + beforeEach(() => { + jest.clearAllMocks(); + + // Mock des middlewares + boCheckJWT.mockImplementation((req, res, next) => { + req.decoded = { ...user }; + next(); + }); + checkPermissionHebergement.mockImplementation((req, res, next) => { + next(); + }); + }); + + it("devrait retourner un hébergement par ID avec succès", async () => { + const mockHebergement = { + id: "123", + }; + + // Mock de Hebergement.getById + Hebergement.getById.mockResolvedValue(mockHebergement); + + const response = await request(app).get("/hebergement/admin/123"); + + // Vérification des résultats + expect(response.status).toBe(200); + expect(Hebergement.getById).toHaveBeenCalledWith("123"); + }); + + it("devrait retourner une erreur 400 si l'ID est manquant ou invalide", async () => { + boCheckJWT.mockImplementationOnce((req, res, next) => { + req.decoded = { ...user }; + req.params = {}; + next(); + }); + + const response = await request(app).get("/hebergement/admin/2"); + expect(response.status).toBe(400); + }); +}); diff --git a/packages/backend/src/routes/__tests__/hebergement/post.test.js b/packages/backend/src/routes/__tests__/hebergement/post.test.js new file mode 100644 index 00000000..e77148db --- /dev/null +++ b/packages/backend/src/routes/__tests__/hebergement/post.test.js @@ -0,0 +1,108 @@ +const request = require("supertest"); +const app = require("../../../app"); +const Hebergement = require("../../../services/hebergement/Hebergement"); +const checkJWT = require("../../../middlewares/checkJWT"); +const checkPermissionHebergement = require("../../../middlewares/checkPermissionHebergement"); +const yup = require("yup"); +const FOUser = require("../../../services/FoUser"); + +// Mock de la méthode Hebergement.update +jest.mock("../../../services/hebergement/Hebergement"); +jest.mock("../../../middlewares/checkJWT"); +jest.mock("../../../middlewares/checkPermissionHebergement"); +jest.mock("../../../schemas/hebergement"); +jest.mock("../../../services/FoUser"); + +describe("POST /", () => { + const user = { + id: 1, + }; + beforeEach(() => { + jest.clearAllMocks(); + checkJWT.mockImplementation((req, res, next) => { + req.decoded = { ...user }; + next(); + }); + checkPermissionHebergement.mockImplementation((req, res, next) => { + next(); + }); + }); + + it("should return 400 if a required parameter is missing", async () => { + const res = await request(app) + .post("/hebergement") + .send({ nom: "Hébergement" }) // Paramètre manquant + .expect(400); + expect(res.statusCode).toBe(400); + }); + + it("should return 200 if the hebergement is posted successfully", async () => { + Hebergement.create.mockResolvedValueOnce(true); + FOUser.getUserOrganisme.mockResolvedValueOnce(1); + + const body = { + nom: "Hébergement 1", + coordonnees: { lat: 10, lon: 20 }, + informationsLocaux: {}, + informationsTransport: {}, + }; + + jest.spyOn(yup, "object").mockImplementationOnce(() => ({ + validate: (parametre) => { + return parametre; + }, + })); + const res = await request(app).post("/hebergement").send(body); + + expect(res.status).toBe(200); + expect(Hebergement.create).toHaveBeenCalledWith( + 1, + 1, + expect.objectContaining(body), + ); + }); + + it("should return 400 if validation fails with yup", async () => { + // Simule l'échec de la validation avec yup + jest.spyOn(yup, "object").mockImplementationOnce(() => ({ + validate: () => { + throw new Error("error"); + }, + })); + + const res = await request(app) + .post("/hebergement") + .send({ + nom: "Hébergement", + coordonnees: {}, + informationsLocaux: "Info", + informationsTransport: "Info", + }) + .expect(400); + + expect(res.status).toBe(400); + }); + + it("should return 404 if Hebergement.update throws an archive error", async () => { + const archiveError = new Error("Hebergement archived"); + archiveError.cause = "archive"; + Hebergement.update.mockRejectedValueOnce(archiveError); + + jest.spyOn(yup, "object").mockImplementationOnce(() => ({ + validate: (parametre) => { + return parametre; + }, + })); + + const res = await request(app) + .post("/hebergement/123") + .send({ + nom: "Hébergement", + coordonnees: { lat: 10, lon: 20 }, + informationsLocaux: "Info locaux", + informationsTransport: "Info transport", + }); + + expect(res.status).toBe(400); + }); +}); diff --git a/packages/backend/src/routes/__tests__/hebergement/update.test.js b/packages/backend/src/routes/__tests__/hebergement/update.test.js new file mode 100644 index 00000000..4c070704 --- /dev/null +++ b/packages/backend/src/routes/__tests__/hebergement/update.test.js @@ -0,0 +1,105 @@ +const request = require("supertest"); +const app = require("../../../app"); +const Hebergement = require("../../../services/hebergement/Hebergement"); +const checkJWT = require("../../../middlewares/checkJWT"); +const checkPermissionHebergement = require("../../../middlewares/checkPermissionHebergement"); +const yup = require("yup"); + +// Mock de la méthode Hebergement.update +jest.mock("../../../services/hebergement/Hebergement"); +jest.mock("../../../middlewares/checkJWT"); +jest.mock("../../../middlewares/checkPermissionHebergement"); +jest.mock("../../../schemas/hebergement"); + +describe("POST /:id", () => { + const user = { + id: 1, + }; + beforeEach(() => { + jest.clearAllMocks(); + checkJWT.mockImplementation((req, res, next) => { + req.decoded = { ...user }; + next(); + }); + checkPermissionHebergement.mockImplementation((req, res, next) => { + next(); + }); + }); + + it("should return 400 if a required parameter is missing", async () => { + const res = await request(app) + .post("/hebergement/1") + .send({ nom: "Hébergement" }) // Paramètre manquant + .expect(400); + expect(res.statusCode).toBe(400); + }); + + it("should return 200 if the hebergement is updated successfully", async () => { + Hebergement.update.mockResolvedValueOnce(true); + + const body = { + nom: "Hébergement 1", + coordonnees: { lat: 10, lon: 20 }, + informationsLocaux: {}, + informationsTransport: {}, + }; + + jest.spyOn(yup, "object").mockImplementationOnce(() => ({ + validate: (parametre) => { + return parametre; + }, + })); + const res = await request(app).post("/hebergement/123").send(body); + + expect(res.status).toBe(200); + expect(Hebergement.update).toHaveBeenCalledWith( + 1, // userId + "123", // hebergementId + expect.objectContaining(body), + ); + }); + + it("should return 400 if validation fails with yup", async () => { + // Simule l'échec de la validation avec yup + jest.spyOn(yup, "object").mockImplementationOnce(() => ({ + validate: () => { + throw new Error("error"); + }, + })); + + const res = await request(app) + .post("/hebergement/123") + .send({ + nom: "Hébergement", + coordonnees: {}, + informationsLocaux: "Info", + informationsTransport: "Info", + }) + .expect(400); + + expect(res.status).toBe(400); + }); + + it("should return 404 if Hebergement.update throws an archive error", async () => { + const archiveError = new Error("Hebergement archived"); + archiveError.cause = "archive"; + Hebergement.update.mockRejectedValueOnce(archiveError); + + jest.spyOn(yup, "object").mockImplementationOnce(() => ({ + validate: (parametre) => { + return parametre; + }, + })); + + const res = await request(app) + .post("/hebergement/123") + .send({ + nom: "Hébergement", + coordonnees: { lat: 10, lon: 20 }, + informationsLocaux: "Info locaux", + informationsTransport: "Info transport", + }); + + expect(res.status).toBe(400); + }); +}); diff --git a/packages/backend/src/routes/hebergement.js b/packages/backend/src/routes/hebergement.js index 544e53ed..b6d62297 100644 --- a/packages/backend/src/routes/hebergement.js +++ b/packages/backend/src/routes/hebergement.js @@ -21,8 +21,6 @@ router.get( getDepartements, hebergementController.getExtract, ); - -// Gère une connexion via mot de passe. router.get( "/:id", checkJWT, diff --git a/packages/backend/src/routes/sejour.js b/packages/backend/src/routes/sejour.js index e350b517..4cdaf956 100644 --- a/packages/backend/src/routes/sejour.js +++ b/packages/backend/src/routes/sejour.js @@ -47,13 +47,6 @@ router.get( getDepartements, demandeSejourController.getHebergementsByDepartementCodes, ); -router.get( - "/admin/hebergement/:sejourId/:hebergementId", - boCheckJWT, - boCheckRoleDS, - getDepartements, - demandeSejourController.getHebergement, -); router.get( "/admin/historique/:declarationId", boCheckJWT, diff --git a/packages/backend/src/services/DemandeSejour.js b/packages/backend/src/services/DemandeSejour.js index 2f364310..03c12900 100644 --- a/packages/backend/src/services/DemandeSejour.js +++ b/packages/backend/src/services/DemandeSejour.js @@ -3,13 +3,12 @@ const dayjs = require("dayjs"); const logger = require("../utils/logger"); const pool = require("../utils/pgpool").getPool(); const dsStatus = require("../helpers/ds-statuts"); +const { + getByDSId: getHebergementsByDSIds, +} = require("./hebergement/Hebergement"); const log = logger(module.filename); -const getDepartementWhereQuery = (departementCodes, params) => { - return `jsonb_path_query_array(hebergement, '$.hebergements[*].coordonnees.adresse.departement') ?| ($${params.length})::text[]`; -}; - /* see: https://day.js.org/docs/en/display/difference if dateDebut = 2021-12-01 and dateFin = 2012-12-03, dayjs(dateFin).diff(dateDebut, "day") will return 2 because it does a diff between 2021-12-01 00:00:00 and 2021-12-03 00:00:00. It would be the same with @@ -55,6 +54,8 @@ const query = { projet_sejour, sanitaires, files, + sejourEtranger, + sejourItinerant, ) => [ ` INSERT INTO front.demande_sejour( @@ -73,9 +74,11 @@ const query = { transport, projet_sejour, sanitaires, - files + files, + sejour_etranger, + sejour_itinerant ) - VALUES ('BROUILLON',$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15) + VALUES ('BROUILLON',$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17) RETURNING id as "declarationId" ;`, @@ -95,6 +98,8 @@ const query = { projet_sejour, sanitaires, files, + sejourEtranger, + sejourItinerant, ], ], create: ( @@ -234,15 +239,6 @@ RETURNING ds.date_fin::text as "dateFin", ds.created_at as "createdAt", ds.edited_at as "editedAt", - ds.duree as "duree", - ds.vacanciers as "vacanciers", - ds.personnel as "personnel", - ds.transport as "transport", - ds.hebergement as "hebergements", - COALESCE(ds.projet_sejour, '{}'::jsonb) as "projetSejour", - ds.sanitaires as "sanitaires", - ds.files as "files", - ds.attestation as "attestation", o.personne_morale->>'siret' as "siret", o.personne_morale->'etablissementPrincipal' as "organismeAgree", dsm.message as "message", @@ -297,12 +293,22 @@ FROM FROM front.demande_sejour_message dsmax WHERE dsmax.declaration_id = ds.id) WHERE - jsonb_path_query_array(hebergement, '$.hebergements[*].coordonnees.adresse.departement') ?| ($1)::text[] - OR a.region_obtention = '${territoireCode}' + EXISTS ( + SELECT + 1 + FROM + FRONT.DEMANDE_SEJOUR_TO_HEBERGEMENT DSTH + LEFT JOIN FRONT.HEBERGEMENT H ON H.ID = DSTH.HEBERGEMENT_ID + LEFT JOIN FRONT.ADRESSE A ON A.ID = H.ADRESSE_ID + WHERE + DSTH.DEMANDE_SEJOUR_ID = DS.ID + AND A.DEPARTEMENT = ANY ($1) + ) + OR A.REGION_OBTENTION = '${territoireCode}' `, [departements], ], - getByDepartementCodes: (search, territoireCode, departementQuery, params) => { + getByDepartementCodes: (search, territoireCode) => { return ` SELECT ds.id as "declarationId", @@ -317,7 +323,17 @@ SELECT o.personne_morale as "personneMorale", o.personne_physique as "personnePhysique", o.type_organisme as "typeOrganisme", - ds.hebergement #>> '{hebergements, 0, coordonnees, adresse, departement}' = ANY ($${params.length}) as "estInstructeurPrincipal", + ( + SELECT + DEPARTEMENT = ANY ($1) + FROM + FRONT.DEMANDE_SEJOUR_TO_HEBERGEMENT DSTH + LEFT JOIN FRONT.HEBERGEMENT H ON H.ID = DSTH.HEBERGEMENT_ID + LEFT JOIN FRONT.ADRESSE A ON A.ID = H.ADRESSE_ID + WHERE DSTH.DEMANDE_SEJOUR_ID = DS.ID + ORDER BY DSTH.DATE_DEBUT + LIMIT 1 + ) as "estInstructeurPrincipal", dsm.message as "message", CASE WHEN (dsm.read_at IS NULL AND dsm.back_user_id IS NULL) THEN 'NON LU' @@ -341,12 +357,24 @@ FROM front.demande_sejour ds WHERE dsmax.declaration_id = ds.id) WHERE statut <> 'BROUILLON' - AND ((${departementQuery}) - OR a.region_obtention = '${territoireCode}') + AND ( + EXISTS ( + SELECT + 1 + FROM + FRONT.DEMANDE_SEJOUR_TO_HEBERGEMENT DSTH + LEFT JOIN FRONT.HEBERGEMENT H ON H.ID = DSTH.HEBERGEMENT_ID + LEFT JOIN FRONT.ADRESSE A ON A.ID = H.ADRESSE_ID + WHERE + DSTH.DEMANDE_SEJOUR_ID = DS.ID + AND A.DEPARTEMENT = ANY ($1) + ) + OR + a.region_obtention = '${territoireCode}') ${search.map((s) => ` AND ${s} `).join("")} `; }, - getByDepartementCodesTotal: (search, territoireCode, departementQuery) => { + getByDepartementCodesTotal: (search, territoireCode) => { return ` SELECT COUNT(DISTINCT ds.id) FROM front.demande_sejour ds @@ -355,8 +383,20 @@ LEFT JOIN front.agrements a ON a.organisme_id = ds.organisme_id LEFT JOIN front.demande_sejour_message dsm ON dsm.declaration_id = ds.id WHERE statut <> 'BROUILLON' - AND ((${departementQuery}) - OR a.region_obtention = '${territoireCode}') + AND ( + EXISTS ( + SELECT + 1 + FROM + FRONT.DEMANDE_SEJOUR_TO_HEBERGEMENT DSTH + LEFT JOIN FRONT.HEBERGEMENT H ON H.ID = DSTH.HEBERGEMENT_ID + LEFT JOIN FRONT.ADRESSE A ON A.ID = H.ADRESSE_ID + WHERE + DSTH.DEMANDE_SEJOUR_ID = DS.ID + AND A.DEPARTEMENT = ANY ($1) + ) + OR + a.region_obtention = '${territoireCode}') ${search.map((s) => ` AND ${s} `).join("")} `; }, @@ -381,7 +421,8 @@ WHERE COALESCE(ds.projet_sejour, '{}'::jsonb) as "projetSejour", ds.sanitaires as "informationsSanitaires", ds.attestation, - ds.hebergement as "hebergement", + sejour_etranger as "sejourEtranger", + sejour_itinerant as "sejourItinerant", ds.organisme as "organisme", o.personne_morale as "personneMorale", o.personne_physique as "personnePhysique", @@ -464,7 +505,7 @@ JOIN front.user_organisme uo ON u.id = uo.use_id WHERE uo.org_id = $1 `, - getExtract: (departementQuery, territoireCode) => ` + getExtract: (territoireCode) => ` SELECT ds.id as id, ds.libelle as libelle, @@ -479,26 +520,20 @@ SELECT FROM front.demande_sejour ds JOIN front.organismes o ON o.id = ds.organisme_id LEFT JOIN front.agrements a ON a.organisme_id = ds.organisme_id -WHERE ((${departementQuery}) +WHERE ( + EXISTS ( + SELECT + 1 + FROM + FRONT.DEMANDE_SEJOUR_TO_HEBERGEMENT DSTH + LEFT JOIN FRONT.HEBERGEMENT H ON H.ID = DSTH.HEBERGEMENT_ID + LEFT JOIN FRONT.ADRESSE A ON A.ID = H.ADRESSE_ID + WHERE + DSTH.DEMANDE_SEJOUR_ID = DS.ID + AND A.DEPARTEMENT = ANY ($1) + ) AND statut <> 'BROUILLON' OR a.region_obtention = '${territoireCode}')`, - getHebergement: (demandeSejourId, departementCodes, hebergementIndex) => [ - ` -SELECT - ds.id AS demande_sejour_id, - ds.date_debut AS date_sejour, - ds.departement_suivi AS departement, - h.hebergement AS hebergement -FROM - front.demande_sejour ds, - jsonb_array_elements(ds.hebergement -> 'hebergements') WITH ORDINALITY AS h(hebergement, ordinality) -WHERE - ds.id = $1 - AND h.hebergement -> 'coordonnees' -> 'adresse' ->> 'departement' = ANY($2) - AND ordinality = $3 - `, - [demandeSejourId, departementCodes, hebergementIndex], - ], getHebergementsByDepartementCodes: ( departementCodes, { search, limit, offset, order, sort }, @@ -506,35 +541,33 @@ WHERE ` WITH filtered_hebergements AS ( SELECT - ds.id AS "declarationId", - ds.date_debut as "dateSejour", - ds.departement_suivi as departement, - h.hebergement ->> 'nom' AS nom, - h.hebergement ->> 'dateFin' AS "dateFin", - h.hebergement ->> 'dateDebut' AS "dateDebut", - h.hebergement -> 'coordonnees' ->> 'email' AS email, - h.hebergement -> 'coordonnees' ->> 'numTelephone1' AS telephone, - h.hebergement -> 'coordonnees' ->> 'nomGestionnaire' AS "nomGestionnaire", - h.hebergement -> 'coordonnees' -> 'adresse' AS adresse, - h.hebergement -> 'informationsLocaux' ->> 'type' AS "typeHebergement", - h.hebergement -> 'informationsLocaux' ->> 'visiteLocauxAt' AS "dateVisite", - CASE - WHEN h.hebergement -> 'informationsLocaux' ->> 'reglementationErp' = 'true' THEN TRUE - WHEN h.hebergement -> 'informationsLocaux' ->> 'reglementationErp' = 'false' THEN FALSE - ELSE NULL - END AS "reglementationErp", - ordinality AS "hebergementIndex" + DS.ID AS "declarationId", + H.ID AS "hebergementId", + DS.DATE_DEBUT AS "dateSejour", + DS.DEPARTEMENT_SUIVI AS "departement", + H.NOM AS "nom", + DSTH.DATE_DEBUT AS "dateDebut", + DSTH.DATE_FIN AS "dateFin", + H.EMAIL AS EMAIL, + H.TELEPHONE_1 AS TELEPHONE, + H.NOM_GESTIONNAIRE AS "nomGestionnaire", + A.LABEL AS ADRESSE, + (SELECT VALUE FROM FRONT.HEBERGEMENT_TYPE WHERE ID = H.ID) AS "typeHebergement", + H.VISITE_LOCAUX_AT AS "dateVisite", + H.REGLEMENTATION_ERP AS "reglementationErp" FROM - front.demande_sejour ds, - jsonb_array_elements(ds.hebergement -> 'hebergements') WITH ORDINALITY AS h(hebergement, ordinality) + FRONT.HEBERGEMENT H + LEFT JOIN FRONT.ADRESSE A ON A.ID = H.ADRESSE_ID + INNER JOIN FRONT.DEMANDE_SEJOUR_TO_HEBERGEMENT DSTH ON DSTH.HEBERGEMENT_ID = H.ID + INNER JOIN FRONT.DEMANDE_SEJOUR DS ON DS.ID = DSTH.DEMANDE_SEJOUR_ID WHERE - ds.statut <> 'BROUILLON' - AND h.hebergement -> 'coordonnees' -> 'adresse' ->> 'departement' = ANY($1) - AND ( - unaccent(h.hebergement ->> 'nom') ILIKE '%' || unaccent($2) || '%' OR - h.hebergement -> 'coordonnees' ->> 'email' ILIKE '%' || $2 || '%' OR - unaccent(h.hebergement -> 'coordonnees' -> 'adresse' ->> 'label') ILIKE '%' || unaccent($2) || '%' - ) + DS.STATUT <> 'BROUILLON' + AND A.DEPARTEMENT = ANY($1) + AND ( + unaccent(h.nom) ILIKE '%' || unaccent($2) || '%' + OR h.email ILIKE '%' || $2 || '%' + OR unaccent(a.label) ILIKE '%' || unaccent($2) || '%' + ) ORDER BY "${sort}" ${order} ), total_count AS ( @@ -575,13 +608,14 @@ SELECT ds.transport as "informationsTransport", COALESCE(ds.projet_sejour, '{}'::jsonb) as "projetSejour", ds.sanitaires as "informationsSanitaires", - ds.hebergement as "hebergement", ds.organisme as "organisme", ds.files as "files", ds.attestation as "attestation", ds.declaration_2m as "declaration2mois", o.personne_morale->>'siret' as "siret", - ds.edited_at as "editedAt" + ds.edited_at as "editedAt", + sejour_etranger as "sejourEtranger", + sejour_itinerant as "sejourItinerant" FROM front.demande_sejour ds JOIN front.organismes o ON o.id = ds.organisme_id WHERE 1=1 @@ -606,23 +640,17 @@ ${Object.keys(criterias) WHERE uo.use_id = $1; `, [ - userId, - // countBrouillon - dsStatus.statuts.BROUILLON, - // countDeclarationAcompleter + userId, // countBrouillon + dsStatus.statuts.BROUILLON, // countDeclarationAcompleter dsStatus.statuts.A_MODIFIER, dsStatus.statuts.A_MODIFIER_8J, - dsStatus.statuts.ATTENTE_8_JOUR, - // countDeclarationEnInstruction + dsStatus.statuts.ATTENTE_8_JOUR, // countDeclarationEnInstruction dsStatus.statuts.TRANSMISE, dsStatus.statuts.TRANSMISE_8J, dsStatus.statuts.EN_COURS, - dsStatus.statuts.EN_COURS_8J, - // countDeclarationFinalisee - dsStatus.statuts.VALIDEE_8J, - // countSejourEnCours - dsStatus.statuts.SEJOUR_EN_COURS, - // countTerminee + dsStatus.statuts.EN_COURS_8J, // countDeclarationFinalisee + dsStatus.statuts.VALIDEE_8J, // countSejourEnCours + dsStatus.statuts.SEJOUR_EN_COURS, // countTerminee dsStatus.statuts.TERMINEE, ], ], @@ -666,8 +694,7 @@ WHERE VALUES ($1,$2,$3,$4,$5,$6,$7,NOW(),NOW()) RETURNING id as "eventId" - `, - /* + ` /* * La query peut insérer plusieurs hébergements d'un coup, d'ùou la necessité de generer plusieurs lignes via le .map * de la requete. Par exemple, si l'on veut inserer 2 hebergements, on utilisera la syntaxe * linkToHebergements(2) avec comme params le tableau (flat) @@ -675,7 +702,7 @@ WHERE * * Le .map genere le texte suivant : * ($1, $2, $3, $4), ($1, $5, $6, $7) - * */ + * */, linkToHebergements: (nbRows) => ` INSERT INTO FRONT.DEMANDE_SEJOUR_TO_HEBERGEMENT ( @@ -708,9 +735,11 @@ WHERE UPDATE front.demande_sejour ds SET hebergement = $1, + sejour_etranger = $2, + sejour_itinerant = $3, edited_at = NOW() WHERE - ds.id = $2 + ds.id = $4 RETURNING id as "declarationId" `, @@ -903,6 +932,8 @@ module.exports.copy = async (declaration) => { declaration.projetSejour, declaration.informationsSanitaires, declaration.files, + declaration.hebergement?.sejourEtranger ?? null, + declaration.hebergement?.sejourItinerant ?? null, ), ); log.d(response); @@ -957,15 +988,26 @@ module.exports.get = async ({ sortBy }, organismesId) => { module.exports.getOne = async (criterias = {}) => { log.i("getOne - IN", { criterias }); - const { rows: demandes, rowCount } = await pool.query( + const { rows: declarations, rowCount } = await pool.query( ...query.getOne(criterias), ); if (rowCount !== 1) { log.w("getOne - DONE with unexpected result", { rowCount }); return null; } + const declaration = declarations[0]; + + const hebergements = await getHebergementsByDSIds(declaration.id); + log.i("getOne - DONE"); - return demandes[0]; + return { + ...declaration, + hebergement: { + hebergements, + sejourItinerant: declaration.sejourItinerant ?? null, + sejourEtranger: declaration.sejourEtranger ?? null, + }, + }; }; module.exports.getByDepartementCodes = async ( @@ -993,7 +1035,7 @@ module.exports.getByDepartementCodes = async ( log.i("getByDepartementCodes - IN"); - const params = []; + const params = [departementCodes]; const searchQuery = []; // Search management @@ -1031,18 +1073,9 @@ module.exports.getByDepartementCodes = async ( searchQuery.push(`dsm.message is not null`); } - /* - * Cette Partie du code soit toujours etre appelé juste avant la fonction query.getByDepartementCodes - * pour maintenir la coherence de l'ordre des paramètres dans les requetes - * */ - params.push(departementCodes); - const departementQuery = getDepartementWhereQuery(departementCodes, params); - let queryWithPagination = query.getByDepartementCodes( searchQuery, territoireCode, - departementQuery, - params, ); const stats = await pool.query( ...query.getAdminStats(departementCodes, territoireCode), @@ -1083,16 +1116,13 @@ module.exports.getByDepartementCodes = async ( } const total = await pool.query( - query.getByDepartementCodesTotal( - searchQuery, - territoireCode, - departementQuery, - ), + query.getByDepartementCodesTotal(searchQuery, territoireCode), params, ); log.i("getByDepartementCodes - DONE"); const totalValue = total.rows.find((t) => t.count)?.count; + return { demandes_sejour: response.rows, stats: Object.entries(stats.rows[0]).reduce((acc, [key, value]) => { @@ -1106,26 +1136,24 @@ module.exports.getByDepartementCodes = async ( module.exports.getById = async (declarationId, departements) => { log.i("getById - IN", { declarationId }); - const { rows: declarations } = await pool.query( - ...query.getById(declarationId, departements), - ); - log.d(declarations); + const declaration = + (await pool.query(...query.getById(declarationId, departements))) + .rows?.[0] ?? null; + const hebergements = await getHebergementsByDSIds(declarationId); - log.i("getById - DONE"); - return declarations[0]; -}; + if (!declaration) { + return null; + } -module.exports.getHebergement = async ( - demandeSejourId, - departementCodes, - hebergementId, -) => { - log.i("getHebergement - IN"); - const { rows } = await pool.query( - ...query.getHebergement(demandeSejourId, departementCodes, hebergementId), - ); - log.d("getHebergement - DONE"); - return rows; + log.i("getById - DONE"); + return { + ...declaration, + hebergement: { + hebergements, + sejourItinerant: declaration.sejourItinerant ?? null, + sejourEtranger: declaration.sejourEtranger ?? null, + }, + }; }; module.exports.getHebergementsByDepartementCodes = async ( @@ -1246,6 +1274,8 @@ module.exports.update = async (type, declarationId, parametre) => { await linkToHebergements(client, declarationId, parametre.hebergements); response = await client.query(query.updateHebergement, [ parametre, + parametre?.sejourEtranger ?? null, + parametre?.sejourItinerant ?? null, declarationId, ]); await client.query("COMMIT"); @@ -1374,14 +1404,9 @@ module.exports.getEmailBackCc = async (departements) => { module.exports.getExtract = async (territoireCode, departementCodes) => { log.i("getExtract - IN"); - const departementQuery = getDepartementWhereQuery(departementCodes, [ + const { rows: data } = await pool.query(query.getExtract(territoireCode), [ departementCodes, ]); - - const { rows: data } = await pool.query( - query.getExtract(departementQuery, territoireCode), - [departementCodes], - ); log.i("getExtract - DONE"); return data; }; diff --git a/packages/backend/src/services/Document.js b/packages/backend/src/services/Document.js index 3b881e32..742df216 100644 --- a/packages/backend/src/services/Document.js +++ b/packages/backend/src/services/Document.js @@ -45,6 +45,16 @@ const query = { WHERE uuid = $1;`, [uuid], ], + getNameByUuid: (uuid) => [ + ` + SELECT + uuid, + filename as "name", + created_at as "createdAt" + FROM doc.documents + WHERE uuid = $1;`, + [uuid], + ], }; module.exports.download = async (uuid) => { @@ -63,6 +73,24 @@ module.exports.download = async (uuid) => { } }; +module.exports.getNameByUuid = async (uuid) => { + log.i("IN"); + try { + const { rows, rowCount } = await poolDoc.query( + ...query.getNameByUuid(uuid), + ); + if (rowCount > 0) { + log.i("DONE", rows[0]); + return rows[0]; + } + log.i("DONE"); + return null; + } catch (err) { + log.w(err); + throw new AppError("query.getNameByUuid failed", { cause: err }); + } +}; + module.exports.downloadNext = async (uuid) => { log.i("IN"); try { diff --git a/packages/backend/src/services/adresse.js b/packages/backend/src/services/adresse.js index 7ef8af2c..6a3e579a 100644 --- a/packages/backend/src/services/adresse.js +++ b/packages/backend/src/services/adresse.js @@ -1,3 +1,5 @@ +const pool = require("../utils/pgpool").getPool(); + const query = { editCleInsee: ` UPDATE FRONT.ADRESSE @@ -31,6 +33,31 @@ const query = { ($1, $2, $3, $4, $5, $6, $7) RETURNING id `, + getById: ` + SELECT + LABEL as "label", + CODE_INSEE as "codeInsee", + CODE_POSTAL as "codePostal", + LONG as "long", + LAT as "lat", + DEPARTEMENT as "departement" +FROM + FRONT.ADRESSE +WHERE id = $1 + `, + getByIds: ` + SELECT + id as "id", + LABEL as "label", + CODE_INSEE as "codeInsee", + CODE_POSTAL as "codePostal", + LONG as "long", + LAT as "lat", + DEPARTEMENT as "departement" +FROM + FRONT.ADRESSE +WHERE id = ANY ($1) + `, }; const getByCleInseeOrLabel = async (client, { cleInsee, label }) => { @@ -71,3 +98,13 @@ module.exports.saveAdresse = async (client, adresse) => { return existingAdresse.id; }; + +module.exports.getById = async (id) => { + const { rows } = await pool.query(query.getById, [id]); + return rows?.[0] ?? null; +}; + +module.exports.getByIds = async (ids) => { + const { rows } = await pool.query(query.getByIds, [ids]); + return rows ?? []; +}; diff --git a/packages/backend/src/services/eig.js b/packages/backend/src/services/eig.js index 3f9a08ce..fc4ec112 100644 --- a/packages/backend/src/services/eig.js +++ b/packages/backend/src/services/eig.js @@ -92,7 +92,14 @@ EIG.ID, DS.PERSONNEL -> 'encadrants' as "encadrants", DS.PERSONNEL -> 'accompagnants' as "accompagnants", DS.STATUT as "dsStatut", - JSONB_PATH_QUERY_ARRAY(DS.HEBERGEMENT,'$.hebergements.coordonnees.adresse.label') as "adresses", + (SELECT DISTINCT + ARRAY_AGG(A.LABEL) + FROM + FRONT.DEMANDE_SEJOUR_TO_HEBERGEMENT DSTH + INNER JOIN FRONT.HEBERGEMENT H ON H.ID = DSTH.HEBERGEMENT_ID + INNER JOIN FRONT.ADRESSE A ON A.ID = H.ADRESSE_ID + WHERE + DEMANDE_SEJOUR_ID = DS.ID) as "adresses", DS.PERIODE as "saison", ARRAY_AGG(JSON_BUILD_OBJECT('type',ET.TYPE,'categorie',EC.CATEGORIE,'precision',E2ET.PRECISIONS)) as "types", EIG.DEROULEMENT as "deroulement", diff --git a/packages/backend/src/services/Hebergement.js b/packages/backend/src/services/hebergement/Hebergement.js similarity index 83% rename from packages/backend/src/services/Hebergement.js rename to packages/backend/src/services/hebergement/Hebergement.js index 017a414f..17389dc2 100644 --- a/packages/backend/src/services/Hebergement.js +++ b/packages/backend/src/services/hebergement/Hebergement.js @@ -1,7 +1,16 @@ /* eslint-disable no-param-reassign */ -const logger = require("../utils/logger"); -const { saveAdresse } = require("./adresse"); -const pool = require("../utils/pgpool").getPool(); +const logger = require("../../utils/logger"); +const { + saveAdresse, + getById: getAdressById, + getByIds: getAdressByIds, +} = require("../adresse"); +const { + queryGetFields, + mapDBHebergement, + mapDBHebergementToDSHebergement, +} = require("./helpers"); +const pool = require("../../utils/pgpool").getPool(); const log = logger(module.filename); @@ -112,30 +121,27 @@ ${new Array(nbRows) ` WITH filtered_hebergements AS ( SELECT - h.id AS "id", - h.nom AS "nom", - h.coordonnees -> 'adresse' ->> 'departement' AS "departement", - h.coordonnees ->> 'email' AS email, - h.coordonnees ->> 'numTelephone1' AS telephone, - h.coordonnees ->> 'nomGestionnaire' AS "nomGestionnaire", - h.coordonnees -> 'adresse' AS adresse, - h.informations_locaux ->> 'type' AS "typeHebergement", - h.informations_locaux ->> 'visiteLocauxAt' AS "dateVisite", - CASE - WHEN h.informations_locaux ->> 'reglementationErp' = 'true' THEN TRUE - WHEN h.informations_locaux ->> 'reglementationErp' = 'false' THEN FALSE - ELSE NULL - END AS "reglementationErp" + H.ID AS "id", + A.DEPARTEMENT AS "departement", + H.EMAIL AS EMAIL, + H.TELEPHONE_1 AS TELEPHONE, + H.NOM_GESTIONNAIRE AS "nomGestionnaire", + A.LABEL AS ADRESSE, + H.NOM AS "nom", + ( SELECT VALUE FROM FRONT.HEBERGEMENT_TYPE WHERE ID = H.ID) AS "typeHebergement", + H.VISITE_LOCAUX_AT AS "dateVisite", + H.REGLEMENTATION_ERP AS "reglementationErp" FROM - front.hebergement h + FRONT.HEBERGEMENT H + LEFT JOIN FRONT.ADRESSE A ON A.ID = H.ADRESSE_ID WHERE - h.coordonnees -> 'adresse' ->> 'departement' = ANY($1) + A.DEPARTEMENT = ANY($1) AND ( - unaccent(h.nom) ILIKE '%' || unaccent($2) || '%' OR - h.coordonnees ->> 'email' ILIKE '%' || $2 || '%' OR - unaccent(h.coordonnees -> 'adresse' ->> 'label') ILIKE '%' || unaccent($2) || '%' + unaccent(h.nom) ILIKE '%' || unaccent($2) || '%' + OR h.email ILIKE '%' || $2 || '%' + OR unaccent(a.label) ILIKE '%' || unaccent($2) || '%' ) - AND CURRENT IS TRUE + AND CURRENT IS TRUE ORDER BY "${sort}" ${order} ), total_count AS ( @@ -154,32 +160,36 @@ ${new Array(nbRows) `, [departementCodes, search, limit, offset], ], - getById: (id) => [ - ` + getById: ` SELECT id, - supprime, nom, - coordonnees, - informations_locaux as "informationsLocaux", - informations_transport as "informationsTransport", - created_at as "createdAt", - edited_at as "editedAt" - FROM front.hebergement + ${queryGetFields} + FROM front.hebergement h WHERE id = $1 `, - [id], - ], + getByDSId: ` + SELECT + ID as "hebergementId", + NOM, + DSTH.DATE_DEBUT as "dateDebut", + DSTH.DATE_FIN as "dateFin", + ${queryGetFields} + FROM + FRONT.HEBERGEMENT H + INNER JOIN FRONT.DEMANDE_SEJOUR_TO_HEBERGEMENT DSTH ON DSTH.HEBERGEMENT_ID = H.ID + AND DSTH.DEMANDE_SEJOUR_ID = $1 ; + `, getByUserId: ` SELECT h.id as "id", nom as "nom", - a.label, - a.departement + a.label as "adresse", + a.departement as "departement" FROM front.hebergement h LEFT JOIN front.user_organisme uo ON uo.org_id = h.organisme_id LEFT JOIN front.adresse a ON a.id = h.adresse_id - WHERE uo.use_id = 1 + WHERE uo.use_id = $1 AND CURRENT IS TRUE `, getPreviousValueForHistory: ` @@ -370,9 +380,36 @@ module.exports.getByUserId = async (userId) => { module.exports.getById = async (id) => { log.i("getById - IN", { id }); - const { rows: hebergements, rowCount } = await pool.query( - ...query.getById(id), - ); + const { rows: hebergements, rowCount } = await pool.query(query.getById, [ + id, + ]); + + if (rowCount === 0) { + return null; + } + const hebergement = hebergements[0]; + const adresse = await getAdressById(hebergement.adresseId); + log.d("getById - DONE"); - return rowCount > 0 ? hebergements[0] : null; + return await mapDBHebergement(hebergement, adresse); +}; + +module.exports.getByDSId = async (dsId) => { + log.i("getByDSId - IN", { dsId }); + const { rows: hebergements, rowCount } = await pool.query(query.getByDSId, [ + dsId, + ]); + + if (rowCount === 0) { + return []; + } + const adresses = await getAdressByIds(hebergements.map((h) => h.adresseId)); + return await Promise.all( + hebergements.map((h) => + mapDBHebergementToDSHebergement( + h, + adresses.find((a) => a.id === h.adresseId), + ), + ), + ); }; diff --git a/packages/backend/src/services/hebergement/helpers.js b/packages/backend/src/services/hebergement/helpers.js new file mode 100644 index 00000000..a6583b86 --- /dev/null +++ b/packages/backend/src/services/hebergement/helpers.js @@ -0,0 +1,149 @@ +const { getNameByUuid } = require("../Document"); + +module.exports.queryGetFields = ` + H.NOM AS "nom", + H.EMAIL AS "email", + H.ADRESSE_ID AS "adresseId", + H.TELEPHONE_1 AS "numTelephone1", + H.TELEPHONE_2 AS "numTelephone2", + H.NOM_GESTIONNAIRE AS "nomGestionnaire", + ( + SELECT + VALUE + FROM + FRONT.HEBERGEMENT_TYPE + WHERE + ID = H.TYPE_ID + ) AS "type", + ( + SELECT + VALUE + FROM + FRONT.HEBERGEMENT_TYPE_PENSION + WHERE + ID = H.TYPE_PENSION_ID + ) AS "typePension", + H.NOMBRE_LITS AS "nombreLits", + H.LIT_DESSUS AS "litDessus", + H.NOMBRE_LITS_SUPERPOSES AS "nombreLitsSuperposes", + H.NOMBRE_MAX_PERSONNES_COUCHAGE AS "nombreMaxPersonnesCouchage", + H.VISITE_LOCAUX AS "visiteLocaux", + H.VISITE_LOCAUX_AT AS "visiteLocauxAt", + H.ACCESSIBILITE_ID AS "accessibiliteId", + ( + SELECT + VALUE + FROM + FRONT.HEBERGEMENT_ACCESSIBILITE + WHERE + ID = H.ACCESSIBILITE_ID + ) AS "accessibilite", + H.ACCESSIBILITE_PRECISION AS "accessibilitePrecision", + H.CHAMBRES_DOUBLES AS "chambresDoubles", + H.CHAMBRES_UNISEXES AS "chambresUnisexes", + H.REGLEMENTATION_ERP AS "reglementationErp", + H.COUCHAGE_INDIVIDUEL AS "couchageIndividuel", + H.RANGEMENT_INDIVIDUEL AS "rangementIndividuel", + H.AMENAGEMENTS_SPECIFIQUES AS "amenagementsSpecifiques", + H.AMENAGEMENTS_SPECIFIQUES_PRECISION AS "amenagementsSpecifiquesPrecision", + H.DESCRIPTION_LIEU_HEBERGEMENT AS "descriptionLieuHebergement", + H.EXCURSION_DESCRIPTION AS "excursionDescription", + H.DEPLACEMENT_PROXIMITE_DESCRIPTION AS "deplacementProximiteDescription", + H.VEHICULES_ADAPTES AS "vehiculesAdaptes", + H.FILE_REPONSE_EXPLOITANT_OU_PROPRIETAIRE AS "fileReponseExploitantOuProprietaire", + H.FILE_DERNIER_ARRETE_AUTORISATION_MAIRE AS "fileDernierArreteAutorisationMaire", + H.FILE_DERNIERE_ATTESTATION_SECURITE AS "fileDerniereAttestationSecurite", + ( + SELECT + ARRAY_AGG(HPH.VALUE) + FROM + FRONT.HEBERGEMENT_TO_PRESTATIONS_HOTELIERES HTPH + LEFT JOIN FRONT.HEBERGEMENT_PRESTATIONS_HOTELIERES HPH ON HPH.ID = HTPH.PRESTATION_ID + WHERE + HEBERGEMENT_ID = H.ID + ) AS "prestationsHoteliere" +`; + +const mapHebergementToCoordonnees = (hebergement, adresse) => { + return { + adresse: { + codeInsee: adresse.codeInsee, + codePostal: adresse.codePostal, + coordinates: [adresse.long, adresse.lat], + departement: adresse.departement, + label: adresse.label, + }, + email: hebergement.email, + nomGestionnaire: hebergement.nomGestionnaire, + numTelephone1: hebergement.numTelephone1, + numTelephone2: hebergement.numTelephone2, + }; +}; + +const mapHebergementToInformationsLocaux = async (hebergement) => { + return { + accessibilite: hebergement.accessibilite, + accessibilitePrecision: hebergement.accessibilitePrecision, + amenagementsSpecifiques: hebergement.amenagementsSpecifiques, + chambresDoubles: hebergement.chambresDoubles, + chambresUnisexes: hebergement.chambresUnisexes, + couchageIndividuel: hebergement.couchageIndividuel, + descriptionLieuHebergement: hebergement.descriptionLieuHebergement, + fileDernierArreteAutorisationMaire: await getNameByUuid( + hebergement.fileDernierArreteAutorisationMaire, + ), + fileDerniereAttestationSecurite: await getNameByUuid( + hebergement.fileDerniereAttestationSecurite, + ), + fileReponseExploitantOuProprietaire: await getNameByUuid( + hebergement.fileReponseExploitantOuProprietaire, + ), + litsDessus: hebergement.litDessus, + nombreLits: hebergement.nombreLits, + nombreLitsSuperposes: hebergement.nombreLitsSuperposes, + nombreMaxPersonnesCouchage: hebergement.nombreMaxPersonnesCouchage, + pension: hebergement.typePension, + precisionAmenagementsSpecifiques: + hebergement.amenagementsSpecifiquesPrecision, + prestationsHotelieres: hebergement.prestationsHoteliere, + rangementIndividuel: hebergement.rangementIndividuel, + reglementationErp: hebergement.reglementationErp, + type: hebergement.type, + visiteLocaux: hebergement.visiteLocaux, + visiteLocauxAt: hebergement.visiteLocauxAt, + }; +}; + +const mapHebergementToInformationsTransport = (hebergement) => { + return { + deplacementProximite: hebergement.deplacementProximiteDescription, + excursion: hebergement.excursionDescription, + vehiculesAdaptes: hebergement.vehiculesAdaptes, + }; +}; + +const mapDBHebergement = async (hebergement, adresse) => { + return { + coordonnees: mapHebergementToCoordonnees(hebergement, adresse), + id: hebergement.id, + informationsLocaux: await mapHebergementToInformationsLocaux(hebergement), + informationsTransport: mapHebergementToInformationsTransport(hebergement), + nom: hebergement.nom, + }; +}; + +const mapDBHebergementToDSHebergement = async (hebergement, adresse) => { + return { + coordonnees: mapHebergementToCoordonnees(hebergement, adresse), + dateDebut: hebergement.dateDebut, + dateFin: hebergement.dateFin, + hebergementId: hebergement.hebergementId, + informationsLocaux: await mapHebergementToInformationsLocaux(hebergement), + informationsTransport: mapHebergementToInformationsTransport(hebergement), + nom: hebergement.nom, + }; +}; + +module.exports.mapDBHebergement = mapDBHebergement; +module.exports.mapDBHebergementToDSHebergement = + mapDBHebergementToDSHebergement; diff --git a/packages/frontend-bo/src/components/hebergements/Lies-a-des-sejours.vue b/packages/frontend-bo/src/components/hebergements/Lies-a-des-sejours.vue index 784e1725..6dc9bde7 100644 --- a/packages/frontend-bo/src/components/hebergements/Lies-a-des-sejours.vue +++ b/packages/frontend-bo/src/components/hebergements/Lies-a-des-sejours.vue @@ -41,7 +41,6 @@ const headers = [ { column: "adresse", text: "Adresse", - format: (row) => row.adresse.label, }, { column: "telephone", @@ -70,7 +69,7 @@ const headers = [ const redirectOnHebergement = (row) => { navigateTo( - `/hebergements/lie-a-des-sejours/${row.declarationId}/${row.hebergementIndex}`, + `/hebergements/lie-a-des-sejours/${row.declarationId}/${row.hebergementId}`, ); }; diff --git a/packages/frontend-bo/src/stores/demande-sejour.js b/packages/frontend-bo/src/stores/demande-sejour.js index 8ae6bfae..b21f3aa6 100644 --- a/packages/frontend-bo/src/stores/demande-sejour.js +++ b/packages/frontend-bo/src/stores/demande-sejour.js @@ -184,7 +184,7 @@ export const useDemandeSejourStore = defineStore("demandeSejour", { this.isGetHebergementLoading = true; try { const data = await $fetchBackend( - `/sejour/admin/hebergement/${demandeSejourId}/${hebergementId}`, + `/hebergement/admin/${hebergementId}`, { method: "GET", credentials: "include", diff --git a/packages/frontend-usagers/src/components/DS/hebergements-sejour.vue b/packages/frontend-usagers/src/components/DS/hebergements-sejour.vue index 308c822b..8998d7db 100644 --- a/packages/frontend-usagers/src/components/DS/hebergements-sejour.vue +++ b/packages/frontend-usagers/src/components/DS/hebergements-sejour.vue @@ -165,7 +165,7 @@ const syntheseRows = computed(() => { ? dayjs(hebergement.dateFin).format("DD/MM/YYYY") : "", hebergement.nom ?? "", - hebergement.adresse ?? "", + hebergement.coordonnees?.adresse?.label ?? "", { component: DsfrButtonGroup, buttons: buttons, diff --git a/packages/frontend-usagers/src/components/DS/synthese.vue b/packages/frontend-usagers/src/components/DS/synthese.vue index 796cd340..4c2d92ca 100644 --- a/packages/frontend-usagers/src/components/DS/synthese.vue +++ b/packages/frontend-usagers/src/components/DS/synthese.vue @@ -265,6 +265,8 @@ /> + +
{{ meta.initialValues.hebergement }}
diff --git a/packages/frontend-usagers/src/pages/hebergements/[[hebergementId]].vue b/packages/frontend-usagers/src/pages/hebergements/[[hebergementId]].vue index b59906a9..9f7336e3 100644 --- a/packages/frontend-usagers/src/pages/hebergements/[[hebergementId]].vue +++ b/packages/frontend-usagers/src/pages/hebergements/[[hebergementId]].vue @@ -102,16 +102,11 @@ async function updateOrCreate(hebergement) { // Sauvegarde de l'hébergement try { - const id = await hebergementStore.updateOrCreate( - hebergement, - hebergementId.value, - ); + await hebergementStore.updateOrCreate(hebergement, hebergementId.value); log.d("hebergement sauvegardé"); toaster.success({ titleTag: "h2", description: "Hébergement sauvegardé" }); - if (!hebergementId.value && id) { - return await navigateTo("/hebergements/liste"); - } + await navigateTo("/hebergements/liste"); } catch (error) { toaster.error({ titleTag: "h2", diff --git a/packages/migrations/src/migrations/20241119135647_vehiculesAdaptes-type.js b/packages/migrations/src/migrations/20241119135647_vehiculesAdaptes-type.js new file mode 100644 index 00000000..9ce2e49b --- /dev/null +++ b/packages/migrations/src/migrations/20241119135647_vehiculesAdaptes-type.js @@ -0,0 +1,38 @@ +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.up = function (knex) { + return knex.raw( + ` +ALTER TABLE FRONT.HEBERGEMENT +RENAME COLUMN VEHICULES_ADAPTES TO VEHICULES_ADAPTES_DEPRECATED; + +ALTER TABLE FRONT.HEBERGEMENT +ADD COLUMN VEHICULES_ADAPTES BOOLEAN; + +UPDATE FRONT.HEBERGEMENT +SET + VEHICULES_ADAPTES = CASE + WHEN VEHICULES_ADAPTES_DEPRECATED = 'true' THEN TRUE + ELSE FALSE + END; + `, + ); +}; + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.down = function (knex) { + return knex.raw( + ` +ALTER TABLE FRONT.HEBERGEMENT +DROP COLUMN VEHICULES_ADAPTES; + +ALTER TABLE FRONT.HEBERGEMENT +RENAME COLUMN VEHICULES_ADAPTES_DEPRECATED TO VEHICULES_ADAPTES; + `, + ); +}; diff --git a/packages/migrations/src/migrations/20241120101643_add-sejourItinerant-sejourEtranger-to-ds.js b/packages/migrations/src/migrations/20241120101643_add-sejourItinerant-sejourEtranger-to-ds.js new file mode 100644 index 00000000..41f60049 --- /dev/null +++ b/packages/migrations/src/migrations/20241120101643_add-sejourItinerant-sejourEtranger-to-ds.js @@ -0,0 +1,28 @@ +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.up = function (knex) { + return knex.raw(` + ALTER TABLE FRONT.demande_sejour + ADD COLUMN sejour_etranger BOOLEAN, + ADD COLUMN sejour_itinerant BOOLEAN; + + UPDATE FRONT.DEMANDE_SEJOUR + SET + SEJOUR_ETRANGER = (HEBERGEMENT -> 'sejourEtranger')::BOOLEAN, + SEJOUR_ITINERANT = (HEBERGEMENT -> 'sejourItinerant')::BOOLEAN ; + `); +}; + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.down = function (knex) { + return knex.raw(` +ALTER TABLE FRONT.DEMANDE_SEJOUR +DROP COLUMN SEJOUR_ETRANGER, +DROP COLUMN SEJOUR_ITINERANT; + `); +};