Skip to content

Commit

Permalink
Merge branch 'main' into securisation-backoffice-cfa
Browse files Browse the repository at this point in the history
  • Loading branch information
remy-auricoste committed Nov 6, 2023
2 parents a77cbd1 + a1ba974 commit 80be907
Show file tree
Hide file tree
Showing 26 changed files with 141 additions and 112 deletions.
4 changes: 2 additions & 2 deletions .infra/files/configs/mongodb/seed.gpg
Git LFS file not shown
2 changes: 1 addition & 1 deletion .talismanrc
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fileignoreconfig:
- filename: .infra/files/configs/mailpit/auth
checksum: 0c02db6c367747bfd696e8c93ed78c456fe311452e7a4ee1d7d5acc88f3b2189
- filename: .infra/files/configs/mongodb/seed.gpg
checksum: 3cb836a5c356c64ac6634c8aeb03b9737950a66ed61d9ae8f6b1528ad7b17434
checksum: e09bc952da0dbeb33331dc317980e6537dc4d37674ca08748246d4d093b82294
- filename: .infra/vault/vault.yml
checksum: 1a62fbc5e3e877b5241d59c61fda05a61b6c8bb4fb7f5662f2f1bc44c288782b
- filename: server/.env.test
Expand Down
6 changes: 6 additions & 0 deletions server/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,12 @@ program.command("migrations:status").description("Check migrations status").acti

program.command("migrations:create").description("Run migrations create").requiredOption("-d, --description <string>", "description").action(createJobAction("migrations:create"))

// Temporaire, one shot à executer en recette et prod
program
.command("recruiters:set-missing-job-start-date")
.description("Récupération des geo_coordinates manquants dans la collection Recruiters")
.option("-q, --queued", "Run job asynchronously", false)
.action(createJobAction("recruiters:set-missing-job-start-date"))
// Temporaire, one shot à executer en recette et prod
program
.command("recruiters:get-missing-geocoordinates")
Expand Down
11 changes: 1 addition & 10 deletions server/src/http/controllers/jobs/jobs.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ import { getPeJobFromId } from "../../../services/pejob.service"
import { getFicheMetierRomeV3FromDB } from "../../../services/rome.service"
import { Server } from "../../server"

import { createDelegationSchema, createEstablishmentSchema, getEstablishmentEntitySchema, updateJobSchema } from "./jobs.validators"

