diff --git a/packages/backend/src/controllers/hebergement/post.js b/packages/backend/src/controllers/hebergement/post.js
index 38c11be8f..37ae6c5bf 100644
--- a/packages/backend/src/controllers/hebergement/post.js
+++ b/packages/backend/src/controllers/hebergement/post.js
@@ -4,6 +4,7 @@ const HebergementSchema = require("../../schemas/hebergement");
const logger = require("../../utils/logger");
const ValidationAppError = require("../../utils/validation-error");
const AppError = require("../../utils/error");
+const FOUser = require("../../services/FoUser");
const log = logger(module.filename);
@@ -44,11 +45,12 @@ module.exports = async function post(req, res, next) {
}
try {
- const id = await Hebergement.create(userId, hebergement);
+ const organismeId = await FOUser.getUserOrganisme(userId);
+ const id = await Hebergement.create(userId, organismeId, hebergement);
return res.status(200).json({
id,
- message: "sauvegarde organisme OK",
+ message: "sauvegarde hebegement OK",
});
} catch (error) {
log.w("DONE with error");
diff --git a/packages/backend/src/controllers/hebergement/update.js b/packages/backend/src/controllers/hebergement/update.js
index c400233a6..e782005bc 100644
--- a/packages/backend/src/controllers/hebergement/update.js
+++ b/packages/backend/src/controllers/hebergement/update.js
@@ -10,15 +10,10 @@ const log = logger(module.filename);
module.exports = async function post(req, res, next) {
const hebergementId = req.params.id;
- const { nom, coordonnees, informationsLocaux, informationsTransport } =
- req.body;
- log.i("IN", {
- coordonnees,
- hebergementId,
- informationsLocaux,
- informationsTransport,
- nom,
- });
+ const { body, decoded } = req;
+ const userId = decoded.id;
+
+ const { nom, coordonnees, informationsLocaux, informationsTransport } = body;
if (
!nom ||
@@ -36,6 +31,7 @@ module.exports = async function post(req, res, next) {
);
}
let hebergement;
+
try {
hebergement = await yup.object(HebergementSchema.schema()).validate(
{
@@ -54,7 +50,7 @@ module.exports = async function post(req, res, next) {
}
try {
- await Hebergement.update(hebergementId, hebergement);
+ await Hebergement.update(userId, hebergementId, hebergement);
log.i("DONE");
return res.sendStatus(200);
} catch (error) {
diff --git a/packages/backend/src/schemas/parts/adresse.js b/packages/backend/src/schemas/parts/adresse.js
index 0d2c8a87f..0710558de 100644
--- a/packages/backend/src/schemas/parts/adresse.js
+++ b/packages/backend/src/schemas/parts/adresse.js
@@ -3,6 +3,7 @@ const yup = require("yup");
const schema = ({ isFromAPIAdresse } = {}) => {
return isFromAPIAdresse
? {
+ cleInsee: yup.string().nullable(true),
codeInsee: yup.string().required("ce champ est obligatoire"),
codePostal: yup.string().required("ce champ est obligatoire"),
coordinates: yup.array().required("ce champ est obligatoire"),
diff --git a/packages/backend/src/services/DemandeSejour.js b/packages/backend/src/services/DemandeSejour.js
index 119d6e05b..6ea205643 100644
--- a/packages/backend/src/services/DemandeSejour.js
+++ b/packages/backend/src/services/DemandeSejour.js
@@ -797,6 +797,38 @@ WHERE
RETURNING
id as "declarationId"
`,
+ unlinkToHebergement: `
+DELETE FROM FRONT.DEMANDE_SEJOUR_TO_HEBERGEMENT
+WHERE
+ DEMANDE_SEJOUR_ID = $1;
+ `,
+ linkToHebergements: (nbRows) => `
+INSERT INTO
+ FRONT.DEMANDE_SEJOUR_TO_HEBERGEMENT (
+ DEMANDE_SEJOUR_ID,
+ HEBERGEMENT_ID,
+ DATE_DEBUT,
+ DATE_FIN
+ )
+VALUES
+${new Array(nbRows)
+ .fill(null)
+ .map(
+ (_, index) =>
+ `($1, $${3 * index + 2}, $${3 * index + 3}, $${3 * index + 4})`,
+ )
+ .join(",")}
+ `,
+};
+
+const linkToHebergements = async (client, declarationId, hebergements) => {
+ await client.query(query.unlinkToHebergement, [declarationId]);
+ if (hebergements.length > 0) {
+ await client.query(query.linkToHebergements(hebergements.length), [
+ declarationId,
+ ...hebergements.flatMap((h) => [h.hebergementId, h.dateDebut, h.dateFin]),
+ ]);
+ }
};
module.exports.create = async ({
@@ -841,33 +873,50 @@ module.exports.create = async ({
module.exports.copy = async (declaration) => {
log.i("copy - IN");
- const response = await pool.query(
- ...query.copy(
- declaration.organismeId,
- `COPIE - ${declaration.libelle}`,
- declaration.dateDebut,
- declaration.dateFin,
- declaration.duree,
- declaration.periode,
- declaration.responsableSejour,
- declaration.organisme,
- declaration.hebergement,
- declaration.informationsVacanciers,
- declaration.informationsPersonnel,
- declaration.informationsTransport,
- declaration.projetSejour,
- declaration.informationsSanitaires,
- declaration.files,
- ),
- );
- log.d(response);
- const { declarationId } = response.rows[0];
+ const client = await pool.connect();
+ let declarationId;
+ try {
+ await client.query("BEGIN");
+ const response = await client.query(
+ ...query.copy(
+ declaration.organismeId,
+ `COPIE - ${declaration.libelle}`,
+ declaration.dateDebut,
+ declaration.dateFin,
+ declaration.duree,
+ declaration.periode,
+ declaration.responsableSejour,
+ declaration.organisme,
+ declaration.hebergement,
+ declaration.informationsVacanciers,
+ declaration.informationsPersonnel,
+ declaration.informationsTransport,
+ declaration.projetSejour,
+ declaration.informationsSanitaires,
+ declaration.files,
+ ),
+ );
+ log.d(response);
+ declarationId = response.rows[0].declarationId;
+ await linkToHebergements(
+ client,
+ declarationId,
+ declaration.hebergement?.hebergements ?? [],
+ );
+ await client.query("COMMIT");
+ } catch (error) {
+ await client.query("ROLLBACK");
+ throw error;
+ } finally {
+ client.release();
+ }
log.i("copy - DONE", { declarationId });
return declarationId;
};
module.exports.delete = async (declarationId, userId) => {
log.i("delete - IN");
+ await pool.query(query.unlinkToHebergement, [declarationId]);
const { rowCount } = await pool.query(...query.delete(declarationId, userId));
log.i("delete - DONE");
return rowCount;
@@ -1182,10 +1231,21 @@ module.exports.update = async (type, declarationId, parametre) => {
}
case "hebergements": {
log.d("hebergements", declarationId);
- response = await pool.query(query.updateHebergement, [
- parametre,
- declarationId,
- ]);
+ const client = await pool.connect();
+ try {
+ await client.query("BEGIN");
+ await linkToHebergements(client, declarationId, parametre.hebergements);
+ response = await client.query(query.updateHebergement, [
+ parametre,
+ declarationId,
+ ]);
+ await client.query("COMMIT");
+ } catch (error) {
+ await client.query("ROLLBACK");
+ throw error;
+ } finally {
+ client.release();
+ }
break;
}
default:
diff --git a/packages/backend/src/services/FoUser.js b/packages/backend/src/services/FoUser.js
index 3198f23bb..2ad922954 100644
--- a/packages/backend/src/services/FoUser.js
+++ b/packages/backend/src/services/FoUser.js
@@ -47,6 +47,7 @@ ${additionalParamsQuery}
`,
additionalParams,
],
+ getUserOragnisme: `SELECT org_id as "organismeId" FROM front.user_organisme WHERE use_id = $1`,
};
module.exports.read = async ({
@@ -150,3 +151,8 @@ module.exports.readOne = async (id) => {
log.i("readOne - DONE");
return users[0];
};
+
+module.exports.getUserOrganisme = async (userId) => {
+ const { rows } = await pool.query(query.getUserOragnisme, [userId]);
+ return rows[0]?.organismeId ?? null;
+};
diff --git a/packages/backend/src/services/Hebergement.js b/packages/backend/src/services/Hebergement.js
index ee9234dbc..d4f0b2770 100644
--- a/packages/backend/src/services/Hebergement.js
+++ b/packages/backend/src/services/Hebergement.js
@@ -1,6 +1,6 @@
/* eslint-disable no-param-reassign */
-const AppError = require("../utils/error");
const logger = require("../utils/logger");
+const { saveAdresse } = require("./adresse");
const pool = require("../utils/pgpool").getPool();
const log = logger(module.filename);
@@ -9,24 +9,102 @@ const query = {
create: `
INSERT INTO front.hebergement(
organisme_id,
+ CREATED_BY,
+ EDITED_BY,
+ created_at,
+ edited_at,
+ HEBERGEMENT_ID,
+ CURRENT,
nom,
coordonnees,
informations_locaux,
informations_transport,
- created_at,
- edited_at
+ EMAIL,
+ ADRESSE_ID,
+ TELEPHONE_1,
+ TELEPHONE_2,
+ NOM_GESTIONNAIRE,
+ TYPE_ID,
+ TYPE_PENSION_ID,
+ NOMBRE_LITS,
+ LIT_DESSUS,
+ NOMBRE_LITS_SUPERPOSES,
+ NOMBRE_MAX_PERSONNES_COUCHAGE,
+ VISITE_LOCAUX,
+ ACCESSIBILITE_ID,
+ CHAMBRES_DOUBLES,
+ CHAMBRES_UNISEXES,
+ REGLEMENTATION_ERP,
+ COUCHAGE_INDIVIDUEL,
+ RANGEMENT_INDIVIDUEL,
+ AMENAGEMENTS_SPECIFIQUES,
+ DESCRIPTION_LIEU_HEBERGEMENT,
+ EXCURSION_DESCRIPTION,
+ DEPLACEMENT_PROXIMITE_DESCRIPTION,
+ VEHICULES_ADAPTES,
+ FILE_REPONSE_EXPLOITANT_OU_PROPRIETAIRE,
+ FILE_DERNIER_ARRETE_AUTORISATION_MAIRE,
+ FILE_DERNIERE_ATTESTATION_SECURITE,
+ VISITE_LOCAUX_AT,
+ ACCESSIBILITE_PRECISION,
+ AMENAGEMENTS_SPECIFIQUES_PRECISION
)
VALUES (
- (SELECT org_id FROM front.user_organisme WHERE use_id = $1),
- $2,
- $3,
- $4,
- $5,
- NOW(),
- NOW()
+ $1, --organisme_id,
+ $2, --CREATED_BY,
+ $3, --EDITED_BY,
+ $4, --created_at,
+ NOW(), --edited_at,
+ $5, --HEBERGEMENT_ID,
+ TRUE, --CURRENT,
+ $6, --nom,
+ $7, --coordonnees,
+ $8, --informations_locaux,
+ $9, --informations_transport,
+ $10, --EMAIL,
+ $11, --ADRESSE_ID,
+ $12, --TELEPHONE_1,
+ $13, --TELEPHONE_2,
+ $14, --NOM_GESTIONNAIRE,
+ (SELECT ID FROM FRONT.HEBERGEMENT_TYPE WHERE VALUE = $15), --TYPE_ID,
+ (SELECT ID FROM FRONT.HEBERGEMENT_TYPE_PENSION WHERE VALUE = $16), --TYPE_PENSION_ID,
+ $17, --NOMBRE_LITS,
+ $18, --LIT_DESSUS,
+ $19, --NOMBRE_LITS_SUPERPOSES,
+ $20, --NOMBRE_MAX_PERSONNES_COUCHAGE,
+ $21, --VISITE_LOCAUX,
+ (SELECT ID FROM FRONT.HEBERGEMENT_ACCESSIBILITE WHERE VALUE = $22), --ACCESSIBILITE_ID,
+ $23, --CHAMBRES_DOUBLES,
+ $24, --CHAMBRES_UNISEXES,
+ $25, --REGLEMENTATION_ERP,
+ $26, --COUCHAGE_INDIVIDUEL,
+ $27, --RANGEMENT_INDIVIDUEL,
+ $28, --AMENAGEMENTS_SPECIFIQUES,
+ $29, --DESCRIPTION_LIEU_HEBERGEMENT,
+ $30, --EXCURSION_DESCRIPTION,
+ $31, --DEPLACEMENT_PROXIMITE_DESCRIPTION,
+ $32, --VEHICULES_ADAPTES,
+ $33, --FILE_REPONSE_EXPLOITANT_OU_PROPRIETAIRE,
+ $34, --FILE_DERNIER_ARRETE_AUTORISATION_MAIRE,
+ $35, --FILE_DERNIERE_ATTESTATION_SECURITE
+ $36, --VISITE_LOCAUX_AT
+ $37, --ACCESSIBILITE_PRECISION
+ $38 --AMENAGEMENTS_SPECIFIQUES_PRECISION
)
RETURNING id
`,
+ associatePrestation: (nbRows) => `
+INSERT INTO
+ FRONT.HEBERGEMENT_TO_PRESTATIONS_HOTELIERES (HEBERGEMENT_ID, PRESTATION_ID)
+VALUES
+${new Array(nbRows)
+ .fill(null)
+ .map(
+ (_, index) =>
+ `($1, (SELECT ID FROM FRONT.HEBERGEMENT_PRESTATIONS_HOTELIERES WHERE VALUE = $${index + 2}))`,
+ )
+ .join(",")}
+ `,
getByDepartementCodes: (
departementCodes,
{ search, limit, offset, order, sort },
@@ -57,6 +135,7 @@ const query = {
h.coordonnees ->> 'email' ILIKE '%' || $2 || '%' OR
unaccent(h.coordonnees -> 'adresse' ->> 'label') ILIKE '%' || unaccent($2) || '%'
)
+ AND CURRENT IS TRUE
ORDER BY "${sort}" ${order}
),
total_count AS (
@@ -102,8 +181,25 @@ const query = {
edited_at as "editedAt"
FROM front.hebergement h
JOIN front.user_organisme uo ON uo.org_id = h.organisme_id
- WHERE uo.use_id = $1
+ WHERE uo.use_id = $1 AND CURRENT IS TRUE
`,
+ getPreviousValueForHistory: `
+ SELECT
+ HEBERGEMENT_ID AS "hebergementUuid",
+ ORGANISME_ID as "organismeId",
+ CREATED_BY as "createdBy",
+ CREATED_AT as "createdAt",
+ CURRENT as "current"
+ FROM
+ FRONT.HEBERGEMENT
+ WHERE
+ ID = $1;
+ `,
+ historize: `
+ UPDATE front.hebergement
+ SET current = FALSE
+ WHERE id = $1
+ `,
update: `
UPDATE front.hebergement
SET
@@ -116,40 +212,142 @@ const query = {
`,
};
-module.exports.create = async (
- userId,
+/*
+* La fonction create est utilisée à la fois pour créer un nouvel hébergement et pour mettre à jour un
+* hébergement existant. Dans le cas d'une mise à jour, elle archive l'hébergement précédent en définissant
+* le champ current à false, puis insère une nouvelle ligne pour l'hébergement mis à jour.
+
+* Pour garantir l'intégrité des données lors de ces opérations, qui impliquent plusieurs interactions avec la base
+* de données, celles-ci sont exécutées dans le cadre d'une transaction. La fonction prend donc en paramètre le client
+* de transaction fourni par pg (node-postgres).
+*
+* Les transactions doivent être écrites dans les fonctions appelantes.
+
+* Pour plus d'informations, consultez la documentation sur les transactions de
+* node-postgres : https://node-postgres.com/features/transactions.
+*/
+const create = async (
+ client,
+ { createdBy, createdAt, updatedBy, organismeId },
{ nom, coordonnees, informationsLocaux, informationsTransport },
+ hebergemenetUuid,
) => {
- log.i("create - IN");
- const {
- rows: [{ id }],
- } = await pool.query(query.create, [
- userId,
+ const adresseId = await saveAdresse(client, coordonnees.adresse);
+ const { rows } = await client.query(query.create, [
+ organismeId, // $1
+ createdBy,
+ updatedBy,
+ createdAt,
+ hebergemenetUuid ?? crypto.randomUUID(), // 5
nom,
coordonnees,
informationsLocaux,
informationsTransport,
+ coordonnees.email, // 10
+ adresseId,
+ coordonnees.numTelephone1,
+ coordonnees.numTelephone2,
+ coordonnees.nomGestionnaire,
+ informationsLocaux.type, // 15
+ informationsLocaux.pension,
+ informationsLocaux.nombreLits,
+ informationsLocaux.litsDessus,
+ informationsLocaux.nombreLitsSuperposes,
+ informationsLocaux.nombreMaxPersonnesCouchage, // 20
+ informationsLocaux.visiteLocaux,
+ informationsLocaux.accessibilite,
+ informationsLocaux.chambresDoubles,
+ informationsLocaux.chambresUnisexes,
+ informationsLocaux.reglementationErp, // 25
+ informationsLocaux.couchageIndividuel,
+ informationsLocaux.rangementIndividuel,
+ informationsLocaux.amenagementsSpecifiques,
+ informationsLocaux.descriptionLieuHebergement,
+ informationsTransport.excursion, // 30
+ informationsTransport.deplacementProximite,
+ informationsTransport.vehiculesAdaptes,
+ informationsLocaux.fileReponseExploitantOuProprietaire?.uuid ?? null,
+ informationsLocaux.fileDernierArreteAutorisationMaire?.uuid ?? null,
+ informationsLocaux.fileDerniereAttestationSecurite?.uuid ?? null,
+ informationsLocaux.visiteLocauxAt,
+ informationsLocaux.accessibilitePrecision,
+ informationsLocaux.precisionAmenagementsSpecifiques,
]);
- log.d("create - DONE", { id });
- return id;
+
+ const hebergementId = rows[0].id;
+ const prestationsHotelieres = informationsLocaux.prestationsHotelieres;
+ if (prestationsHotelieres.length > 0) {
+ await client.query(
+ query.associatePrestation(prestationsHotelieres.length),
+ [hebergementId, ...prestationsHotelieres],
+ );
+ }
+
+ return hebergementId;
};
-module.exports.update = async (
- hebergementId,
- { nom, coordonnees, informationsLocaux, informationsTransport },
-) => {
- log.i("update - IN");
- const { rowCount } = await pool.query(query.update, [
- hebergementId,
- nom,
- coordonnees,
- informationsLocaux,
- informationsTransport,
- ]);
- if (rowCount === 0) {
- throw new AppError("hebergement " + hebergementId + " not found");
+module.exports.create = async (userId, organismeId, hebergement) => {
+ const client = await pool.connect();
+ let hebergementId;
+
+ try {
+ await client.query("BEGIN");
+ hebergementId = await create(
+ client,
+ {
+ createdAt: new Date(),
+ createdBy: userId,
+ updatedBy: userId,
+ organismeId,
+ },
+ hebergement,
+ );
+ await client.query("COMMIT");
+ } catch (error) {
+ await client.query("ROLLBACK");
+ throw error;
+ } finally {
+ client.release();
}
- log.i("update - DONE");
+
+ return hebergementId;
+};
+
+module.exports.update = async (userId, hebergementId, hebergement) => {
+ const {
+ rows: [{ hebergementUuid, organismeId, createdBy, createdAt, current }],
+ } = await pool.query(query.getPreviousValueForHistory, [hebergementId]);
+ const client = await pool.connect();
+
+ if (!current) {
+ throw new Error("L'hebergement est archivé et ne peux pas etre modifié");
+ }
+
+ let newHebergementId;
+ try {
+ await client.query("BEGIN");
+ await client.query(query.historize, [hebergementId]);
+ newHebergementId = await create(
+ client,
+ {
+ createdBy,
+ createdAt,
+ updatedBy: userId,
+ organismeId,
+ },
+ hebergement,
+ hebergementUuid,
+ );
+
+ await client.query("COMMIT");
+ } catch (error) {
+ await client.query("ROLLBACK");
+ throw error;
+ } finally {
+ client.release();
+ }
+
+ return newHebergementId;
};
module.exports.getByDepartementCodes = async (departementsCodes, params) => {
diff --git a/packages/backend/src/services/adresse.js b/packages/backend/src/services/adresse.js
new file mode 100644
index 000000000..0906016d7
--- /dev/null
+++ b/packages/backend/src/services/adresse.js
@@ -0,0 +1,75 @@
+const pool = require("../utils/pgpool").getPool();
+
+const query = {
+ editCleInsee: `
+ UPDATE FRONT.ADRESSE
+ SET
+ CLE_INSEE = $2
+ WHERE
+ ID = $1
+ RETURNING id
+ `,
+ getByCleInseeOrLabel: `
+ SELECT
+ ID, CLE_INSEE as "cleInsee"
+ FROM
+ FRONT.ADRESSE
+ WHERE
+ CLE_INSEE = $1
+ OR LABEL = $2
+ `,
+ insert: `
+ INSERT INTO
+ FRONT.ADRESSE (
+ CLE_INSEE,
+ LABEL,
+ CODE_INSEE,
+ CODE_POSTAL,
+ LONG,
+ LAT,
+ DEPARTEMENT
+ )
+ VALUES
+ ($1, $2, $3, $4, $5, $6, $7)
+ RETURNING id
+ `,
+};
+
+const getByCleInseeOrLabel = async (client, { cleInsee, label }) => {
+ const { rows } = await client.query(query.getByCleInseeOrLabel, [
+ cleInsee,
+ label,
+ ]);
+ return rows?.[0] ?? null;
+};
+
+module.exports.saveAdresse = async (client, adresse) => {
+ const existingAdresse = await getByCleInseeOrLabel(client, {
+ cleInsee: adresse.cleInsee,
+ label: adresse.label,
+ });
+
+ if (existingAdresse && !existingAdresse.cleInsee && adresse.cleInsee) {
+ const { rows } = await client.query(query.editCleInsee, [
+ existingAdresse.id,
+ adresse.cleInsee,
+ ]);
+ return rows[0].id;
+ }
+
+ if (!existingAdresse) {
+ const { rows } = await client.query(query.insert, [
+ adresse.cleInsee,
+ adresse.label,
+ adresse.codeInsee,
+ adresse.codePostal,
+ adresse.coordinates[0],
+ adresse.coordinates[1],
+ adresse.departement,
+ ]);
+
+ return rows[0].id;
+ }
+
+ return existingAdresse.id;
+};
diff --git a/packages/frontend-bo/src/components/user/Compte.vue b/packages/frontend-bo/src/components/user/Compte.vue
index 4cb009fa9..e4b09ed7d 100644
--- a/packages/frontend-bo/src/components/user/Compte.vue
+++ b/packages/frontend-bo/src/components/user/Compte.vue
@@ -9,9 +9,9 @@
(popUpParams.value = null);
const modalOpenCounter = ref(0);
const openModal = (p) => {
- console.log(p);
modalOpenCounter.value++;
popUpParams.value = {
cb: () => {
diff --git a/packages/frontend-bo/src/stores/demande-sejour.js b/packages/frontend-bo/src/stores/demande-sejour.js
index 2f80f7d27..7e7fe0643 100644
--- a/packages/frontend-bo/src/stores/demande-sejour.js
+++ b/packages/frontend-bo/src/stores/demande-sejour.js
@@ -68,18 +68,6 @@ export const useDemandeSejourStore = defineStore("demandeSejour", {
credentials: "include",
});
- for (const hebergement of demande?.hebergement?.hebergements ?? []) {
- hebergement.nom = (
- await $fetchBackend(
- `/hebergement/admin/${hebergement.hebergementId}`,
- {
- method: "GET",
- credentials: "include",
- },
- )
- ).hebergement.nom;
- }
-
if (demande) {
log.i("fetchDemandes for one id - DONE");
this.currentDemande = demande;
diff --git a/packages/frontend-usagers/src/components/DS/hebergements-sejour-detail.vue b/packages/frontend-usagers/src/components/DS/hebergements-sejour-detail.vue
index 342acb5c6..7ea130846 100644
--- a/packages/frontend-usagers/src/components/DS/hebergements-sejour-detail.vue
+++ b/packages/frontend-usagers/src/components/DS/hebergements-sejour-detail.vue
@@ -62,7 +62,7 @@
label="Nom de l'hébergement"
:label-visible="true"
:model-value="hebergementStore.hebergementCourant.nom"
- readonly
+ disabled
/>
@@ -73,7 +73,7 @@
:model-value="
hebergementStore.hebergementCourant.coordonnees.nomGestionnaire
"
- readonly
+ disabled
/>
@@ -84,7 +84,7 @@
:model-value="
hebergementStore.hebergementCourant.coordonnees.adresse.label
"
- readonly
+ disabled
/>
@@ -120,7 +120,7 @@
:model-value="
hebergementStore.hebergementCourant.coordonnees.numTelephone2
"
- readonly
+ disabled
/>
@@ -129,7 +129,7 @@
label="Adresse courriel"
:label-visible="true"
:model-value="hebergementStore.hebergementCourant.coordonnees.email"
- readonly
+ disabled
/>
@@ -140,12 +140,11 @@
name="informationsLocaux.type"
legend="Type du lieu d'hébergement"
:model-value="type"
- :disabled="!props.modifiable"
+ disabled
:options="hebergementUtils.typeOptions"
:is-valid="typeMeta.valid"
:inline="false"
:error-message="typeErrorMessage"
- readonly
@update:model-value="onTypeChange"
/>
@@ -157,7 +156,7 @@
-
-
- Informations ERP : Selon la circulaire du 6 octobre 2023, il sera
- requis l’arrêté d’autorisation du maire et/ou la dernière
- attestation du passage de la commission de sécurité datant de moins
- de 5 ans pour séjours se déroulant en établissement recevant du
- public (ERP).
-
-
- A défaut de transmission de ces justificatifs, la DDETS met en
- demeure l'organisme de produire ces pièces et propose au Préfet de
- département une annulation des séjours, si absence de tous les
- justificatifs.
-
- On distingue 3 catégories d’hébergements :
-
- -
- Les établissements recevant du public (ERP, tous les hôtels et les
- gros meubles de tourisme deplus de 15 personnes de type gîtes de
- groupes
-
- -
- Les Bâtiments d’Habitation Collective (BHC, comme des résidences
- de tourisme)
-
- -
- Les maisons individuelles (MI, comme des chambres d’hôtes et
- petits meublés, qui ne peuvent dépasser 5 chambres et hébergent 15
- personnes au maximum)
-
-
-
@@ -248,7 +215,7 @@
v-model="fileReponseExploitantOuProprietaire"
label="Téléchargement du document Réponse du propriétaire ou exploitant indiquant les raisons pour lesquelles le lieu d’hébergement n’est pas soumis à la réglementation ERP"
hint="Taille maximale : 5 Mo. Formats supportés : jpg, png, pdf."
- :modifiable="props.modifiable"
+ :modifiable="false"
:error-message="fileReponseExploitantOuProprietaireErrorMessage"
/>
@@ -257,7 +224,7 @@
@@ -289,7 +257,7 @@
@@ -324,6 +292,7 @@
:model-value="descriptionLieuHebergement"
:error-message="descriptionLieuHebergementErrorMessage"
:is-valid="descriptionLieuHebergementMeta.valid"
+ disabled
@update:model-value="onDescriptionLieuHebergementChange"
/>
@@ -339,6 +308,7 @@
:model-value="nombreLits"
:error-message="nombreLitsErrorMessage"
:is-valid="nombreLitsMeta.valid"
+ disabled
@update:model-value="onNombreLitsChange"
/>
@@ -354,6 +324,7 @@
:model-value="nombreLitsSuperposes"
:error-message="nombreLitsSuperposesErrorMessage"
:is-valid="nombreLitsSuperposesMeta.valid"
+ disabled
@update:model-value="
onNombreLitsSuperposesChange($event !== '' ? $event : null)
"
@@ -369,7 +340,7 @@
name="informationsLocaux.litsDessus"
legend="Pour les lits superposés, les lits « du dessus » seront-ils occupés
par des vacanciers ?"
- :disabled="!props.modifiable"
+ disabled
:model-value="litsDessus"
:options="ouiNonOptions"
:is-valid="litsDessusMeta.valid"
@@ -385,7 +356,7 @@
name="informationsLocaux.nombreMaxPersonnesCouchage"
label="Nombre maximum de personnes prévues par espace de couchage"
type="number"
- :readonly="!props.modifiable"
+ disabled
:label-visible="true"
:model-value="nombreMaxPersonnesCouchage"
:error-message="nombreMaxPersonnesCouchageErrorMessage"
@@ -399,7 +370,7 @@
{
if (hebergementStore.hebergements.length > 0) {
return hebergements.value.map((hebergement, index) => {
- const currentHebergement = hebergementStore.hebergements.find((elem) => {
- return elem.id.toString() === hebergement.hebergementId.toString();
- });
- if (currentHebergement) {
- const buttons = [
- {
- icon: "ri:delete-bin-2-line",
- iconOnly: true,
- tertiary: true,
- noOutline: true,
- disabled: !props.modifiable,
- onClick: (event) => {
- event.stopPropagation();
- removeHebergement(index);
- },
+ const buttons = [
+ {
+ icon: "ri:delete-bin-2-line",
+ iconOnly: true,
+ tertiary: true,
+ noOutline: true,
+ disabled: !props.modifiable,
+ onClick: (event) => {
+ event.stopPropagation();
+ removeHebergement(index);
},
- ];
+ },
+ ];
- const rows = [
- `${index + 1}`,
- hebergement.dateFin && hebergement.dateDebut
- ? dayjs(hebergement.dateFin)
- .diff(dayjs(hebergement.dateDebut), "day")
- .toString()
- : "",
- hebergement.dateDebut
- ? dayjs(hebergement.dateDebut).format("DD/MM/YYYY")
- : "",
- hebergement.dateFin
- ? dayjs(hebergement.dateFin).format("DD/MM/YYYY")
- : "",
- currentHebergement.nom ?? "",
- currentHebergement.adresse ?? "",
- {
- component: DsfrButtonGroup,
- buttons: buttons,
- },
- ];
- return {
- rowData: rows,
- rowAttrs: {
- class: "pointer",
- onClick: () => editNuitee(index),
- },
- };
- } else return [];
+ const rows = [
+ `${index + 1}`,
+ hebergement.dateFin && hebergement.dateDebut
+ ? dayjs(hebergement.dateFin)
+ .diff(dayjs(hebergement.dateDebut), "day")
+ .toString()
+ : "",
+ hebergement.dateDebut
+ ? dayjs(hebergement.dateDebut).format("DD/MM/YYYY")
+ : "",
+ hebergement.dateFin
+ ? dayjs(hebergement.dateFin).format("DD/MM/YYYY")
+ : "",
+ hebergement.nom ?? "",
+ hebergement.adresse ?? "",
+ {
+ component: DsfrButtonGroup,
+ buttons: buttons,
+ },
+ ];
+ return {
+ rowData: rows,
+ rowAttrs: {
+ class: "pointer",
+ onClick: () => editNuitee(index),
+ },
+ };
});
} else return [];
});
diff --git a/packages/frontend-usagers/src/components/search-address.vue b/packages/frontend-usagers/src/components/search-address.vue
index c95462726..cd71c2394 100644
--- a/packages/frontend-usagers/src/components/search-address.vue
+++ b/packages/frontend-usagers/src/components/search-address.vue
@@ -49,6 +49,7 @@ const searchAddressDebounced = debounce(async function (queryString) {
options.value = adresses.map((address) => {
return {
label: address.properties.label,
+ cleInsee: address.properties.id,
codeInsee: address.properties.citycode,
codePostal: address.properties.postcode,
coordinates: address.geometry.coordinates,
@@ -122,7 +123,7 @@ function select(_value, option) {
:is-pointed="isPointed(option)"
/>
- Pas de résultat
+ Pas de résultat
diff --git a/packages/frontend-usagers/src/utils/adresse.js b/packages/frontend-usagers/src/utils/adresse.js
deleted file mode 100644
index e3897dd8a..000000000
--- a/packages/frontend-usagers/src/utils/adresse.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import * as yup from "yup";
-
-const schema = ({ isFromAPIAdresse } = {}) => {
- return isFromAPIAdresse
- ? {
- label: yup.string().required("ce champ est obligatoire"),
- codeInsee: yup.string().required("ce champ est obligatoire"),
- codePostal: yup.string().required("ce champ est obligatoire"),
- coordinates: yup.array().required("ce champ est obligatoire"),
- departement: yup.string().required("ce champ est obligatoire"),
- }
- : {
- label: yup.string().required(),
- };
-};
-
-export default {
- schema,
-};
diff --git a/packages/frontend-usagers/src/utils/organisme.js b/packages/frontend-usagers/src/utils/organisme.js
index 5d050231f..d0b10ab36 100644
--- a/packages/frontend-usagers/src/utils/organisme.js
+++ b/packages/frontend-usagers/src/utils/organisme.js
@@ -1,10 +1,10 @@
import * as yup from "yup";
import dayjs from "dayjs";
import regex from "./regex";
-import adresse from "./adresse";
import personne from "./personne";
import protocoleTransport from "./protocoleTransport";
import protocoleSanitaire from "./protocoleSanitaire";
+import { adresseSchema } from "@vao/shared/src/schema/adresse";
const types = [
{
@@ -225,8 +225,8 @@ const personnePhysiqueSchema = {
regex.numTelephoneRegex.test(tel),
),
adresseIdentique: yup.boolean().required(),
- adresseDomicile: yup.object({ ...adresse.schema(true) }).required(),
- adresseSiege: yup.object({ ...adresse.schema(true) }).required(),
+ adresseDomicile: yup.object({ ...adresseSchema(true) }).required(),
+ adresseSiege: yup.object({ ...adresseSchema(true) }).required(),
};
const agrementSchema = (regions) => ({
file: yup.mixed().required(),
diff --git a/packages/frontend-usagers/src/utils/personne.js b/packages/frontend-usagers/src/utils/personne.js
index 2694b90ef..99bfd1665 100644
--- a/packages/frontend-usagers/src/utils/personne.js
+++ b/packages/frontend-usagers/src/utils/personne.js
@@ -1,8 +1,8 @@
import * as yup from "yup";
import dayjs from "dayjs";
import regex from "./regex";
-import adresse from "./adresse";
import { informationsPersonnelListe } from "#imports";
+import { adresseSchema } from "@vao/shared/src/schema/adresse";
const schema = ({
showAdresse,
@@ -60,7 +60,7 @@ const schema = ({
...(showAdresse && {
adresse: yup.object({
- ...adresse.schema(),
+ ...adresseSchema(),
}),
}),
...(showAttestation && {
diff --git a/packages/frontend-usagers/src/utils/prestataireUtils.js b/packages/frontend-usagers/src/utils/prestataireUtils.js
index dfee2273e..bcb183aed 100644
--- a/packages/frontend-usagers/src/utils/prestataireUtils.js
+++ b/packages/frontend-usagers/src/utils/prestataireUtils.js
@@ -1,7 +1,7 @@
import * as yup from "yup";
import dayjs from "dayjs";
import regex from "./regex";
-import adresse from "./adresse";
+import { adresseSchema } from "@vao/shared/src/schema/adresse";
const typePrestataireOptions = [
{
@@ -53,7 +53,7 @@ const schema = {
.required(),
adresse: yup.object().when("typePrestataire", {
is: (val) => val === "personne_morale",
- then: () => yup.object(adresse.schema()),
+ then: () => yup.object(adresseSchema()),
otherwise: (val) => val.nullable().strip(),
}),
competence: yup.string().when("typePrestataire", {
diff --git a/packages/migrations/src/migrations/20241107125107_hebergement-refacto.js b/packages/migrations/src/migrations/20241107125107_hebergement-refacto.js
new file mode 100644
index 000000000..df6e27dfd
--- /dev/null
+++ b/packages/migrations/src/migrations/20241107125107_hebergement-refacto.js
@@ -0,0 +1,333 @@
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
+exports.up = function (knex) {
+ return knex.raw(`
+CREATE TABLE FRONT.ADRESSE (
+ ID SERIAL NOT NULL,
+ CLE_INSEE VARCHAR(50) UNIQUE,
+ LABEL TEXT NOT NULL,
+ CODE_INSEE VARCHAR(5) NOT NULL,
+ CODE_POSTAL VARCHAR(5) NOT NULL,
+ LONG DOUBLE PRECISION NOT NULL,
+ LAT DOUBLE PRECISION NOT NULL,
+ DEPARTEMENT VARCHAR(3) REFERENCES GEO.TERRITOIRES (CODE),
+ CONSTRAINT PK_ADRESSE PRIMARY KEY (ID),
+ CONSTRAINT UNIQUE_CLE_INSEE UNIQUE (CLE_INSEE)
+);
+
+INSERT INTO
+ FRONT.ADRESSE (
+ LABEL,
+ CODE_INSEE,
+ CODE_POSTAL,
+ LONG,
+ LAT,
+ DEPARTEMENT
+ )
+SELECT DISTINCT
+ COORDONNEES -> 'adresse' ->> 'label' AS LABEL,
+ COORDONNEES -> 'adresse' ->> 'codeInsee' AS CODE_INSEE,
+ COORDONNEES -> 'adresse' ->> 'codePostal' AS CODE_POSTAL,
+ (COORDONNEES -> 'adresse' -> 'coordinates' -> 0)::DOUBLE PRECISION AS LONG,
+ (COORDONNEES -> 'adresse' -> 'coordinates' -> 1)::DOUBLE PRECISION AS LAT,
+ COORDONNEES -> 'adresse' ->> 'departement' AS DEPARTEMENT
+FROM
+ FRONT.HEBERGEMENT ;
+
+CREATE TABLE FRONT.HEBERGEMENT_TYPE (
+ ID SERIAL NOT NULL,
+ VALUE VARCHAR(100),
+ CONSTRAINT PK_HEBERGEMENT_TYPE PRIMARY KEY (ID)
+);
+
+INSERT INTO
+ FRONT.HEBERGEMENT_TYPE (VALUE)
+VALUES
+ ('hotel'),
+ ('meuble_tourisme'),
+ ('residence_tourisme'),
+ ('camping'),
+ ('autre') ;
+
+CREATE TABLE FRONT.HEBERGEMENT_TYPE_PENSION (
+ ID SERIAL NOT NULL,
+ VALUE VARCHAR(100),
+ CONSTRAINT PK_HEBERGEMENT_TYPE_PENSION PRIMARY KEY (ID)
+);
+
+INSERT INTO
+ FRONT.HEBERGEMENT_TYPE_PENSION (VALUE)
+VALUES
+ ('hebergement_seul'),
+ ('petit_dejeuner'),
+ ('demi_pension'),
+ ('pension_complete') ;
+
+CREATE TABLE FRONT.HEBERGEMENT_ACCESSIBILITE (
+ ID SERIAL NOT NULL,
+ VALUE VARCHAR(100),
+ CONSTRAINT PK_HEBERGEMENT_ACCESSIBILITE PRIMARY KEY (ID)
+);
+
+INSERT INTO
+ FRONT.HEBERGEMENT_ACCESSIBILITE (VALUE)
+VALUES
+ ('accessible'),
+ ('non_adapte'),
+ ('commentaires') ;
+
+CREATE TABLE FRONT.HEBERGEMENT_PRESTATIONS_HOTELIERES (
+ ID SERIAL NOT NULL,
+ VALUE VARCHAR(100),
+ CONSTRAINT PK_HEBERGEMENT_PRESTATIONS_HOTELIERES PRIMARY KEY (ID)
+);
+
+INSERT INTO
+ FRONT.HEBERGEMENT_PRESTATIONS_HOTELIERES (VALUE)
+VALUES
+ ('blanchisseries'),
+ ('entretien_locaux') ;
+
+CREATE TABLE FRONT.HEBERGEMENT_TO_PRESTATIONS_HOTELIERES(
+ HEBERGEMENT_ID INTEGER REFERENCES FRONT.HEBERGEMENT (ID) ON DELETE CASCADE,
+ PRESTATION_ID INTEGER REFERENCES FRONT.HEBERGEMENT_PRESTATIONS_HOTELIERES (ID) ON DELETE CASCADE,
+ CONSTRAINT pk_hebergement_prestation PRIMARY KEY (HEBERGEMENT_ID, PRESTATION_ID)
+);
+
+ALTER TABLE FRONT.HEBERGEMENT
+ADD COLUMN HEBERGEMENT_ID UUID NOT NULL DEFAULT GEN_RANDOM_UUID (),
+ADD COLUMN CURRENT BOOLEAN NOT NULL DEFAULT TRUE,
+ADD COLUMN CREATED_BY INTEGER REFERENCES FRONT.USERS (ID),
+ADD COLUMN EDITED_BY INTEGER REFERENCES FRONT.USERS (ID),
+ADD COLUMN EMAIL VARCHAR(320),
+ADD COLUMN ADRESSE_ID INTEGER REFERENCES FRONT.ADRESSE (ID),
+ADD COLUMN TELEPHONE_1 VARCHAR(20),
+ADD COLUMN TELEPHONE_2 VARCHAR(20),
+ADD COLUMN NOM_GESTIONNAIRE VARCHAR(320),
+ADD COLUMN TYPE_ID INTEGER REFERENCES FRONT.HEBERGEMENT_TYPE (ID),
+ADD COLUMN TYPE_PENSION_ID INTEGER REFERENCES FRONT.HEBERGEMENT_TYPE_PENSION (ID),
+ADD COLUMN NOMBRE_LITS INTEGER,
+ADD COLUMN LIT_DESSUS BOOLEAN,
+ADD COLUMN NOMBRE_LITS_SUPERPOSES INTEGER,
+ADD COLUMN NOMBRE_MAX_PERSONNES_COUCHAGE INTEGER,
+ADD COLUMN VISITE_LOCAUX BOOLEAN,
+ADD COLUMN VISITE_LOCAUX_AT TIMESTAMP WITH TIME ZONE,
+ADD COLUMN ACCESSIBILITE_ID INTEGER REFERENCES FRONT.HEBERGEMENT_ACCESSIBILITE (ID),
+ADD COLUMN ACCESSIBILITE_PRECISION TEXT,
+ADD COLUMN CHAMBRES_DOUBLES BOOLEAN,
+ADD COLUMN CHAMBRES_UNISEXES BOOLEAN,
+ADD COLUMN REGLEMENTATION_ERP BOOLEAN,
+ADD COLUMN COUCHAGE_INDIVIDUEL BOOLEAN,
+ADD COLUMN RANGEMENT_INDIVIDUEL BOOLEAN,
+ADD COLUMN AMENAGEMENTS_SPECIFIQUES BOOLEAN,
+ADD COLUMN AMENAGEMENTS_SPECIFIQUES_PRECISION TEXT,
+ADD COLUMN DESCRIPTION_LIEU_HEBERGEMENT TEXT,
+ADD COLUMN EXCURSION_DESCRIPTION TEXT,
+ADD COLUMN DEPLACEMENT_PROXIMITE_DESCRIPTION TEXT,
+ADD COLUMN VEHICULES_ADAPTES TEXT,
+ADD COLUMN FILE_REPONSE_EXPLOITANT_OU_PROPRIETAIRE UUID,
+ADD COLUMN FILE_DERNIER_ARRETE_AUTORISATION_MAIRE UUID,
+ADD COLUMN FILE_DERNIERE_ATTESTATION_SECURITE UUID;
+
+UPDATE FRONT.HEBERGEMENT
+SET
+ EMAIL = COORDONNEES ->> 'email',
+ ADRESSE_ID = (
+ SELECT
+ ID
+ FROM
+ FRONT.ADRESSE A
+ WHERE
+ A.LABEL = COORDONNEES -> 'adresse' ->> 'label'
+ AND A.CODE_INSEE = COORDONNEES -> 'adresse' ->> 'codeInsee'
+ AND A.CODE_POSTAL = COORDONNEES -> 'adresse' ->> 'codePostal'
+ AND A.LONG = (COORDONNEES -> 'adresse' -> 'coordinates' -> 0)::DOUBLE PRECISION
+ AND A.LAT = (COORDONNEES -> 'adresse' -> 'coordinates' -> 1)::DOUBLE PRECISION
+ AND A.DEPARTEMENT = COORDONNEES -> 'adresse' ->> 'departement'
+ ),
+ TELEPHONE_1 = COORDONNEES ->> 'numTelephone1',
+ TELEPHONE_2 = COORDONNEES ->> 'numTelephone2',
+ NOM_GESTIONNAIRE = COORDONNEES ->> 'nomGestionnaire',
+ TYPE_ID = (
+ SELECT
+ ID
+ FROM
+ FRONT.HEBERGEMENT_TYPE
+ WHERE
+ VALUE = INFORMATIONS_LOCAUX ->> 'type'
+ ),
+ TYPE_PENSION_ID = (
+ SELECT
+ ID
+ FROM
+ FRONT.HEBERGEMENT_TYPE_PENSION
+ WHERE
+ VALUE = INFORMATIONS_LOCAUX ->> 'pension'
+ ),
+ LIT_DESSUS = (INFORMATIONS_LOCAUX ->> 'litsDessus')::BOOLEAN,
+ NOMBRE_LITS = (INFORMATIONS_LOCAUX ->> 'nombreLits')::INTEGER,
+ NOMBRE_LITS_SUPERPOSES = (INFORMATIONS_LOCAUX ->> 'nombreLitsSuperposes')::INTEGER,
+ NOMBRE_MAX_PERSONNES_COUCHAGE = (
+ INFORMATIONS_LOCAUX ->> 'nombreMaxPersonnesCouchage'
+ )::INTEGER,
+ VISITE_LOCAUX = (INFORMATIONS_LOCAUX ->> 'visiteLocaux')::BOOLEAN,
+ VISITE_LOCAUX_AT = (INFORMATIONS_LOCAUX ->> 'visiteLocauxAt')::TIMESTAMP WITH TIME ZONE,
+ ACCESSIBILITE_ID = (
+ SELECT
+ ID
+ FROM
+ FRONT.HEBERGEMENT_ACCESSIBILITE
+ WHERE
+ VALUE = INFORMATIONS_LOCAUX ->> 'accessibilite'
+ ),
+ ACCESSIBILITE_PRECISION = (INFORMATIONS_LOCAUX ->> 'accessibilitePrecision')::TEXT,
+ CHAMBRES_DOUBLES = (INFORMATIONS_LOCAUX ->> 'chambresDoubles')::BOOLEAN,
+ CHAMBRES_UNISEXES = (INFORMATIONS_LOCAUX ->> 'chambresUnisexes')::BOOLEAN,
+ REGLEMENTATION_ERP = (INFORMATIONS_LOCAUX ->> 'reglementationErp')::BOOLEAN,
+ COUCHAGE_INDIVIDUEL = (INFORMATIONS_LOCAUX ->> 'couchageIndividuel')::BOOLEAN,
+ RANGEMENT_INDIVIDUEL = (INFORMATIONS_LOCAUX ->> 'rangementIndividuel')::BOOLEAN,
+ AMENAGEMENTS_SPECIFIQUES = (INFORMATIONS_LOCAUX ->> 'amenagementsSpecifiques')::BOOLEAN,
+ AMENAGEMENTS_SPECIFIQUES_PRECISION = (INFORMATIONS_LOCAUX ->> 'precisionAmenagementsSpecifiques')::TEXT,
+ DESCRIPTION_LIEU_HEBERGEMENT = INFORMATIONS_LOCAUX ->> 'descriptionLieuHebergement',
+ EXCURSION_DESCRIPTION = INFORMATIONS_TRANSPORT ->> 'excursion',
+ DEPLACEMENT_PROXIMITE_DESCRIPTION = INFORMATIONS_TRANSPORT ->> 'deplacementProximite',
+ VEHICULES_ADAPTES = (INFORMATIONS_TRANSPORT ->> 'vehiculesAdaptes')::BOOLEAN,
+ FILE_REPONSE_EXPLOITANT_OU_PROPRIETAIRE = (
+ INFORMATIONS_LOCAUX -> 'fileReponseExploitantOuProprietaire' ->> 'uuid'
+ )::UUID,
+ FILE_DERNIER_ARRETE_AUTORISATION_MAIRE = (
+ INFORMATIONS_LOCAUX -> 'fileDernierArreteAutorisationMaire' ->> 'uuid'
+ )::UUID,
+ FILE_DERNIERE_ATTESTATION_SECURITE = (
+ INFORMATIONS_LOCAUX -> 'fileDerniereAttestationSecurite' ->> 'uuid'
+ )::UUID;
+
+INSERT INTO
+ FRONT.HEBERGEMENT_TO_PRESTATIONS_HOTELIERES (HEBERGEMENT_ID, PRESTATION_ID)
+SELECT
+ HEBERGEMENT_ID,
+ (
+ SELECT
+ ID
+ FROM
+ FRONT.HEBERGEMENT_PRESTATIONS_HOTELIERES
+ WHERE
+ VALUE = SUB_HEBERGEMENT.HEBERGEMENT_PRESTATIONS_HOTELIERES_VALUE
+ )
+FROM
+ (
+ SELECT
+ ID AS HEBERGEMENT_ID,
+ JSONB_ARRAY_ELEMENTS(
+ INFORMATIONS_LOCAUX -> 'prestationsHotelieres'::TEXT
+ ) ->> 0 AS HEBERGEMENT_PRESTATIONS_HOTELIERES_VALUE
+ FROM
+ FRONT.HEBERGEMENT
+ ) SUB_HEBERGEMENT;
+
+CREATE TABLE FRONT.DEMANDE_SEJOUR_TO_HEBERGEMENT (
+ HEBERGEMENT_ID INTEGER REFERENCES FRONT.HEBERGEMENT (ID),
+ DEMANDE_SEJOUR_ID INTEGER REFERENCES FRONT.DEMANDE_SEJOUR (ID),
+ DATE_DEBUT TIMESTAMP WITH TIME ZONE NOT NULL,
+ DATE_FIN TIMESTAMP WITH TIME ZONE NOT NULL,
+ CONSTRAINT UNIQUE_IDS_DATES UNIQUE (
+ HEBERGEMENT_ID,
+ DEMANDE_SEJOUR_ID,
+ DATE_DEBUT,
+ DATE_FIN
+ )
+) ;
+
+INSERT INTO
+ FRONT.DEMANDE_SEJOUR_TO_HEBERGEMENT (
+ HEBERGEMENT_ID,
+ DEMANDE_SEJOUR_ID,
+ DATE_DEBUT,
+ DATE_FIN
+ )
+SELECT
+ (
+ JSONB_ARRAY_ELEMENTS(HEBERGEMENT -> 'hebergements') -> 'hebergementId' ->> 0
+ )::INTEGER AS HEBERGEMENT_ID,
+ ID AS DEMANDE_SEJOUR_ID,
+ (
+ JSONB_ARRAY_ELEMENTS(HEBERGEMENT -> 'hebergements') -> 'dateDebut' ->> 0
+ )::TIMESTAMP WITH TIME ZONE AS DATE_DEBUT,
+ (
+ JSONB_ARRAY_ELEMENTS(HEBERGEMENT -> 'hebergements') -> 'dateFin' ->> 0
+ )::TIMESTAMP WITH TIME ZONE AS DATE_FIN
+FROM
+ FRONT.DEMANDE_SEJOUR ;
+
+CREATE UNIQUE INDEX idx_hebergement_hebergement_id ON FRONT.HEBERGEMENT (hebergement_id) WHERE (CURRENT IS TRUE);
+
+GRANT ALL ON TABLE FRONT.ADRESSE TO vao_u ;
+GRANT ALL ON TABLE FRONT.HEBERGEMENT_TYPE TO vao_u ;
+GRANT ALL ON TABLE FRONT.HEBERGEMENT_TYPE_PENSION TO vao_u ;
+GRANT ALL ON TABLE FRONT.HEBERGEMENT_ACCESSIBILITE TO vao_u ;
+GRANT ALL ON TABLE FRONT.HEBERGEMENT_PRESTATIONS_HOTELIERES TO vao_u ;
+GRANT ALL ON TABLE FRONT.HEBERGEMENT_TO_PRESTATIONS_HOTELIERES TO vao_u ;
+GRANT ALL ON TABLE FRONT.DEMANDE_SEJOUR_TO_HEBERGEMENT TO vao_u ;
+
+GRANT ALL ON SEQUENCE FRONT.ADRESSE_ID_SEQ TO VAO_U ;
+GRANT ALL ON SEQUENCE FRONT.HEBERGEMENT_TYPE_ID_SEQ TO VAO_U ;
+GRANT ALL ON SEQUENCE FRONT.HEBERGEMENT_TYPE_PENSION_ID_SEQ TO VAO_U ;
+GRANT ALL ON SEQUENCE FRONT.HEBERGEMENT_ACCESSIBILITE_ID_SEQ TO VAO_U ;
+GRANT ALL ON SEQUENCE FRONT.HEBERGEMENT_PRESTATIONS_HOTELIERES_ID_SEQ TO VAO_U ;
+
+ `);
+};
+
+/**
+ * @param { import("knex").Knex } knex
+ * @returns { Promise }
+ */
+exports.down = function (knex) {
+ return knex.raw(`
+ALTER TABLE FRONT.HEBERGEMENT
+DROP COLUMN HEBERGEMENT_ID,
+DROP COLUMN CURRENT,
+DROP COLUMN CREATED_BY,
+DROP COLUMN EDITED_BY,
+DROP COLUMN EMAIL,
+DROP COLUMN ADRESSE_ID,
+DROP COLUMN TELEPHONE_1,
+DROP COLUMN TELEPHONE_2,
+DROP COLUMN NOM_GESTIONNAIRE,
+DROP COLUMN TYPE_ID,
+DROP COLUMN TYPE_PENSION_ID,
+DROP COLUMN NOMBRE_LITS,
+DROP COLUMN LIT_DESSUS,
+DROP COLUMN NOMBRE_LITS_SUPERPOSES,
+DROP COLUMN NOMBRE_MAX_PERSONNES_COUCHAGE,
+DROP COLUMN VISITE_LOCAUX,
+DROP COLUMN ACCESSIBILITE_ID,
+DROP COLUMN CHAMBRES_DOUBLES,
+DROP COLUMN CHAMBRES_UNISEXES,
+DROP COLUMN REGLEMENTATION_ERP,
+DROP COLUMN COUCHAGE_INDIVIDUEL,
+DROP COLUMN RANGEMENT_INDIVIDUEL,
+DROP COLUMN AMENAGEMENTS_SPECIFIQUES,
+DROP COLUMN DESCRIPTION_LIEU_HEBERGEMENT,
+DROP COLUMN EXCURSION_DESCRIPTION,
+DROP COLUMN DEPLACEMENT_PROXIMITE_DESCRIPTION,
+DROP COLUMN VEHICULES_ADAPTES,
+DROP COLUMN FILE_REPONSE_EXPLOITANT_OU_PROPRIETAIRE,
+DROP COLUMN FILE_DERNIER_ARRETE_AUTORISATION_MAIRE,
+DROP COLUMN FILE_DERNIERE_ATTESTATION_SECURITE,
+DROP COLUMN VISITE_LOCAUX_AT,
+DROP COLUMN ACCESSIBILITE_PRECISION,
+DROP COLUMN AMENAGEMENTS_SPECIFIQUES_PRECISION;
+
+DROP TABLE FRONT.HEBERGEMENT_TO_PRESTATIONS_HOTELIERES ;
+DROP TABLE FRONT.HEBERGEMENT_PRESTATIONS_HOTELIERES ;
+DROP TABLE FRONT.HEBERGEMENT_ACCESSIBILITE ;
+DROP TABLE FRONT.HEBERGEMENT_TYPE_PENSION ;
+DROP TABLE FRONT.HEBERGEMENT_TYPE ;
+DROP TABLE FRONT.ADRESSE ;
+
+DROP TABLE FRONT.DEMANDE_SEJOUR_TO_HEBERGEMENT ;
+ `);
+};
diff --git a/packages/shared/src/schema/adresse.js b/packages/shared/src/schema/adresse.js
index 023eae706..945b3acbb 100644
--- a/packages/shared/src/schema/adresse.js
+++ b/packages/shared/src/schema/adresse.js
@@ -3,6 +3,7 @@ import * as yup from "yup";
export const adresseSchema = ({ isFromAPIAdresse } = {}) => {
return isFromAPIAdresse
? {
+ cleInsee: yup.string().nullable(true),
codeInsee: yup.string().required("ce champ est obligatoire"),
codePostal: yup.string().required("ce champ est obligatoire"),
coordinates: yup.array().required("ce champ est obligatoire"),