From 4f07f00cc64e944ddc06054338e64c315885ee06 Mon Sep 17 00:00:00 2001 From: Paul Gaucher Date: Fri, 22 Mar 2024 18:10:42 +0100 Subject: [PATCH 1/2] feat: ajout du brouillon dans le user --- .../src/common/actions/effectifs.actions.ts | 2 +- .../validation/dossierApprenantSchemaV1V2.ts | 3 +- .../validation/dossierApprenantSchemaV3.ts | 3 +- .../admin.routes/transmissions.routes.ts | 2 +- .../specific.routes/transmission.routes.ts | 2 +- .../routes/specific.routes/user.routes.ts | 41 +++++++++++++++++++ server/src/http/server.ts | 8 ++-- .../common/validation/zodPrimitives.test.ts | 2 +- .../models/apis}/effectifsCreationSchema.ts | 6 +-- shared/models/data/usersMigration.model.ts | 3 ++ .../models/data}/zodPrimitives.ts | 7 ++-- 11 files changed, 62 insertions(+), 17 deletions(-) create mode 100644 server/src/http/routes/specific.routes/user.routes.ts rename {server/src/common/validation => shared/models/apis}/effectifsCreationSchema.ts (89%) rename {server/src/common/validation/utils => shared/models/data}/zodPrimitives.ts (99%) diff --git a/server/src/common/actions/effectifs.actions.ts b/server/src/common/actions/effectifs.actions.ts index 603d54221..4929b0649 100644 --- a/server/src/common/actions/effectifs.actions.ts +++ b/server/src/common/actions/effectifs.actions.ts @@ -1,6 +1,7 @@ import Boom from "boom"; import { cloneDeep, isObject, merge, mergeWith, reduce, set, uniqBy } from "lodash-es"; import { ObjectId } from "mongodb"; +import { IEffectifCreationSchema } from "shared/models/apis/effectifsCreationSchema"; import { IEffectif } from "shared/models/data/effectifs.model"; import { IOrganisme } from "shared/models/data/organismes.model"; import { cyrb53Hash, normalize } from "shared/utils/crypt"; @@ -10,7 +11,6 @@ import { effectifsDb } from "@/common/model/collections"; import { defaultValuesEffectif } from "@/common/model/effectifs.model/effectifs.model"; import { stripEmptyFields } from "../utils/miscUtils"; -import { IEffectifCreationSchema } from "../validation/effectifsCreationSchema"; import { legacySchema } from "./effectif.legacy_schema"; import { getOrganismeById } from "./organismes/organismes.actions"; diff --git a/server/src/common/validation/dossierApprenantSchemaV1V2.ts b/server/src/common/validation/dossierApprenantSchemaV1V2.ts index f10c957e7..c3f00ad9b 100644 --- a/server/src/common/validation/dossierApprenantSchemaV1V2.ts +++ b/server/src/common/validation/dossierApprenantSchemaV1V2.ts @@ -1,7 +1,6 @@ +import { primitivesV1, primitivesV3 } from "shared/models/data/zodPrimitives"; import { z } from "zod"; -import { primitivesV1, primitivesV3 } from "@/common/validation/utils/zodPrimitives"; - /** * Note: ce schema est seulement utilisé pour générer la documentation OpenAPI pour l'API v1. * Les données entrantes de l'API V1 sont validées par dossierApprenantSchema (Joi). diff --git a/server/src/common/validation/dossierApprenantSchemaV3.ts b/server/src/common/validation/dossierApprenantSchemaV3.ts index b587868ae..43dc69f8e 100644 --- a/server/src/common/validation/dossierApprenantSchemaV3.ts +++ b/server/src/common/validation/dossierApprenantSchemaV3.ts @@ -1,8 +1,7 @@ import { NIR_LOOSE_REGEX } from "shared"; +import { primitivesV1, primitivesV3 } from "shared/models/data/zodPrimitives"; import { z } from "zod"; -import { primitivesV1, primitivesV3 } from "@/common/validation/utils/zodPrimitives"; - export const stripModelAdditionalKeys = (validationSchema, data) => { const strippedData = Object.keys(validationSchema.shape).reduce((acc, curr) => { return data[curr] !== undefined diff --git a/server/src/http/routes/admin.routes/transmissions.routes.ts b/server/src/http/routes/admin.routes/transmissions.routes.ts index 4bf39064b..cbc094de7 100644 --- a/server/src/http/routes/admin.routes/transmissions.routes.ts +++ b/server/src/http/routes/admin.routes/transmissions.routes.ts @@ -1,4 +1,5 @@ import express from "express"; +import { extensions } from "shared/models/data/zodPrimitives"; import { z } from "zod"; import { @@ -6,7 +7,6 @@ import { getAllErrorsTransmissionStatusGroupedByOrganismeForAGivenDay, } from "@/common/actions/indicateurs/transmissions/transmission.action"; import paginationSchema from "@/common/validation/paginationSchema"; -import { extensions } from "@/common/validation/utils/zodPrimitives"; import { returnResult } from "@/http/middlewares/helpers"; import validateRequestMiddleware from "@/http/middlewares/validateRequestMiddleware"; diff --git a/server/src/http/routes/specific.routes/transmission.routes.ts b/server/src/http/routes/specific.routes/transmission.routes.ts index 6c280da95..62b002e57 100644 --- a/server/src/http/routes/specific.routes/transmission.routes.ts +++ b/server/src/http/routes/specific.routes/transmission.routes.ts @@ -1,5 +1,6 @@ import { ObjectId } from "bson"; import express from "express"; +import { extensions } from "shared/models/data/zodPrimitives"; import { z } from "zod"; import { @@ -8,7 +9,6 @@ import { getSuccessfulTransmissionStatusDetailsForAGivenDay, } from "@/common/actions/indicateurs/transmissions/transmission.action"; import paginationSchema from "@/common/validation/paginationSchema"; -import { extensions } from "@/common/validation/utils/zodPrimitives"; import { returnResult, requireOrganismePermission } from "@/http/middlewares/helpers"; import validateRequestMiddleware from "@/http/middlewares/validateRequestMiddleware"; diff --git a/server/src/http/routes/specific.routes/user.routes.ts b/server/src/http/routes/specific.routes/user.routes.ts new file mode 100644 index 000000000..faedef5db --- /dev/null +++ b/server/src/http/routes/specific.routes/user.routes.ts @@ -0,0 +1,41 @@ +import express from "express"; +import { effectifCreationSchema } from "shared/models/apis/effectifsCreationSchema"; + +import { usersMigrationDb } from "@/common/model/collections"; +import { AuthContext } from "@/common/model/internal/AuthContext"; +import { returnResult } from "@/http/middlewares/helpers"; +import validateRequestMiddleware from "@/http/middlewares/validateRequestMiddleware"; + +export default () => { + const router = express.Router(); + + router.get("/effectif-draft", returnResult(getUserDraft)); + + router.put( + "/effectif-draft", + validateRequestMiddleware({ body: effectifCreationSchema.deepPartial() }), + returnResult(updateUserDraft) + ); + return router; +}; + +const getUserDraft = async (req) => { + const user = req.user as AuthContext; + const found = await usersMigrationDb().findOne({ _id: user._id }); + return found?.draft_effectif_form ?? {}; +}; + +const updateUserDraft = async (req) => { + const user = req.user as AuthContext; + const updated = await usersMigrationDb().findOneAndUpdate( + { + _id: user._id, + }, + { + $set: { + draft_effectif_form: req.body, + }, + } + ); + return updated.value?.draft_effectif_form; +}; diff --git a/server/src/http/server.ts b/server/src/http/server.ts index 47f164fd6..a30662179 100644 --- a/server/src/http/server.ts +++ b/server/src/http/server.ts @@ -10,6 +10,8 @@ import Joi from "joi"; import { ObjectId } from "mongodb"; import passport from "passport"; import { typesEffectifNominatif, CODE_POSTAL_REGEX } from "shared"; +import { effectifCreationSchema, IEffectifCreationSchema } from "shared/models/apis/effectifsCreationSchema"; +import { extensions, primitivesV1, primitivesV3 } from "shared/models/data/zodPrimitives"; import swaggerUi from "swagger-ui-express"; import { z } from "zod"; @@ -104,12 +106,10 @@ import { passwordSchema, validateFullObjectSchema, validateFullZodObjectSchema } import { SReqPostVerifyUser } from "@/common/validation/ApiERPSchema"; import { configurationERPSchema } from "@/common/validation/configurationERPSchema"; import { dossierApprenantSchemaV3WithMoreRequiredFieldsValidatingUAISiret } from "@/common/validation/dossierApprenantSchemaV3"; -import { effectifCreationSchema, IEffectifCreationSchema } from "@/common/validation/effectifsCreationSchema"; import loginSchemaLegacy from "@/common/validation/loginSchemaLegacy"; import objectIdSchema from "@/common/validation/objectIdSchema"; import { registrationSchema, registrationUnknownNetworkSchema } from "@/common/validation/registrationSchema"; import userProfileSchema from "@/common/validation/userProfileSchema"; -import { extensions, primitivesV1, primitivesV3 } from "@/common/validation/utils/zodPrimitives"; import config from "@/config"; import { authMiddleware, checkActivationToken, checkPasswordToken } from "./helpers/passport-handlers"; @@ -137,6 +137,7 @@ import dossierApprenantRouter from "./routes/specific.routes/dossiers-apprenants import { getOrganismeEffectifs, updateOrganismeEffectifs } from "./routes/specific.routes/organisme.routes"; import organismesRouter from "./routes/specific.routes/organismes.routes"; import transmissionRoutes from "./routes/specific.routes/transmission.routes"; +import userRoutes from "./routes/specific.routes/user.routes"; const openapiSpecs = JSON.parse(fs.readFileSync(openApiFilePath, "utf8")); @@ -435,7 +436,8 @@ function setupRoutes(app: Application) { has_accept_cgu_version: req.params.version, }); }) - ); + ) + .use("/api/v1/user", userRoutes()); /******************************** * API pour un organisme * diff --git a/server/tests/integration/common/validation/zodPrimitives.test.ts b/server/tests/integration/common/validation/zodPrimitives.test.ts index e3807f566..13bd20c94 100644 --- a/server/tests/integration/common/validation/zodPrimitives.test.ts +++ b/server/tests/integration/common/validation/zodPrimitives.test.ts @@ -1,4 +1,4 @@ -import { primitivesV3 } from "@/common/validation/utils/zodPrimitives"; +import { primitivesV3 } from "shared/models/data/zodPrimitives"; describe("Regex primitivesV3", () => { describe("derniere_situation", () => { diff --git a/server/src/common/validation/effectifsCreationSchema.ts b/shared/models/apis/effectifsCreationSchema.ts similarity index 89% rename from server/src/common/validation/effectifsCreationSchema.ts rename to shared/models/apis/effectifsCreationSchema.ts index e96faebe0..4af09fa26 100644 --- a/server/src/common/validation/effectifsCreationSchema.ts +++ b/shared/models/apis/effectifsCreationSchema.ts @@ -1,9 +1,9 @@ +import { z } from "zod"; + import { zApprenant } from "shared/models/data/effectifs/apprenant.part"; import { zContrat } from "shared/models/data/effectifs/contrat.part"; import { zFormationEffectif } from "shared/models/data/effectifs/formation.part"; -import { z } from "zod"; - -import { primitivesV1, primitivesV3 } from "@/common/validation/utils/zodPrimitives"; +import { primitivesV1, primitivesV3 } from "shared/models/data/zodPrimitives"; export const effectifCreationSchema = z.object({ annee_scolaire: primitivesV1.formation.annee_scolaire, diff --git a/shared/models/data/usersMigration.model.ts b/shared/models/data/usersMigration.model.ts index 29150ceba..e7a406fb2 100644 --- a/shared/models/data/usersMigration.model.ts +++ b/shared/models/data/usersMigration.model.ts @@ -2,6 +2,8 @@ import type { CreateIndexesOptions, IndexSpecification } from "mongodb"; import { z } from "zod"; import { zObjectId } from "zod-mongodb-schema"; +import { effectifCreationSchema } from "../apis/effectifsCreationSchema"; + export const collectionName = "usersMigration"; const indexes: [IndexSpecification, CreateIndexesOptions][] = [ @@ -65,6 +67,7 @@ export const zUsersMigration = z.object({ ) .optional(), unsubscribe: z.boolean().optional().describe("unsubscribe email"), + draft_effectif_form: effectifCreationSchema.deepPartial().nullish(), }); export type IUsersMigration = z.output; diff --git a/server/src/common/validation/utils/zodPrimitives.ts b/shared/models/data/zodPrimitives.ts similarity index 99% rename from server/src/common/validation/utils/zodPrimitives.ts rename to shared/models/data/zodPrimitives.ts index 6c6f111c3..08f4b6117 100644 --- a/server/src/common/validation/utils/zodPrimitives.ts +++ b/shared/models/data/zodPrimitives.ts @@ -1,6 +1,8 @@ import { extendZodWithOpenApi } from "@asteasolutions/zod-to-openapi"; import { subDays } from "date-fns"; import { capitalize } from "lodash-es"; +import { z } from "zod"; + import { CODES_STATUT_APPRENANT_ENUM, EFFECTIF_DERNIER_SITUATION, @@ -11,10 +13,9 @@ import { UAI_REGEX, CODE_POSTAL_REGEX, DERNIER_ORGANISME_UAI_REGEX, -} from "shared"; -import { z } from "zod"; +} from "shared/constants"; -import { telephoneConverter } from "./frenchTelephoneNumber"; +import { telephoneConverter } from "../../../server/src/common/validation/utils/frenchTelephoneNumber"; extendZodWithOpenApi(z); From 036dd66f0654217eaf4049aa51b577dcd9764915 Mon Sep 17 00:00:00 2001 From: Paul Gaucher Date: Tue, 26 Mar 2024 15:59:49 +0100 Subject: [PATCH 2/2] feat: mise a jour du snapshot de userMigration --- .../validationSchema.test.ts.snap | 2196 +++++++++++++++++ 1 file changed, 2196 insertions(+) diff --git a/server/src/common/mongodb/__snapshots__/validationSchema.test.ts.snap b/server/src/common/mongodb/__snapshots__/validationSchema.test.ts.snap index ed2248ccc..50134ff78 100644 --- a/server/src/common/mongodb/__snapshots__/validationSchema.test.ts.snap +++ b/server/src/common/mongodb/__snapshots__/validationSchema.test.ts.snap @@ -7219,6 +7219,2202 @@ exports[`validation-schema should create validation schema for usersMigration: u "bsonType": "date", "description": "Date de création du compte", }, + "draft_effectif_form": { + "anyOf": [ + { + "additionalProperties": false, + "bsonType": "object", + "properties": { + "annee_scolaire": { + "bsonType": "string", + "description": "Période scolaire", + }, + "apprenant": { + "additionalProperties": false, + "bsonType": "object", + "properties": { + "adresse": { + "anyOf": [ + { + "additionalProperties": false, + "bsonType": "object", + "properties": { + "academie": { + "bsonType": "string", + "enum": [ + "1", + "2", + "3", + "4", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "20", + "22", + "23", + "24", + "25", + "27", + "28", + "31", + "32", + "33", + "43", + "44", + "70", + "77", + "78", + ], + }, + "bassinEmploi": { + "bsonType": "string", + "description": "Code Bassin d'emploi", + }, + "code_insee": { + "bsonType": "string", + "description": "Le code insee doit contenir 5 caractères", + "pattern": "^[0-9]{1}[0-9A-Z]{1}[0-9]{3}$", + }, + "code_postal": { + "bsonType": "string", + "description": "Le code postal doit contenir 5 caractères", + "pattern": "^[0-9]{5}$", + }, + "commune": { + "bsonType": "string", + "description": "Commune", + "maxLength": 80, + }, + "complement": { + "bsonType": "string", + "description": "Complément d'adresse", + }, + "complete": { + "bsonType": "string", + "description": "Adresse complète", + }, + "departement": { + "bsonType": "string", + "enum": [ + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "21", + "22", + "23", + "24", + "25", + "26", + "27", + "28", + "29", + "30", + "31", + "32", + "33", + "34", + "35", + "36", + "37", + "38", + "39", + "40", + "41", + "42", + "43", + "44", + "45", + "46", + "47", + "48", + "49", + "50", + "51", + "52", + "53", + "54", + "55", + "56", + "57", + "58", + "59", + "60", + "61", + "62", + "63", + "64", + "65", + "66", + "67", + "68", + "69", + "70", + "71", + "72", + "73", + "74", + "75", + "76", + "77", + "78", + "79", + "80", + "81", + "82", + "83", + "84", + "85", + "86", + "87", + "88", + "89", + "90", + "91", + "92", + "93", + "94", + "95", + "971", + "972", + "973", + "974", + "975", + "976", + "977", + "978", + "984", + "986", + "987", + "988", + "989", + "01", + "02", + "03", + "04", + "05", + "06", + "07", + "08", + "09", + "2A", + "2B", + ], + }, + "numero": { + "bsonType": "int", + "description": "N° de la voie", + }, + "pays": { + "bsonType": "string", + "description": "Pays", + "enum": [ + "AF", + "ZA", + "AL", + "DZ", + "DE", + "AD", + "AO", + "AG", + "SA", + "AR", + "AM", + "AU", + "AT", + "AZ", + "BS", + "BH", + "BD", + "BB", + "BE", + "BZ", + "BJ", + "BT", + "BY", + "MM", + "BO", + "BQ", + "BA", + "BW", + "BR", + "BN", + "BG", + "BF", + "BI", + "KH", + "CM", + "CA", + "CV", + "CF", + "CL", + "CN", + "CY", + "CO", + "KM", + "CG", + "CD", + "KR", + "KP", + "CR", + "CI", + "HR", + "CU", + "CW", + "DK", + "DJ", + "DO", + "DM", + "EG", + "SV", + "AE", + "EC", + "ER", + "ES", + "EE", + "SZ", + "US", + "ET", + "MK", + "FJ", + "FI", + "FR", + "GA", + "GM", + "GE", + "GH", + "GR", + "GD", + "GT", + "GN", + "GQ", + "GW", + "GY", + "HT", + "HN", + "HU", + "IN", + "ID", + "IR", + "IQ", + "IE", + "IS", + "IL", + "IT", + "JM", + "JP", + "JO", + "KZ", + "KE", + "KG", + "KI", + "XK", + "KW", + "LA", + "LS", + "LV", + "LB", + "LR", + "LY", + "LI", + "LT", + "LU", + "MG", + "MY", + "MW", + "MV", + "ML", + "MT", + "MA", + "MH", + "MU", + "MR", + "MX", + "FM", + "MD", + "MC", + "MN", + "ME", + "MZ", + "NA", + "NR", + "NP", + "NI", + "NE", + "NG", + "NO", + "NZ", + "OM", + "UG", + "UZ", + "PK", + "PW", + "PS", + "PA", + "PG", + "PY", + "NL", + "PE", + "PH", + "PL", + "PT", + "QA", + "RO", + "GB", + "RU", + "RW", + "KN", + "SM", + "SX", + "VC", + "LC", + "SB", + "WS", + "ST", + "SN", + "RS", + "SC", + "SL", + "SG", + "SK", + "SI", + "SO", + "SD", + "SS", + "LK", + "SE", + "CH", + "SR", + "SY", + "TJ", + "TZ", + "TD", + "CZ", + "TH", + "TL", + "TG", + "TO", + "TT", + "TN", + "TM", + "TR", + "TV", + "UA", + "UY", + "VU", + "VA", + "VE", + "VN", + "YE", + "ZM", + "ZW", + ], + }, + "region": { + "bsonType": "string", + "enum": [ + "11", + "24", + "27", + "28", + "32", + "44", + "52", + "53", + "75", + "76", + "84", + "93", + "94", + "977", + "978", + "01", + "02", + "03", + "04", + "05", + "06", + "00", + ], + }, + "repetition_voie": { + "bsonType": "string", + "description": "Indice de répétition du numéro de voie", + "enum": [ + "B", + "T", + "Q", + "C", + ], + }, + "voie": { + "bsonType": "string", + "description": "Nom de voie", + }, + }, + }, + { + "bsonType": "null", + }, + ], + }, + "affelnet": { + "anyOf": [ + { + "bsonType": "array", + "items": { + "bsonType": "string", + "description": "voeux affelnet de l'apprenant", + }, + }, + { + "bsonType": "null", + }, + ], + }, + "code_postal_de_naissance": { + "anyOf": [ + { + "bsonType": "string", + "description": "Le code postal doit contenir 5 caractères. +Pour les jeunes résidents à l’étranger, il conviendra de mettre « 99 » suivi du numéro de pays. +*Exemple : pour l’Allemagne le code pays est 109, il conviendra donc de saisir : « 99109 »*", + "pattern": "^[0-9]{5}$", + }, + { + "bsonType": "null", + }, + ], + }, + "courriel": { + "bsonType": [ + "string", + "null", + ], + }, + "date_de_naissance": { + "anyOf": [ + { + "bsonType": "date", + "description": "Date de naissance de l'apprenant", + }, + { + "bsonType": "null", + }, + ], + }, + "date_rqth": { + "anyOf": [ + { + "bsonType": "date", + "description": "Date de la reconnaissance travailleur handicapé", + }, + { + "bsonType": "null", + }, + ], + }, + "dernier_diplome": { + "anyOf": [ + { + "bsonType": "number", + "description": "Dernier diplôme obtenu", + "enum": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 99, + ], + }, + { + "bsonType": "null", + }, + ], + }, + "dernier_organisme_uai": { + "anyOf": [ + { + "bsonType": "string", + "description": "Numéro UAI de l’établissement fréquenté l’année dernière (N-1), si déjà en apprentissage, mettre l’UAI du site de formation + ou département. +* Pour les apprentis en emploi l'année dernière, le numéro UAI n-1 à indiquer est le **995** qui signifie "Non concerné". + +* Si cette information n'est pas connue, le numéro UAI n-1 à indiquer est le **993** qui signifie "Inconnu" ", + "pattern": "^(0?[0-9][0-9]|0?2[AB]|0?9[012345]|97[1234678]|98[46789]|99[0135]|[0-9]{7}[a-zA-Z])$", + }, + { + "bsonType": "null", + }, + ], + }, + "derniere_situation": { + "anyOf": [ + { + "bsonType": "number", + "description": "Situation de l'apprenant N-1", + "enum": [ + 1003, + 1005, + 1009, + 1013, + 1015, + 1017, + 1019, + 1021, + 1023, + 2001, + 2003, + 2005, + 2007, + 3001, + 3101, + 3003, + 3103, + 3009, + 3109, + 3011, + 3111, + 3031, + 3131, + 3032, + 3132, + 3033, + 3133, + 3117, + 3119, + 3021, + 3121, + 3023, + 3123, + 4001, + 4101, + 4003, + 4103, + 4005, + 4105, + 4007, + 4107, + 4009, + 4011, + 4111, + 4013, + 4113, + 4015, + 4115, + 4017, + 4117, + 4019, + 4119, + 4021, + 4121, + 4023, + 4123, + 4025, + 4125, + 4027, + 4127, + 5901, + 5903, + 5905, + 5907, + 5909, + 9900, + 9999, + ], + }, + { + "bsonType": "null", + }, + ], + }, + "has_nir": { + "bsonType": [ + "bool", + "null", + ], + }, + "ine": { + "bsonType": [ + "string", + "null", + ], + }, + "inscription_sportif_haut_niveau": { + "bsonType": [ + "bool", + "null", + ], + }, + "mineur": { + "bsonType": [ + "bool", + "null", + ], + }, + "mineur_emancipe": { + "bsonType": [ + "bool", + "null", + ], + }, + "nationalite": { + "anyOf": [ + { + "bsonType": "number", + "description": "Apprenant étranger, non citoyen européen", + "enum": [ + 1, + 2, + 3, + ], + }, + { + "bsonType": "null", + }, + ], + }, + "nom": { + "bsonType": "string", + "description": "Nom de l'apprenant", + "minLength": 1, + }, + "organisme_gestionnaire": { + "bsonType": [ + "number", + "null", + ], + }, + "parcoursup": { + "anyOf": [ + { + "bsonType": "array", + "items": { + "bsonType": "string", + "description": "voeux parcoursup de l'apprenant", + }, + }, + { + "bsonType": "null", + }, + ], + }, + "prenom": { + "bsonType": "string", + "description": "Prénom de l'apprenant", + "minLength": 1, + }, + "regime_scolaire": { + "anyOf": [ + { + "bsonType": "string", + "description": "Régime scolaire (I : Interne, D : Demi-pensionnaire, E : Externe, IE : Interne externé)", + "enum": [ + "I", + "D", + "E", + "IE", + ], + }, + { + "bsonType": "null", + }, + ], + }, + "representant_legal": { + "anyOf": [ + { + "additionalProperties": false, + "bsonType": "object", + "properties": { + "adresse": { + "anyOf": [ + { + "additionalProperties": false, + "bsonType": "object", + "properties": { + "academie": { + "bsonType": "string", + "enum": [ + "1", + "2", + "3", + "4", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "20", + "22", + "23", + "24", + "25", + "27", + "28", + "31", + "32", + "33", + "43", + "44", + "70", + "77", + "78", + ], + }, + "bassinEmploi": { + "bsonType": "string", + "description": "Code Bassin d'emploi", + }, + "code_insee": { + "bsonType": "string", + "description": "Le code insee doit contenir 5 caractères", + "pattern": "^[0-9]{1}[0-9A-Z]{1}[0-9]{3}$", + }, + "code_postal": { + "bsonType": "string", + "description": "Le code postal doit contenir 5 caractères", + "pattern": "^[0-9]{5}$", + }, + "commune": { + "bsonType": "string", + "description": "Commune", + "maxLength": 80, + }, + "complement": { + "bsonType": "string", + "description": "Complément d'adresse", + }, + "complete": { + "bsonType": "string", + "description": "Adresse complète", + }, + "departement": { + "bsonType": "string", + "enum": [ + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "21", + "22", + "23", + "24", + "25", + "26", + "27", + "28", + "29", + "30", + "31", + "32", + "33", + "34", + "35", + "36", + "37", + "38", + "39", + "40", + "41", + "42", + "43", + "44", + "45", + "46", + "47", + "48", + "49", + "50", + "51", + "52", + "53", + "54", + "55", + "56", + "57", + "58", + "59", + "60", + "61", + "62", + "63", + "64", + "65", + "66", + "67", + "68", + "69", + "70", + "71", + "72", + "73", + "74", + "75", + "76", + "77", + "78", + "79", + "80", + "81", + "82", + "83", + "84", + "85", + "86", + "87", + "88", + "89", + "90", + "91", + "92", + "93", + "94", + "95", + "971", + "972", + "973", + "974", + "975", + "976", + "977", + "978", + "984", + "986", + "987", + "988", + "989", + "01", + "02", + "03", + "04", + "05", + "06", + "07", + "08", + "09", + "2A", + "2B", + ], + }, + "numero": { + "bsonType": "int", + "description": "N° de la voie", + }, + "pays": { + "bsonType": "string", + "description": "Pays", + "enum": [ + "AF", + "ZA", + "AL", + "DZ", + "DE", + "AD", + "AO", + "AG", + "SA", + "AR", + "AM", + "AU", + "AT", + "AZ", + "BS", + "BH", + "BD", + "BB", + "BE", + "BZ", + "BJ", + "BT", + "BY", + "MM", + "BO", + "BQ", + "BA", + "BW", + "BR", + "BN", + "BG", + "BF", + "BI", + "KH", + "CM", + "CA", + "CV", + "CF", + "CL", + "CN", + "CY", + "CO", + "KM", + "CG", + "CD", + "KR", + "KP", + "CR", + "CI", + "HR", + "CU", + "CW", + "DK", + "DJ", + "DO", + "DM", + "EG", + "SV", + "AE", + "EC", + "ER", + "ES", + "EE", + "SZ", + "US", + "ET", + "MK", + "FJ", + "FI", + "FR", + "GA", + "GM", + "GE", + "GH", + "GR", + "GD", + "GT", + "GN", + "GQ", + "GW", + "GY", + "HT", + "HN", + "HU", + "IN", + "ID", + "IR", + "IQ", + "IE", + "IS", + "IL", + "IT", + "JM", + "JP", + "JO", + "KZ", + "KE", + "KG", + "KI", + "XK", + "KW", + "LA", + "LS", + "LV", + "LB", + "LR", + "LY", + "LI", + "LT", + "LU", + "MG", + "MY", + "MW", + "MV", + "ML", + "MT", + "MA", + "MH", + "MU", + "MR", + "MX", + "FM", + "MD", + "MC", + "MN", + "ME", + "MZ", + "NA", + "NR", + "NP", + "NI", + "NE", + "NG", + "NO", + "NZ", + "OM", + "UG", + "UZ", + "PK", + "PW", + "PS", + "PA", + "PG", + "PY", + "NL", + "PE", + "PH", + "PL", + "PT", + "QA", + "RO", + "GB", + "RU", + "RW", + "KN", + "SM", + "SX", + "VC", + "LC", + "SB", + "WS", + "ST", + "SN", + "RS", + "SC", + "SL", + "SG", + "SK", + "SI", + "SO", + "SD", + "SS", + "LK", + "SE", + "CH", + "SR", + "SY", + "TJ", + "TZ", + "TD", + "CZ", + "TH", + "TL", + "TG", + "TO", + "TT", + "TN", + "TM", + "TR", + "TV", + "UA", + "UY", + "VU", + "VA", + "VE", + "VN", + "YE", + "ZM", + "ZW", + ], + }, + "region": { + "bsonType": "string", + "enum": [ + "11", + "24", + "27", + "28", + "32", + "44", + "52", + "53", + "75", + "76", + "84", + "93", + "94", + "977", + "978", + "01", + "02", + "03", + "04", + "05", + "06", + "00", + ], + }, + "repetition_voie": { + "bsonType": "string", + "description": "Indice de répétition du numéro de voie", + "enum": [ + "B", + "T", + "Q", + "C", + ], + }, + "voie": { + "bsonType": "string", + "description": "Nom de voie", + }, + }, + }, + { + "bsonType": "null", + }, + ], + }, + "courriel": { + "bsonType": [ + "string", + "null", + ], + }, + "meme_adresse": { + "bsonType": [ + "bool", + "null", + ], + }, + "nom": { + "bsonType": [ + "string", + "null", + ], + }, + "pcs": { + "anyOf": [ + { + "bsonType": "number", + "description": "Nomenclatures des professions et catégories socioprofessionnelles", + "enum": [ + 10, + 21, + 22, + 23, + 31, + 33, + 34, + 37, + 38, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 52, + 53, + 54, + 55, + 56, + 61, + 66, + 69, + 71, + 72, + 73, + 76, + 81, + 82, + 99, + ], + }, + { + "bsonType": "null", + }, + ], + }, + "prenom": { + "bsonType": [ + "string", + "null", + ], + }, + "telephone": { + "anyOf": [ + { + "bsonType": "string", + "description": "Dans le cas d'un numéro français, il n'est pas + nécessaire de saisir le "0" car l'indicateur pays est + pré-renseigné. + Il doit contenir 9 chiffres après l'indicatif.", + "pattern": "^([+])?(\\d{7,12})$", + }, + { + "bsonType": "null", + }, + ], + }, + }, + }, + { + "bsonType": "null", + }, + ], + }, + "responsable_mail1": { + "bsonType": [ + "string", + "null", + ], + }, + "responsable_mail2": { + "bsonType": [ + "string", + "null", + ], + }, + "rqth": { + "bsonType": [ + "bool", + "null", + ], + }, + "sexe": { + "anyOf": [ + { + "bsonType": "string", + "description": "Sexe de l'apprenant (M: Homme, F: Femme)", + "enum": [ + "M", + "F", + ], + }, + { + "bsonType": "null", + }, + ], + }, + "situation_avant_contrat": { + "anyOf": [ + { + "bsonType": "number", + "description": "Situation de l'apprenant avant le contrat", + "enum": [ + 11, + 12, + 21, + 31, + 41, + 51, + 52, + 53, + 54, + 90, + 99, + ], + }, + { + "bsonType": "null", + }, + ], + }, + "telephone": { + "anyOf": [ + { + "bsonType": "string", + "description": "Téléphone de l'apprenant", + "pattern": "^([+])?(\\d{7,12})$", + }, + { + "bsonType": "null", + }, + ], + }, + "type_cfa": { + "anyOf": [ + { + "bsonType": "string", + "description": "Type de CFA", + "enum": [ + "01", + "02", + "03", + "04", + "05", + "06", + "07", + "08", + "09", + "10", + ], + }, + { + "bsonType": "null", + }, + ], + }, + }, + }, + "contrats": { + "bsonType": "array", + "items": { + "additionalProperties": false, + "bsonType": "object", + "properties": { + "adresse": { + "anyOf": [ + { + "additionalProperties": false, + "bsonType": "object", + "properties": { + "academie": { + "bsonType": "string", + "enum": [ + "1", + "2", + "3", + "4", + "6", + "7", + "8", + "9", + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "20", + "22", + "23", + "24", + "25", + "27", + "28", + "31", + "32", + "33", + "43", + "44", + "70", + "77", + "78", + ], + }, + "bassinEmploi": { + "bsonType": "string", + "description": "Code Bassin d'emploi", + }, + "code_insee": { + "bsonType": "string", + "description": "Le code insee doit contenir 5 caractères", + "pattern": "^[0-9]{1}[0-9A-Z]{1}[0-9]{3}$", + }, + "code_postal": { + "bsonType": "string", + "description": "Le code postal doit contenir 5 caractères", + "pattern": "^[0-9]{5}$", + }, + "commune": { + "bsonType": "string", + "description": "Commune", + "maxLength": 80, + }, + "complement": { + "bsonType": "string", + "description": "Complément d'adresse", + }, + "complete": { + "bsonType": "string", + "description": "Adresse complète", + }, + "departement": { + "bsonType": "string", + "enum": [ + "10", + "11", + "12", + "13", + "14", + "15", + "16", + "17", + "18", + "19", + "21", + "22", + "23", + "24", + "25", + "26", + "27", + "28", + "29", + "30", + "31", + "32", + "33", + "34", + "35", + "36", + "37", + "38", + "39", + "40", + "41", + "42", + "43", + "44", + "45", + "46", + "47", + "48", + "49", + "50", + "51", + "52", + "53", + "54", + "55", + "56", + "57", + "58", + "59", + "60", + "61", + "62", + "63", + "64", + "65", + "66", + "67", + "68", + "69", + "70", + "71", + "72", + "73", + "74", + "75", + "76", + "77", + "78", + "79", + "80", + "81", + "82", + "83", + "84", + "85", + "86", + "87", + "88", + "89", + "90", + "91", + "92", + "93", + "94", + "95", + "971", + "972", + "973", + "974", + "975", + "976", + "977", + "978", + "984", + "986", + "987", + "988", + "989", + "01", + "02", + "03", + "04", + "05", + "06", + "07", + "08", + "09", + "2A", + "2B", + ], + }, + "numero": { + "bsonType": "int", + "description": "N° de la voie", + }, + "pays": { + "bsonType": "string", + "description": "Pays", + "enum": [ + "AF", + "ZA", + "AL", + "DZ", + "DE", + "AD", + "AO", + "AG", + "SA", + "AR", + "AM", + "AU", + "AT", + "AZ", + "BS", + "BH", + "BD", + "BB", + "BE", + "BZ", + "BJ", + "BT", + "BY", + "MM", + "BO", + "BQ", + "BA", + "BW", + "BR", + "BN", + "BG", + "BF", + "BI", + "KH", + "CM", + "CA", + "CV", + "CF", + "CL", + "CN", + "CY", + "CO", + "KM", + "CG", + "CD", + "KR", + "KP", + "CR", + "CI", + "HR", + "CU", + "CW", + "DK", + "DJ", + "DO", + "DM", + "EG", + "SV", + "AE", + "EC", + "ER", + "ES", + "EE", + "SZ", + "US", + "ET", + "MK", + "FJ", + "FI", + "FR", + "GA", + "GM", + "GE", + "GH", + "GR", + "GD", + "GT", + "GN", + "GQ", + "GW", + "GY", + "HT", + "HN", + "HU", + "IN", + "ID", + "IR", + "IQ", + "IE", + "IS", + "IL", + "IT", + "JM", + "JP", + "JO", + "KZ", + "KE", + "KG", + "KI", + "XK", + "KW", + "LA", + "LS", + "LV", + "LB", + "LR", + "LY", + "LI", + "LT", + "LU", + "MG", + "MY", + "MW", + "MV", + "ML", + "MT", + "MA", + "MH", + "MU", + "MR", + "MX", + "FM", + "MD", + "MC", + "MN", + "ME", + "MZ", + "NA", + "NR", + "NP", + "NI", + "NE", + "NG", + "NO", + "NZ", + "OM", + "UG", + "UZ", + "PK", + "PW", + "PS", + "PA", + "PG", + "PY", + "NL", + "PE", + "PH", + "PL", + "PT", + "QA", + "RO", + "GB", + "RU", + "RW", + "KN", + "SM", + "SX", + "VC", + "LC", + "SB", + "WS", + "ST", + "SN", + "RS", + "SC", + "SL", + "SG", + "SK", + "SI", + "SO", + "SD", + "SS", + "LK", + "SE", + "CH", + "SR", + "SY", + "TJ", + "TZ", + "TD", + "CZ", + "TH", + "TL", + "TG", + "TO", + "TT", + "TN", + "TM", + "TR", + "TV", + "UA", + "UY", + "VU", + "VA", + "VE", + "VN", + "YE", + "ZM", + "ZW", + ], + }, + "region": { + "bsonType": "string", + "enum": [ + "11", + "24", + "27", + "28", + "32", + "44", + "52", + "53", + "75", + "76", + "84", + "93", + "94", + "977", + "978", + "01", + "02", + "03", + "04", + "05", + "06", + "00", + ], + }, + "repetition_voie": { + "bsonType": "string", + "description": "Indice de répétition du numéro de voie", + "enum": [ + "B", + "T", + "Q", + "C", + ], + }, + "voie": { + "bsonType": "string", + "description": "Nom de voie", + }, + }, + }, + { + "bsonType": "null", + }, + ], + }, + "cause_rupture": { + "bsonType": [ + "string", + "null", + ], + }, + "date_debut": { + "bsonType": "date", + "description": "Date de début du contrat", + }, + "date_fin": { + "anyOf": [ + { + "bsonType": "date", + "description": "Date de fin du contrat", + }, + { + "bsonType": "null", + }, + ], + }, + "date_rupture": { + "anyOf": [ + { + "bsonType": "date", + "description": "Date de rupture du contrat", + }, + { + "bsonType": "null", + }, + ], + }, + "denomination": { + "bsonType": [ + "string", + "null", + ], + }, + "naf": { + "anyOf": [ + { + "bsonType": "string", + "description": "Le Code NAF est composé de 4 chiffres et 1 lettre. Il est délivré par l'INSEE.[Informations sur le Code NAF.](https://www.economie.gouv.fr/entreprises/activite-entreprise-code-ape-code-naf)", + "pattern": "^[0-9]{2}\\.?[0-9]{0,2}[a-zA-Z]{0,1}$", + }, + { + "bsonType": "null", + }, + ], + }, + "nombre_de_salaries": { + "anyOf": [ + { + "bsonType": "int", + "description": "L'effectif salarié rempli automatiquement correspond à l'estimation de la base Entreprises de l'INSEE.
L'effectif renseigné est celui de l’entreprise dans sa globalité (et non seulement l’effectif de l’établissement d’exécution du contrat).", + }, + { + "bsonType": "null", + }, + ], + }, + "siret": { + "anyOf": [ + { + "bsonType": "string", + "description": "N° SIRET de l'employeur", + "pattern": "^[0-9]{14}$", + }, + { + "bsonType": "null", + }, + ], + }, + "type_employeur": { + "anyOf": [ + { + "bsonType": "number", + "description": "Le type d'employeur doit être en adéquation avec son statut juridique.", + "enum": [ + 11, + 12, + 13, + 14, + 15, + 16, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + ], + }, + { + "bsonType": "null", + }, + ], + }, + }, + }, + }, + "formation": { + "additionalProperties": false, + "bsonType": "object", + "properties": { + "annee": { + "anyOf": [ + { + "bsonType": "int", + "description": "Numéro de l'année dans la formation (promo)", + }, + { + "bsonType": "null", + }, + ], + }, + "cause_exclusion": { + "bsonType": [ + "string", + "null", + ], + }, + "cfd": { + "anyOf": [ + { + "bsonType": "string", + "description": "Code CFD de la formation", + "pattern": "^[A-Z0-9]{8}$", + }, + { + "bsonType": "null", + }, + ], + }, + "date_entree": { + "anyOf": [ + { + "bsonType": "date", + "description": "Date d'entrée en formation", + }, + { + "bsonType": "null", + }, + ], + }, + "date_exclusion": { + "anyOf": [ + { + "bsonType": "date", + "description": "Date d'exclusion", + }, + { + "bsonType": "null", + }, + ], + }, + "date_fin": { + "anyOf": [ + { + "bsonType": "date", + "description": "Date de fin de la formation", + }, + { + "bsonType": "null", + }, + ], + }, + "date_inscription": { + "anyOf": [ + { + "bsonType": "date", + "description": "Date d'inscription", + }, + { + "bsonType": "null", + }, + ], + }, + "date_obtention_diplome": { + "anyOf": [ + { + "bsonType": "date", + "description": "Date d'obtention du diplôme", + }, + { + "bsonType": "null", + }, + ], + }, + "duree_formation_relle": { + "anyOf": [ + { + "bsonType": "int", + "description": "Durée réelle de la formation en mois", + }, + { + "bsonType": "null", + }, + ], + }, + "duree_theorique": { + "anyOf": [ + { + "bsonType": "int", + "description": "Durée théorique de la formation en année", + }, + { + "bsonType": "null", + }, + ], + }, + "duree_theorique_mois": { + "anyOf": [ + { + "bsonType": "int", + "description": "Durée théorique de la formation en mois", + }, + { + "bsonType": "null", + }, + ], + }, + "formation_id": { + "anyOf": [ + { + "bsonType": "objectId", + "description": "ID de la formation", + }, + { + "bsonType": "null", + }, + ], + }, + "formation_presentielle": { + "bsonType": [ + "bool", + "null", + ], + }, + "libelle_court": { + "bsonType": [ + "string", + "null", + ], + }, + "libelle_long": { + "bsonType": [ + "string", + "null", + ], + }, + "niveau": { + "anyOf": [ + { + "anyOf": [ + { + "not": {}, + }, + { + "bsonType": [ + "string", + "null", + ], + }, + ], + }, + { + "bsonType": "null", + }, + ], + }, + "niveau_libelle": { + "anyOf": [ + { + "anyOf": [ + { + "not": {}, + }, + { + "bsonType": [ + "string", + "null", + ], + }, + ], + }, + { + "bsonType": "null", + }, + ], + }, + "obtention_diplome": { + "bsonType": [ + "bool", + "null", + ], + }, + "periode": { + "anyOf": [ + { + "bsonType": "array", + "description": "Période de la formation, en année (peut être sur plusieurs années)", + "items": { + "bsonType": "int", + }, + }, + { + "bsonType": "null", + }, + ], + }, + "referent_handicap": { + "anyOf": [ + { + "additionalProperties": false, + "bsonType": "object", + "properties": { + "email": { + "bsonType": [ + "string", + "null", + ], + }, + "nom": { + "bsonType": [ + "string", + "null", + ], + }, + "prenom": { + "bsonType": [ + "string", + "null", + ], + }, + }, + }, + { + "bsonType": "null", + }, + ], + }, + "rncp": { + "anyOf": [ + { + "bsonType": "string", + "description": "Code RNCP de la formation à laquelle l'apprenant est inscrit", + "pattern": "^(RNCP)?[0-9]{2,5}$", + }, + { + "bsonType": "null", + }, + ], + }, + }, + }, + "organisme": { + "additionalProperties": false, + "bsonType": "object", + "properties": { + "organisme_formateur_id": { + "bsonType": "string", + }, + "organisme_lieu_id": { + "bsonType": "string", + }, + "organisme_responsable_id": { + "bsonType": "string", + }, + "type_cfa": { + "bsonType": "string", + "description": "Type de CFA", + "pattern": "^(01|02|03|04|05|06|07|08|09|10)$", + }, + }, + }, + }, + }, + { + "bsonType": "null", + }, + ], + }, "email": { "bsonType": "string", "description": "Email utilisateur",