Skip to content

Commit

Permalink
Sosynpl[premieroctet#120]: Fixed mongo request filters, missing mobil…
Browse files Browse the repository at this point in the history
…ity filter
  • Loading branch information
SeghirOumo committed Jul 15, 2024
1 parent 7298a3f commit be6fa63
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 73 deletions.
4 changes: 2 additions & 2 deletions backend/web/server/plugins/sosynpl/consts.js
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ const DEFAULT_SEARCH_RADIUS=20

module.exports={
SOSYNPL, ROLES, COMPANY_SIZE, WORK_MODE, WORK_MODE_REMOTE, WORK_MODE_REMOTE_SITE, WORK_MODE_SITE, WORK_DURATION, WORK_DURATION_LESS_1_MONTH, WORK_DURATION_MORE_6_MONTH, WORK_DURATION__1_TO_6_MONTHS, VALID_STATUS, VALID_STATUS_PENDING, SOURCE,
DISCRIMINATOR_KEY, DISC_CUSTOMER, DISC_FREELANCE, DISC_ADMIN, DISC_CUSTOMER_FREELANCE, EXPERIENCE, ROLE_CUSTOMER, ROLE_FREELANCE, ROLE_ADMIN,
DISCRIMINATOR_KEY, DISC_CUSTOMER, DISC_FREELANCE, DISC_ADMIN, DISC_CUSTOMER_FREELANCE, EXPERIENCE, EXPERIENCE_EXPERIMENTED, EXPERIENCE_EXPERT, EXPERIENCE_JUNIOR, EXPERIENCE_SENIOR, ROLE_CUSTOMER, ROLE_FREELANCE, ROLE_ADMIN,
LEGAL_STATUS, DEACTIVATION_REASON, SUSPEND_REASON, ACTIVITY_STATE, ACTIVITY_STATE_ACTIVE, ACTIVITY_STATE_STANDBY,
ACTIVITY_STATE_SUSPENDED, ACTIVITY_STATE_DISABLED, MOBILITY, MOBILITY_CITY, MOBILITY_FRANCE, MOBILITY_REGIONS,
AVAILABILITY, AVAILABILITY_UNDEFINED, AVAILABILITY_UNDEFINED, AVAILABILITY_ON, AVAILABILITY_OFF, SS_PILAR,
Expand All @@ -421,6 +421,6 @@ module.exports={
SOSYNPL_COMMISSION_VAT_RATE, APPLICATION_REFUSE_REASON,REFUSE_REASON_CANCELED, REFUSE_REASON_PROVIDED, APPLICATION_STATUS_ACCEPTED,
MISSION_STATUS, MISSION_STATUS_TO_COME, MISSION_STATUS_CURRENT, MISSION_STATUS_FREELANCE_FINISHED, MISSION_STATUS_CUSTOMER_FINISHED, MISSION_STATUS_CLOSED,
REPORT_STATUS, REPORT_STATUS_DRAFT, REPORT_STATUS_DISPUTE, REPORT_STATUS_SENT, REPORT_STATUS_PAID, REPORT_STATUS_ACCEPTED,
SEARCH_MODE, DEFAULT_SEARCH_RADIUS, DURATION_UNIT_DAYS, DURATION_FILTERS
SEARCH_MODE, DEFAULT_SEARCH_RADIUS, DURATION_UNIT_DAYS, DURATION_FILTERS, DURATION_MONTH,SOURCE_RECOMMANDATION,
}

60 changes: 33 additions & 27 deletions backend/web/server/plugins/sosynpl/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,31 @@
const lodash=require('lodash')
const CustomerFreelance = require("../../models/CustomerFreelance")
const User = require("../../models/User")
const { ROLE_FREELANCE, DEFAULT_SEARCH_RADIUS, AVAILABILITY_ON, ANNOUNCE_STATUS_ACTIVE, DURATION_FILTERS, WORK_MODE, WORK_MODE_SITE, WORK_MODE_REMOTE, WORK_MODE_REMOTE_SITE, WORK_DURATION_LESS_1_MONTH, WORK_DURATION_MORE_6_MONTH, WORK_DURATION__1_TO_6_MONTHS, MOBILITY_FRANCE, MOBILITY_NONE, DURATION_UNIT_DAYS } = require("./consts")
const { ROLE_FREELANCE, DEFAULT_SEARCH_RADIUS, AVAILABILITY_ON, ANNOUNCE_STATUS_ACTIVE, DURATION_FILTERS, WORK_MODE, WORK_MODE_SITE, WORK_MODE_REMOTE, WORK_MODE_REMOTE_SITE, WORK_DURATION_LESS_1_MONTH, WORK_DURATION_MORE_6_MONTH, WORK_DURATION__1_TO_6_MONTHS, MOBILITY_FRANCE, MOBILITY_NONE, DURATION_UNIT_DAYS, MOBILITY_CITY, MOBILITY_REGIONS } = require("./consts")
const { computeDistanceKm } = require('../../../utils/functions')
const Announce = require('../../models/Announce')
const { REGIONS_FULL } = require('../../../utils/consts')

const computeSuggestedFreelances = async (userId, params, data) => {
// if (!data.job || !data.start_date) {
// console.log("missing attributes on announce")
// return []
// }
if (!data.job || !data.start_date) {
console.log("missing attributes on announce")
return []
}

const MAP_WORKMODE = {
0: 'WORK_MODE_SITE',
5: 'WORK_MODE_REMOTE',
0: WORK_MODE_SITE,
5: WORK_MODE_REMOTE,
}

const workMode = MAP_WORKMODE[data.homework_days] || 'WORK_MODE_REMOTE_SITE'
const workMode = MAP_WORKMODE[data.homework_days] || WORK_MODE_REMOTE_SITE

const durationDays = data.duration*DURATION_UNIT_DAYS[data.duration_unit]
const workDuration =
durationDays < 30
? 'WORK_DURATION_LESS_1_MONTH'
? WORK_DURATION_LESS_1_MONTH
: durationDays > 180
? 'WORK_DURATION_MORE_6_MONTH'
: 'WORK_DURATION__1_TO_6_MONTHS'
? WORK_DURATION_MORE_6_MONTH
: WORK_DURATION__1_TO_6_MONTHS

const getRegionFromZipcode = (zipcode) => {
const departmentCode = zipcode.toString().substring(0, 2)
Expand All @@ -43,31 +43,39 @@ const computeSuggestedFreelances = async (userId, params, data) => {
if (data.homework_days === 5) {
return {}
}
if (data.mobility === 'MOBILITY_FRANCE') {
return { mobility: 'MOBILITY_FRANCE' }
if (data.mobility === MOBILITY_FRANCE) {
return { mobility: MOBILITY_FRANCE }
}
if (data.mobility === 'MOBILITY_NONE') {
const regionKey = getRegionFromZipcode(data.city.zipcode)
if (data.mobility === MOBILITY_NONE) {
const regionKey = getRegionFromZipcode(data.city.zip_code)
return {
$or: [
{
mobility: 'MOBILITY_CITY',
mobility: MOBILITY_CITY,
$expr: {
$lt: [
computeDistanceKm(data.city, '$mobility_city'),
computeDistanceKm(data.city, "$mobility_city"),
'$mobility_city_distance',
],
},
},
{
mobility: 'MOBILITY_REGIONS',
mobility: MOBILITY_REGIONS,
mobility_regions: { $in: [regionKey] },
},
],
}
}
return {}
return true
}

const availabilityFilter = {
$or: [
{ availability: AVAILABILITY_ON },
{ available_from: { $lte: data.start_date } },
],
}

const filter = {
main_job: data.job,
work_sector: { $in: data.sectors },
Expand All @@ -77,17 +85,15 @@ const computeSuggestedFreelances = async (userId, params, data) => {
main_experience: { $in: data.experience },
work_mode: workMode,
work_duration: workDuration,
// ...mobilityFilter(),
// $or: [
// { available: true },
// { available_from: { $lte: data.start_date } },
// ],
$and:[
mobilityFilter(),
availabilityFilter
],
}

return CustomerFreelance.find(filter)
const suggestions = await CustomerFreelance.find(filter)
return suggestions
}


const PROFILE_TEXT_SEARCH_FIELDS=['position', 'description', 'motivation']

const searchFreelances = async (userId, params, data, fields) => {
Expand Down
110 changes: 67 additions & 43 deletions backend/web/tests/sosynpl/search.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const mongoose = require('mongoose')
const moment = require('moment')
const { faker } = require('@faker-js/faker')
const { MONGOOSE_OPTIONS, loadFromDb } = require('../../server/utils/database')
const Announce = require('../../server/models/Announce')
const Job = require('../../server/models/Job')
Expand All @@ -11,14 +10,17 @@ const LanguageLevel = require('../../server/models/LanguageLevel')
const CustomerFreelance = require('../../server/models/CustomerFreelance')
const SoftSkill = require('../../server/models/SoftSkill')
const JobFile = require('../../server/models/JobFile')
const { LANGUAGE_LEVEL_ADVANCED } = require('../../utils/consts')
const { EXPERIENCE_EXPERT, DURATION_MONTH, MOBILITY_FRANCE, SOURCE_RECOMMANDATION, WORK_MODE_REMOTE_SITE, WORK_DURATION__1_TO_6_MONTHS, AVAILABILITY_ON, AVAILABILITY_OFF, MOBILITY_CITY, MOBILITY_NONE } = require('../../server/plugins/sosynpl/consts')
const { computeDistanceKm } = require('../../utils/functions')
require('../../server/plugins/sosynpl/functions')
require('../../server/plugins/sosynpl/announce')
require('../../server/models/JobFile')
require('../../server/models/Application')


describe('Search', () => {
let job, sector, expertise1, expertise2, expertise3, software, language, announce, customerFreelance
let job, sector, expertise1, expertise2, expertise3, software, language, announce, customerFreelance, rouen, msa, dieppe
let softSkillComm, softSkillConflict, softSkillTeamWork

beforeAll(async () => {
Expand All @@ -32,72 +34,95 @@ describe('Search', () => {
expertise2 = await Expertise.create({ name: 'Java' })
expertise3 = await Expertise.create({ name: 'Python' })
software = await Software.create({ name: 'VS Code' })
language = await LanguageLevel.create({ language: 'fr', level: 'LANGUAGE_LEVEL_ADVANCED' })
language = await LanguageLevel.create({ language: 'fr', level: LANGUAGE_LEVEL_ADVANCED })
softSkillComm = await SoftSkill.create({ name: 'Communication', value: 'SOFT_SKILL_COMM' })
softSkillTeamWork = await SoftSkill.create({ name: 'TeamWork', value: 'SOFT_SKILL_TEAMWORK'})
softSkillConflict = await SoftSkill.create({ name: 'Conflict', value: 'SOFT_SKILL_CONFLICT'})

rouen = {
address: 'Place du Vieux-Marché',
city: 'Rouen',
zip_code: '76000',
country: 'France',
latitude: 49.4431,
longitude: 1.0993,
}
msa = {
address: 'Place Colbert',
city: 'Mont Saint Aignan',
zip_code: '76130',
country: 'France',
latitude: 49.4655,
longitude: 1.0877,
}
dieppe = {
address: 'Place Nationale',
city: 'Dieppe',
zip_code: '76200',
country: 'France',
latitude: 49.9225,
longitude: 1.0781,
}
announce = await Announce.create({
user: new mongoose.Types.ObjectId(),
job: job._id,
title: faker.name.jobTitle(),
experience: ['EXPERIENCE_EXPERT'],
start_date: moment(),
duration: faker.datatype.number({ min: 1, max: 12 }),
duration_unit: 'DURATION_MONTH',
title: 'Senior Developer',
experience: [EXPERIENCE_EXPERT],
start_date: new Date(2024, 6, 20),
duration: 3,
duration_unit: DURATION_MONTH,
sectors: [sector._id],
city: {
address: faker.address.streetAddress(),
city: faker.address.city(),
zip_code: faker.address.zipCode(),
country: faker.address.country()
},
homework_days: faker.datatype.number({ min: 0, max: 5 }),
mobility: 'MOBILITY_FRANCE',
mobility_days_per_month: faker.datatype.number({ min: 1, max: 30 }),
budget: faker.datatype.number({ min: 1000, max: 10000 }),
budget_hidden: faker.datatype.boolean(),
homework_days: 3,
mobility: MOBILITY_NONE,
mobility_days_per_month: 10,
budget: 5000,
budget_hidden: false,
expertises: [expertise1._id, expertise2._id, expertise3._id],
pinned_expertises: [expertise1._id],
softwares: [software._id],
languages: [language._id],
gold_soft_skills: [softSkillComm._id],
silver_soft_skills: [softSkillTeamWork._id],
bronze_soft_skills: [softSkillConflict._id],
city: msa,
})

customerFreelance = await CustomerFreelance.create({
password: faker.internet.password(),
email: faker.internet.email(),
lastname: faker.name.lastName(),
firstname: faker.name.firstName(),
source: 'SOURCE_RECOMMANDATION',
password: 'password123',
availability: AVAILABILITY_OFF,
available_from: new Date(2024,6,19),
available_days_per_week: 5,
email: 'sample@example.com',
lastname: 'Doe',
firstname: 'John',
source: SOURCE_RECOMMANDATION,
curriculum: new mongoose.Types.ObjectId(),
experience: new mongoose.Types.ObjectId(),
motivation: faker.lorem.sentence(),
main_job: job._id,
motivation: 'Motivated to work on challenging projects',
main_job: job,
gold_soft_skills: [softSkillComm._id],
silver_soft_skills: [softSkillTeamWork._id],
bronze_soft_skills: [softSkillConflict._id],
work_sector: [sector._id],
expertises: [expertise1._id],
siren: '923145171',
legal_status: 'EI',
company_name: faker.company.name(),
position: faker.name.jobTitle(),
company_name: 'Sample Company',
position: 'Lead Developer',
softwares: [software._id],
languages: [language._id],
main_experience: 'EXPERIENCE_EXPERT',
work_mode: 'WORK_MODE_REMOTE_SITE',
work_duration: ['WORK_DURATION__1_TO_6_MONTHS'],
mobility: 'MOBILITY_FRANCE',
main_experience: EXPERIENCE_EXPERT,
work_mode: WORK_MODE_REMOTE_SITE,
work_duration: [WORK_DURATION__1_TO_6_MONTHS],
mobility: MOBILITY_CITY,
mobility_city: rouen,
mobility_city_distance: 10,
cgu_accepted: true,
phone: '0606060606',
address: {
address: faker.address.streetAddress(),
city: faker.address.city(),
zip_code: faker.address.zipCode(),
country: faker.address.country()
address: '123 Main St',
city: 'Sample City',
zip_code: '12345',
country: 'Sample Country'
}
})
})
Expand All @@ -109,12 +134,11 @@ describe('Search', () => {

test('should find suggested freelances based on announce criteria', async () => {
const loadedAnnounce = await loadFromDb({model:'announce', id:announce._id,
fields:'suggested_freelances,gold_soft_skills,silver_soft_skills,bronze_soft_skills,job,sectors,expertises,softwares,languages,experience,_duration_days,duration_unit,duration'.split(',')
fields:'city,mobility,suggested_freelances,gold_soft_skills,silver_soft_skills,bronze_soft_skills,start_date,job,sectors,expertises,softwares,languages,experience,_duration_days,duration_unit,duration'.split(',')
})

console.log(customerFreelance)
console.log(announce)
console.log("suggestion:",loadedAnnounce[0].suggested_freelances)
console.log("freelance:",customerFreelance.fullname)
const suggestion = loadedAnnounce[0].suggested_freelances[0]
// console.dir(customerFreelance, { depth: null, colors: true, maxArrayLength: null })
// console.dir(announce, { depth: null, colors: true, maxArrayLength: null })
expect(String(customerFreelance._id)).toMatch(String(suggestion.id))
})
})
2 changes: 1 addition & 1 deletion backend/web/utils/consts.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ module.exports = {
ALL_SERVICES, ALF_CONDS, CANCEL_MODE, CUSTOM_PRESTATIONS_FLTR,
generate_id, GID_LEN, CESU,
NEEDED_VAR,
SKILLS, LANGUAGES, MAX_DESCRIPTION_LENGTH, EXPIRATION_DELAY,
SKILLS, LANGUAGES, LANGUAGE_LEVEL_ADVANCED, LANGUAGE_LEVEL_BEGINNER, LANGUAGE_LEVEL_INTERMEDIATE, LANGUAGE_LEVEL_NATIVE, MAX_DESCRIPTION_LENGTH, EXPIRATION_DELAY,
CLOSE_NOTIFICATION_DELAY, ACCOUNT_MIN_AGE, COMPANY_SIZE, COMPANY_ACTIVITY,
BUDGET_PERIOD, PRO, PART, CREASHOP_MODE,
MONTH_PERIOD, YEAR_PERIOD, DASHBOARD_MODE, MICROSERVICE_MODE, CARETAKER_MODE, REGISTER_MODE,
Expand Down

0 comments on commit be6fa63

Please sign in to comment.