toulouse-foederis: add candidature endpoint (#77524)
gitea/passerelle/pipeline/head This commit looks good
Details
gitea/passerelle/pipeline/head This commit looks good
Details
This commit is contained in:
parent
816da0f6b6
commit
7395fa5560
|
@ -30,6 +30,229 @@ from passerelle.utils.api import endpoint
|
|||
from passerelle.utils.json import datasource_array_schema, datasource_schema, response_schema
|
||||
|
||||
|
||||
def boolean_field(description):
|
||||
return {
|
||||
'description': description,
|
||||
'oneOf': [
|
||||
{'type': 'boolean'},
|
||||
{
|
||||
'type': 'string',
|
||||
'pattern': '[Oo]|[Nn]|[Tt][Rr][Uu][Ee]|[Ff][Aa][Ll][Ss][Ee]|1|0',
|
||||
'pattern_description': _(
|
||||
'Values "0", "1", "O", "N", "true" or "false" are allowed (case insensitive).'
|
||||
),
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def get_bool(obj):
|
||||
if obj is True or str(obj).lower() in ['true', 'o', '1']:
|
||||
return True
|
||||
if obj is False or str(obj).lower() in ['false', 'n', '0']:
|
||||
return False
|
||||
return obj
|
||||
|
||||
|
||||
APPLICATION_SCHEMA = {
|
||||
'$schema': 'http://json-schema.org/draft-04/schema#',
|
||||
'title': 'Toulouse Foederis application',
|
||||
'description': '',
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'type': {
|
||||
'description': _('Application Type (External or Internal).'),
|
||||
'type': 'string',
|
||||
},
|
||||
'announce_id': {
|
||||
'description': _('ID of the concerned job offer.'),
|
||||
'type': 'string',
|
||||
'pattern': '^[0-9]*$',
|
||||
},
|
||||
'civility': {
|
||||
'description': _("ID of an element of the data source 'civilite'."),
|
||||
'type': 'string',
|
||||
'pattern': '^[0-9]+$',
|
||||
},
|
||||
'first_name': {
|
||||
'description': _('Applicant first name.'),
|
||||
'type': 'string',
|
||||
},
|
||||
'last_name': {
|
||||
'description': _('Applicant last name.'),
|
||||
'type': 'string',
|
||||
},
|
||||
'gender': {
|
||||
'description': _('Applicant gender.'),
|
||||
'type': 'string',
|
||||
'enum': ['H', 'F', ''],
|
||||
},
|
||||
'birth_date': {
|
||||
'description': _('Applicant birth date.'),
|
||||
'type': 'string',
|
||||
'pattern': '^([0-9]{4}-[0-9]{2}-[0-9]{2})?$',
|
||||
},
|
||||
'nationality': {
|
||||
'description': _("ID of an element of the data source 'nationalite'."),
|
||||
'type': 'string',
|
||||
'pattern': '^[0-9]+$',
|
||||
},
|
||||
'work_authorization_end_date': {
|
||||
'description': _("Applicant end of working authorization, if nationality is 'other'."),
|
||||
'example_value': '2023-04-05',
|
||||
'type': 'string',
|
||||
'pattern': '^([0-9]{4}-[0-9]{2}-[0-9]{2})?$',
|
||||
},
|
||||
'rqth': boolean_field(_('RQTH.')),
|
||||
'rqth_end_date': {
|
||||
'description': _('End of RQTH, or none if not applicable.'),
|
||||
'type': 'string',
|
||||
'pattern': '^([0-9]{4}-[0-9]{2}-[0-9]{2})?$',
|
||||
},
|
||||
'driving_license': {
|
||||
'description': _('Driving license.'),
|
||||
'type': 'string',
|
||||
},
|
||||
'fimo': boolean_field(_('FIMO licence.')),
|
||||
'fimo_delivrance_date': {
|
||||
'description': _('FIMO licence delivrance date.'),
|
||||
'type': 'string',
|
||||
'pattern': '^([0-9]{4}-[0-9]{2}-[0-9]{2})?$',
|
||||
},
|
||||
'fimo_end_validity_date': {
|
||||
'description': _('FIMO licence end validity date.'),
|
||||
'type': 'string',
|
||||
'pattern': '^([0-9]{4}-[0-9]{2}-[0-9]{2})?$',
|
||||
},
|
||||
'current_situation': {
|
||||
'description': _("ID of an element of the data source 'situation-actuelle'."),
|
||||
'type': 'string',
|
||||
'pattern': '^[0-9]+$',
|
||||
},
|
||||
'agent_collectivity': {
|
||||
'description': _("Agent's collectivity"),
|
||||
'type': 'string',
|
||||
},
|
||||
'availability_start_date': {
|
||||
'description': _('Applicant availability start date.'),
|
||||
'type': 'string',
|
||||
'pattern': '^([0-9]{4}-[0-9]{2}-[0-9]{2})?$',
|
||||
},
|
||||
'availability_end_date': {
|
||||
'description': _('Applicant availability end date.'),
|
||||
'type': 'string',
|
||||
'pattern': '^([0-9]{4}-[0-9]{2}-[0-9]{2})?$',
|
||||
},
|
||||
'salary_expectations': {
|
||||
'description': _('Applicant salary expectations.'),
|
||||
'type': 'string',
|
||||
},
|
||||
'address': {
|
||||
'description': _('Applicant address.'),
|
||||
'type': 'string',
|
||||
},
|
||||
'address_complement': {
|
||||
'description': _('Applicant address complement.'),
|
||||
'type': 'string',
|
||||
},
|
||||
'zip': {
|
||||
'description': _('Applicant zip code.'),
|
||||
'type': 'string',
|
||||
},
|
||||
'city': {
|
||||
'description': _('Applicant city.'),
|
||||
'type': 'string',
|
||||
},
|
||||
'phone': {
|
||||
'description': _('Applicant phone number.'),
|
||||
'type': 'string',
|
||||
},
|
||||
'email': {
|
||||
'description': _('Applicant email.'),
|
||||
'type': 'string',
|
||||
},
|
||||
'contract_start_date': {
|
||||
'description': _('Applicant contract start date.'),
|
||||
'type': 'string',
|
||||
'pattern': '^([0-9]{4}-[0-9]{2}-[0-9]{2})?$',
|
||||
},
|
||||
'contract_end_date': {
|
||||
'description': _('Applicant contract end date.'),
|
||||
'type': 'string',
|
||||
'pattern': '^([0-9]{4}-[0-9]{2}-[0-9]{2})?$',
|
||||
},
|
||||
'additional_informations': {
|
||||
'description': _('Application information complement.'),
|
||||
'type': 'string',
|
||||
},
|
||||
'origin': {
|
||||
'description': _("ID of an element of the data source 'origine-candidature'."),
|
||||
'pattern': '^[0-9]*$',
|
||||
'type': 'string',
|
||||
},
|
||||
'origin_precisions': {
|
||||
'description': _("Precisions if 'origine' is 'other'."),
|
||||
'type': 'string',
|
||||
},
|
||||
'rgpd_agreement': boolean_field(_('RGPD agreement.')),
|
||||
'job_type': {
|
||||
'description': _("ID of an element of the data source 'type-emploi'."),
|
||||
'type': 'string',
|
||||
'pattern': '^[0-9]*$',
|
||||
},
|
||||
'job_realm': {
|
||||
'description': _("ID of an element of the data source 'domaine-emploi'."),
|
||||
'type': 'string',
|
||||
'pattern': '^[0-9]*$',
|
||||
},
|
||||
'job_family': {
|
||||
'description': _("ID of an element of the data source 'sous-domaine-emploi'."),
|
||||
'type': 'string',
|
||||
'pattern': '^[0-9]*$',
|
||||
},
|
||||
'job': {
|
||||
'description': _("ID of an element of the data source 'emploi'."),
|
||||
'type': 'string',
|
||||
'pattern': '^[0-9]*$',
|
||||
},
|
||||
'desired_work_time': {
|
||||
'description': _('TC / TNC.'),
|
||||
'type': 'string',
|
||||
'enum': ['TC', 'TNC'],
|
||||
},
|
||||
'internship_duration': {
|
||||
'description': _('Duration of the desired internship.'),
|
||||
'type': 'string',
|
||||
},
|
||||
'school_name': {
|
||||
'description': _("Candidate trainee's school name."),
|
||||
'type': 'string',
|
||||
},
|
||||
'diploma_name': {
|
||||
'description': _("Candidate trainee's diploma name."),
|
||||
'type': 'string',
|
||||
},
|
||||
'diploma_speciality': {
|
||||
'description': _("Candidate trainee's diploma speciality."),
|
||||
'type': 'string',
|
||||
},
|
||||
'aimed_diploma_level': {
|
||||
'description': _("ID of an element of the data source 'niveau-diplome'."),
|
||||
'type': 'string',
|
||||
'pattern': '^[0-9]*$',
|
||||
},
|
||||
'last_obtained_diploma': {
|
||||
'description': _("Candidate trainee's last obtained diploma."),
|
||||
'type': 'string',
|
||||
},
|
||||
'last_course_taken': {
|
||||
'description': _("Candidate trainee's last taken course."),
|
||||
'type': 'string',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class UpdateError(Exception):
|
||||
pass
|
||||
|
||||
|
@ -295,6 +518,78 @@ class Resource(BaseResource, HTTPResource):
|
|||
with document.pdf.open() as fd:
|
||||
return HttpResponse(fd, content_type='application/pdf')
|
||||
|
||||
@endpoint(
|
||||
perm="can_access",
|
||||
name="create-application",
|
||||
post={
|
||||
"description": _("Creates an application"),
|
||||
"request_body": {"schema": {"application/json": APPLICATION_SCHEMA}},
|
||||
},
|
||||
)
|
||||
def create_application(self, request, post_data):
|
||||
def _get_id(field_name):
|
||||
id = post_data.get(field_name, None)
|
||||
if id is None or id == '':
|
||||
return None
|
||||
return int(id)
|
||||
|
||||
request_data = {
|
||||
'type_de_candidature': post_data.get('type', 'E'),
|
||||
'annonce': _get_id('announce_id'),
|
||||
self.REFERENTIELS_FKEYS['civilite']: _get_id('civility'),
|
||||
'firstName': post_data.get('first_name', None),
|
||||
'lastName': post_data.get('last_name', None),
|
||||
'sexe': post_data.get('gender', None),
|
||||
'date_de_naissance': post_data.get('birth_date', None),
|
||||
self.REFERENTIELS_FKEYS['nationalite']: _get_id('nationality'),
|
||||
'date_fin_autorisation_de_travail': post_data.get('work_authorization_end_date', None),
|
||||
'rqth': 'O' if get_bool(post_data.get('rqth', False)) else 'N',
|
||||
'date_fin_rqth': post_data.get('rqth_end_date', None),
|
||||
'permis_de_conduire': post_data.get('driving_license', None),
|
||||
'fimo': 'O' if get_bool(post_data.get('fimo', False)) else 'N',
|
||||
'Date_delivrance_fimo': post_data.get('fimo_delivrance_date', None),
|
||||
'date_fin_validite_fimo': post_data.get('fimo_end_validity_date', None),
|
||||
self.REFERENTIELS_FKEYS['situation_actuelle']: _get_id('current_situation'),
|
||||
'collectivite_agent': post_data.get('agent_collectivity', None),
|
||||
'date_debut_disponibilite': post_data.get('availability_start_date', None),
|
||||
'date_fin_disponibilite': post_data.get('availability_end_date', None),
|
||||
'pretentions_salariales': post_data.get('salary_expectations', None),
|
||||
'adresse': post_data.get('address', None),
|
||||
'adresse_ligne_2': post_data.get('address_complement', None),
|
||||
'code_postal': post_data.get('zip', None),
|
||||
'ville': post_data.get('city', None),
|
||||
'telephone': post_data.get('phone', None),
|
||||
'email': post_data.get('email', None),
|
||||
'date_debut_contrat': post_data.get('contract_start_date', None),
|
||||
'date_fin_contrat': post_data.get('contract_end_date', None),
|
||||
'complement_information_candidature': post_data.get('additional_informations', None),
|
||||
self.REFERENTIELS_FKEYS['origine_candidature']: _get_id('origin'),
|
||||
'precision_origine_candidature': post_data.get('origin_precisions', None),
|
||||
'accord_RGPD': get_bool(post_data.get('rgpd_agreement', False)),
|
||||
self.REFERENTIELS_FKEYS['type_emploi']: _get_id('job_type'),
|
||||
self.REFERENTIELS_FKEYS['domaine_emploi']: _get_id('job_realm'),
|
||||
self.REFERENTIELS_FKEYS['sous_domaine_emploi']: _get_id('job_family'),
|
||||
self.REFERENTIELS_FKEYS['emploi']: _get_id('job'),
|
||||
'temps_de_travail_souhaite': post_data.get('desired_work_time', None),
|
||||
'duree_du_contrat_de_stage_apprentissage': post_data.get('internship_duration', None),
|
||||
'ecole_centre_de_formation_mission_loc': post_data.get('school_name', None),
|
||||
'intitule_diplome_vise': post_data.get('diploma_name', None),
|
||||
'specialite_diplome': post_data.get('diploma_speciality', None),
|
||||
self.REFERENTIELS_FKEYS['niveau_diplome']: _get_id('aimed_diploma_level'),
|
||||
'dernier_diplome_obtenu': post_data.get('last_obtained_diploma', None),
|
||||
'derniere_classe_suivie': post_data.get('last_course_taken', None),
|
||||
}
|
||||
|
||||
request_data = {k: v for k, v in request_data.items() if v is not None and v != ''}
|
||||
|
||||
results = self.http_request(
|
||||
'POST', 'data/candidature?viewIntegrationName=api_publik', json=request_data
|
||||
)
|
||||
return {
|
||||
'err': 0,
|
||||
'data': {'application_id': results[0]['id']},
|
||||
}
|
||||
|
||||
@endpoint(
|
||||
description=_('List announces'),
|
||||
long_description=_(
|
||||
|
|
|
@ -405,6 +405,114 @@ class TestEndpoints:
|
|||
app.get('/toulouse-foederis/foederis/announce/111/pdf/', status=404)
|
||||
assert response.headers['content-type'] == 'application/pdf'
|
||||
|
||||
def test_create_application(self, resource, app):
|
||||
@httmock.urlmatch(path=r'^.*/data/candidature$')
|
||||
def handler(url, request):
|
||||
assert request.headers['content-type'] == 'application/json'
|
||||
assert request.headers['api-key'] == APIKEY
|
||||
payload = json.loads(request.body)
|
||||
assert payload == {
|
||||
"type_de_candidature": "E",
|
||||
"annonce": 524522,
|
||||
"R60284409": 170013,
|
||||
"firstName": "John",
|
||||
"lastName": "Doe",
|
||||
"sexe": "H",
|
||||
"date_de_naissance": "1985-03-06",
|
||||
"R1249730": 93421,
|
||||
"date_fin_autorisation_de_travail": "2023-05-09",
|
||||
"rqth": "N",
|
||||
"date_fin_rqth": "2023-05-08",
|
||||
"permis_de_conduire": "A,B",
|
||||
"fimo": "O",
|
||||
"Date_delivrance_fimo": "2023-05-07",
|
||||
"date_fin_validite_fimo": "2023-05-08",
|
||||
"R1258320": 1258319,
|
||||
"collectivite_agent": "Mairie de Toulouse",
|
||||
"date_debut_disponibilite": "2023-05-02",
|
||||
"date_fin_disponibilite": "2023-05-01",
|
||||
"pretentions_salariales": "1000",
|
||||
"adresse": "12 Sesame Street",
|
||||
"code_postal": "77710",
|
||||
"ville": "Nemours",
|
||||
"telephone": "+33 636656565",
|
||||
"email": "csechet@entrouvert.com",
|
||||
"date_debut_contrat": "2023-05-06",
|
||||
"date_fin_contrat": "2023-05-04",
|
||||
"complement_information_candidature": "I need money.",
|
||||
"R1261279": 1561049,
|
||||
"accord_RGPD": True,
|
||||
"R1249707": 157193,
|
||||
"R60845221": 5776395,
|
||||
"R60845244": 5776394,
|
||||
"temps_de_travail_souhaite": "TC",
|
||||
"duree_du_contrat_de_stage_apprentissage": "2h",
|
||||
"ecole_centre_de_formation_mission_loc": "Ecole de la vie",
|
||||
"intitule_diplome_vise": "BE",
|
||||
"specialite_diplome": "Curling",
|
||||
"R1249737": 1124022,
|
||||
"dernier_diplome_obtenu": "BAC",
|
||||
"derniere_classe_suivie": "Terminale",
|
||||
}
|
||||
|
||||
return httmock.response(200, json.dumps({"code": 200, "results": [{"id": 42}]}))
|
||||
|
||||
@httmock.urlmatch()
|
||||
def error_handler(url, request):
|
||||
assert False, 'should not be reached'
|
||||
|
||||
with httmock.HTTMock(handler, error_handler):
|
||||
response = app.post_json(
|
||||
'/toulouse-foederis/foederis/create-application',
|
||||
params={
|
||||
"additional_informations": "I need money.",
|
||||
"address": "12 Sesame Street",
|
||||
"address_complement": "",
|
||||
"agent_collectivity": "Mairie de Toulouse",
|
||||
"aimed_diploma_level": "1124022",
|
||||
"announce_id": "0524522",
|
||||
"availability_end_date": "2023-05-01",
|
||||
"availability_start_date": "2023-05-02",
|
||||
"birth_date": "1985-03-06",
|
||||
"city": "Nemours",
|
||||
"civility": "170013",
|
||||
"contract_end_date": "2023-05-04",
|
||||
"contract_start_date": "2023-05-06",
|
||||
"current_situation": "1258319",
|
||||
"desired_work_time": "TC",
|
||||
"diploma_name": "BE",
|
||||
"diploma_speciality": "Curling",
|
||||
"driving_license": "A,B",
|
||||
"email": "csechet@entrouvert.com",
|
||||
"fimo": "o",
|
||||
"fimo_delivrance_date": "2023-05-07",
|
||||
"fimo_end_validity_date": "2023-05-08",
|
||||
"first_name": "John",
|
||||
"gender": "H",
|
||||
"internship_duration": "2h",
|
||||
"job_family": "5776394",
|
||||
"job_realm": "5776395",
|
||||
"job_type": "157193",
|
||||
"last_course_taken": "Terminale",
|
||||
"last_name": "Doe",
|
||||
"last_obtained_diploma": "BAC",
|
||||
"nationality": "93421",
|
||||
"origin": "1561049",
|
||||
"origin_precisions": "",
|
||||
"phone": "+33 636656565",
|
||||
"rgpd_agreement": "tRuE",
|
||||
"rqth": False,
|
||||
"rqth_end_date": "2023-05-08",
|
||||
"salary_expectations": "1000",
|
||||
"school_name": "Ecole de la vie",
|
||||
"type": "E",
|
||||
"work_authorization_end_date": "2023-05-09",
|
||||
"zip": "77710",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.json["data"]["application_id"] == 42
|
||||
|
||||
|
||||
def test_migration_0003_no_null_no_charfield(migration):
|
||||
with connection.cursor() as cur:
|
||||
|
|
Loading…
Reference in New Issue