const config = {
rateLimit: {
max: 5,
Expand All @@ -45,11 +43,9 @@ export default (server: Server) => {
schema: zRoutes.get["/v1/jobs/establishment"],
config,
onRequest: server.auth(zRoutes.get["/v1/jobs/establishment"]),
// TODO: AttachValidation Error ?
},
async (req, res) => {
const { establishment_siret, email } = req.query
await getEstablishmentEntitySchema.validateAsync({ establishment_siret, email }, { abortEarly: false })

const establishment = await Recruiter.findOne({ establishment_siret, email }).lean()

Expand Down Expand Up @@ -95,8 +91,6 @@ export default (server: Server) => {
},
async (req, res) => {
const { body } = req
// Validate establishment parameters
await createEstablishmentSchema.validateAsync(body, { abortEarly: false })

const { first_name, last_name, phone, email, origin, idcc, establishment_siret } = body
const user = getUserFromRequest(req, zRoutes.post["/v1/jobs/establishment"]).value
Expand Down Expand Up @@ -161,6 +155,7 @@ export default (server: Server) => {
job_level_label: body.job_level_label,
job_start_date: new Date(body.job_start_date),
job_description: body.job_description,
job_employer_description: body.job_employer_description,
job_creation_date: dayjs().toDate(),
job_expiration_date: addExpirationPeriod(dayjs()).toDate(),
job_status: JOB_STATUS.ACTIVE,
Expand Down Expand Up @@ -196,8 +191,6 @@ export default (server: Server) => {
return res.status(400).send({ error: true, message: "Job does not exists" })
}

await updateJobSchema.validateAsync(req.body, { abortEarly: false })

const updatedRecruiter = await patchOffre(jobId, req.body)

return res.status(200).send(updatedRecruiter)
Expand Down Expand Up @@ -260,8 +253,6 @@ export default (server: Server) => {
return res.status(400).send({ error: true, message: "Job does not exists" })
}

await createDelegationSchema.validateAsync(req.body)

const updatedRecruiter = await createJobDelegations({ jobId: jobId.toString(), etablissementCatalogueIds: req.body.establishmentIds })

res.status(200)
Expand Down
61 changes: 0 additions & 61 deletions server/src/http/controllers/jobs/jobs.validators.ts

This file was deleted.

2 changes: 1 addition & 1 deletion server/src/http/routes/appointmentRequest.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export default (server: Server) => {
const [emailCandidat, emailCfa] = await Promise.all([
mailer.sendEmail({
to: user.email,
subject: `Le centre de formation a bien reçu votre demande de contact !`,
subject: `Votre demande de RDV auprès de ${eligibleTrainingsForAppointment.etablissement_formateur_raison_sociale}`,
template: getStaticFilePath("./templates/mail-candidat-confirmation-rdv.mjml.ejs"),
data: mailData,
}),
Expand Down
12 changes: 2 additions & 10 deletions server/src/http/routes/etablissementRecruteur.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,9 @@ export default (server: Server) => {
}

const result = await getEntrepriseDataFromSiret({ siret, cfa_delegated_siret })

if ("error" in result) {
switch (result.errorCode) {
case BusinessErrorCodes.IS_CFA: {
throw Boom.badRequest(result.message, {
isCfa: true,
})
}
default: {
throw Boom.badRequest(result.message)
}
}
throw Boom.badRequest(result.message, result)
} else {
return res.status(200).send(result)
}
Expand Down
3 changes: 3 additions & 0 deletions server/src/jobs/jobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { removeIsDelegatedFromJobs } from "./lba_recruteur/formulaire/misc/remov
import { removeVersionKeyFromAllCollections } from "./lba_recruteur/formulaire/misc/removeVersionKeyFromAllCollections"
import { repiseGeocoordinates } from "./lba_recruteur/formulaire/misc/repriseGeocoordinates"
import { updateAddressDetailOnRecruitersCollection } from "./lba_recruteur/formulaire/misc/updateAddressDetailOnRecruitersCollection"
import { updateMissingStartDate } from "./lba_recruteur/formulaire/misc/updateMissingStartDate"
import { relanceFormulaire } from "./lba_recruteur/formulaire/relanceFormulaire"
import { generateIndexes } from "./lba_recruteur/indexes/generateIndexes"
import { relanceOpco } from "./lba_recruteur/opco/relanceOpco"
Expand Down Expand Up @@ -189,6 +190,8 @@ export async function runJob(job: IInternalJobsCronTask | IInternalJobsSimple):
return CronsMap[job.name].handler()
}
switch (job.name) {
case "recruiters:set-missing-job-start-date":
return updateMissingStartDate()
case "recruiters:get-missing-geocoordinates":
return repiseGeocoordinates()
case "recruiters:get-missing-address-detail":
Expand Down
3 changes: 2 additions & 1 deletion server/src/jobs/lba_recruteur/formulaire/misc/exportPE.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,11 +191,12 @@ export const exportPE = async (): Promise<void> => {
try {
const csvPath = new URL("./exportPE.csv", import.meta.url)
const buffer: any[] = []
const threshold = dayjs().subtract(30, "days").toDate()

// Retrieve only active offers
const offres: any[] = await db
.collection("jobs")
.find({ job_status: JOB_STATUS.ACTIVE, recruiterStatus: RECRUITER_STATUS.ACTIF, geo_coordinates: { $nin: ["NOT FOUND", null] } })
.find({ job_status: JOB_STATUS.ACTIVE, recruiterStatus: RECRUITER_STATUS.ACTIF, geo_coordinates: { $nin: ["NOT FOUND", null] }, job_update_date: { $gte: threshold } })
.toArray()

logger.info(`get info from ${offres.length} offers...`)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { logger } from "../../../../common/logger"
import { Recruiter } from "../../../../common/model/index"
import { asyncForEach } from "../../../../common/utils/asyncUtils"

export const updateMissingStartDate = async () => {
logger.info("Start update missing job_start_date")
const forms = await Recruiter.find({ "jobs.job_start_date": null })
await asyncForEach(forms, async (form) => {
await asyncForEach(form.jobs, async (job) => {
if (job.job_start_date === null) {
if (job.job_creation_date) {
job.job_start_date = job.job_creation_date
}
}
})
await form.save({ timestamps: false })
})
logger.info("End update missing job_start_date")
}
8 changes: 4 additions & 4 deletions server/src/services/application.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,18 +193,18 @@ export const sendApplication = async ({
encryptedId,
})

const searched_for_job_label = query.searched_for_job_label || ""

const buildTopic = (aCompanyType, aJobTitle) => {
let res = "Candidature"
if (aCompanyType === "matcha") {
res = `Candidature en alternance - ${aJobTitle}`
} else {
res = `Candidature spontanée en alternance`
res = `Candidature spontanée en alternance ${searched_for_job_label ? "- " + searched_for_job_label : ""}`
}
return res
}

const searched_for_job_label = query.searched_for_job_label || ""

// Sends acknowledge email to "candidate" and application email to "company"
const [emailCandidat, emailCompany] = await Promise.all([
mailer.sendEmail({
Expand Down Expand Up @@ -339,7 +339,7 @@ interface IApplicationTemplates {
}
/**
* @description Return template file path for given type
* @param {string} type
* @param {string} applicationType
* @return {IApplicationTemplates}
*/
const getEmailTemplates = (applicationType: string): IApplicationTemplates => {
Expand Down
1 change: 1 addition & 0 deletions server/src/services/constant.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,5 @@ export type IRole = IRoles[keyof IRoles]
export enum BusinessErrorCodes {
IS_CFA = "IS_CFA",
ALREADY_EXISTS = "ALREADY_EXISTS",
CLOSED = "CLOSED",
}
7 changes: 5 additions & 2 deletions server/src/services/etablissement.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -535,15 +535,18 @@ export const validateCreationEntrepriseFromCfa = async ({ siret, cfa_delegated_s

export const getEntrepriseDataFromSiret = async ({ siret, cfa_delegated_siret }: { siret: string; cfa_delegated_siret?: string }) => {
const result = await getEtablissementFromGouv(siret)

if (!result) {
return errorFactory("Le numéro siret est invalide.")
}

const { etat_administratif, activite_principale } = result.data

if (etat_administratif === "F") {
return errorFactory("Cette entreprise est considérée comme fermée.")
return errorFactory("Cette entreprise est considérée comme fermée.", BusinessErrorCodes.CLOSED)
}
// Check if a CFA already has the company as partenaire
if (!cfa_delegated_siret) {
if (cfa_delegated_siret === "undefined") {
// Allow cfa to add themselves as a company
if (activite_principale.code.startsWith("85")) {
return errorFactory("Le numéro siret n'est pas référencé comme une entreprise.", BusinessErrorCodes.IS_CFA)
Expand Down
2 changes: 2 additions & 0 deletions shared/constants/recruteur.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export const TRAINING_RYTHM = {
"1S1S": "1 semaine / 1 semaine",
"2S3S": "2 semaines / 3 semaines",
"6S6S": "6 semaines / 6 semaines",
NONRENSEIGNE: "Non renseigné",
}

export const ROLES = {
Expand All @@ -100,4 +101,5 @@ export const ROLES = {
export enum BusinessErrorCodes {
IS_CFA = "IS_CFA",
ALREADY_EXISTS = "ALREADY_EXISTS",
CLOSED = "CLOSED",
}
29 changes: 29 additions & 0 deletions shared/helpers/dayjs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import dayjs from "dayjs"
// eslint-disable-next-line import/extensions
import "dayjs/locale/fr.js"
import advancedFormat from "dayjs/plugin/advancedFormat.js"
import customParseFormat from "dayjs/plugin/customParseFormat.js"
import duration from "dayjs/plugin/duration.js"
import isBetween from "dayjs/plugin/isBetween.js"
import isSameOrAfter from "dayjs/plugin/isSameOrAfter.js"
import isSameOrBefore from "dayjs/plugin/isSameOrBefore.js"
import isYesterday from "dayjs/plugin/isYesterday.js"
import localizedFormat from "dayjs/plugin/localizedFormat.js"
import timezone from "dayjs/plugin/timezone.js"
import utc from "dayjs/plugin/utc.js"

dayjs.locale("fr")
dayjs.extend(utc)
dayjs.extend(duration)
dayjs.extend(timezone)
dayjs.extend(isSameOrBefore)
dayjs.extend(isSameOrAfter)
dayjs.extend(isBetween)
dayjs.extend(customParseFormat)
dayjs.extend(advancedFormat)
dayjs.extend(isYesterday)
dayjs.extend(localizedFormat)

export type TDayjs = dayjs.Dayjs

export default dayjs
Loading

0 comments on commit 80be907

Please sign in to comment.