diff --git a/README.md b/README.md index 8012558fb..13b38dba1 100644 --- a/README.md +++ b/README.md @@ -72,11 +72,11 @@ We invite developers to join us in our mission to bring AI and data integration | Name | Type | Status | Release date | Last update | |-------------------------------------------------------------------------------------------------------------------------------------------|----------------------|--------------------|----------------|-----------------| -| [**Adzuna**](./src/hrflow_connectors/v1/connectors/adzuna/README.md) | Job Board | :book: Open source | *08/09/2022* | *05/09/2024* | +| [**Adzuna**](./src/hrflow_connectors/v2/connectors/adzuna/README.md) | Job Board | :book: Open source | *08/09/2022* | *05/09/2024* | | [**Carrevolutis**](./src/hrflow_connectors/v1/connectors/carrevolutis/README.md) | Job Board | :book: Open source | *20/03/2024* | *05/09/2024* | +| [**France Travail (ex: Pole Emploi)**](./src/hrflow_connectors/v2/connectors/francetravail/README.md) | Job Board | :book: Open source | *15/07/2022* | *24/10/2024* | | [**Jobology**](./src/hrflow_connectors/v1/connectors/jobology/README.md) | Job Board | :book: Open source | *21/12/2022* | *05/09/2024* | | [**Meteojob**](./src/hrflow_connectors/v1/connectors/meteojob/README.md) | Job Board | :book: Open source | *15/02/2024* | *05/09/2024* | -| [**Pole Emploi**](./src/hrflow_connectors/v1/connectors/poleemploi/README.md) | Job Board | :book: Open source | *15/07/2022* | *24/10/2024* | # :lock: Premium Connectors diff --git a/manifest.json b/manifest.json index 827d2c69c..f2585f2eb 100644 --- a/manifest.json +++ b/manifest.json @@ -64402,6 +64402,10372 @@ } } ] + }, + { + "name": "Adzuna", + "type": "JOBBOARD", + "subtype": "adzuna", + "logo": "https://raw.githubusercontent.com/Riminder/hrflow-connectors/master/src/hrflow_connectors/v2/connectors/adzuna/logo.png", + "actions": [ + { + "name": "create_jobs_in_hrflow", + "data_type": "job", + "direction": "inbound", + "mode": "create", + "connector_auth_parameters": { + "title": "AuthParameters", + "type": "object", + "properties": { + "app_id": { + "description": "Application ID, supplied by Adzuna", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "app_key": { + "description": "Application key, supplied by Adzuna", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "app_id", + "app_key" + ], + "$defs": {} + }, + "hrflow_auth_parameters": { + "title": "AuthParameters", + "type": "object", + "properties": { + "api_secret": { + "description": "API Key used to access HrFlow.ai API", + "type": "string" + }, + "api_user": { + "description": "User email used to access HrFlow.ai API", + "type": "string" + } + }, + "required": [ + "api_secret", + "api_user" + ], + "$defs": {} + }, + "origin": "Adzuna", + "origin_data_schema": { + "title": "AdzunaJob", + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "created": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "full_description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "redirect_url": { + "type": "string" + }, + "latitude": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "longitude": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "category": { + "$ref": "#/$defs/Category" + }, + "location": { + "$ref": "#/$defs/Location" + }, + "salary_min": { + "type": "integer" + }, + "salary_max": { + "type": "integer" + }, + "salary_is_predicted": { + "$ref": "#/$defs/Flag" + }, + "company": { + "$ref": "#/$defs/Company" + }, + "contract_type": { + "anyOf": [ + { + "$ref": "#/$defs/ContractType" + }, + { + "type": "null" + } + ] + }, + "contract_time": { + "anyOf": [ + { + "$ref": "#/$defs/ContractTime" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "id", + "created", + "title", + "description", + "full_description", + "redirect_url", + "latitude", + "longitude", + "category", + "location", + "salary_min", + "salary_max", + "salary_is_predicted", + "company", + "contract_type", + "contract_time" + ], + "$defs": { + "Category": { + "title": "Category", + "type": "object", + "properties": { + "tag": { + "type": "string" + }, + "label": { + "type": "string" + } + }, + "required": [ + "tag", + "label" + ] + }, + "Location": { + "title": "Location", + "type": "object", + "properties": { + "area": { + "type": "array", + "items": { + "type": "string" + } + }, + "display_name": { + "type": "string" + } + }, + "required": [ + "area", + "display_name" + ] + }, + "Flag": { + "title": "Flag", + "enum": [ + "0", + "1" + ] + }, + "Company": { + "title": "Company", + "type": "object", + "properties": { + "display_name": { + "type": "string" + }, + "canonical_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "display_name", + "canonical_name", + "count" + ] + }, + "ContractType": { + "title": "ContractType", + "enum": [ + "contract", + "permanent" + ] + }, + "ContractTime": { + "title": "ContractTime", + "enum": [ + "full_time", + "part_time" + ] + } + } + }, + "supports_incremental": false, + "pull_parameters": { + "title": "ReadJobsParameters", + "type": "object", + "properties": { + "country": { + "description": "ISO 8601 country code of the country of interest", + "$ref": "#/$defs/CountryCode" + }, + "results_per_page": { + "description": "The number of results to include on a page of search results.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": 50 + }, + "what": { + "description": "The keywords to search for. Multiple terms may be space separated.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "what_and": { + "description": "The keywords to search for, all keywords must be found.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "what_phrase": { + "description": "An entire phrase which must be found in the description or title.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "what_or": { + "description": "The keywords to search for, any keywords may be found. Multiple terms may be space separated.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "what_exclude": { + "description": "Keywords to exclude from the search. Multiple terms may be space separated.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "title_only": { + "description": "Keywords to find, but only in the title. Multiple terms may be space separated.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "where": { + "description": "The geographic centre of the search. Place names, postal codes, etc. may be used.\t", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "distance": { + "description": "The distance in kilometres from the centre of the place described by the 'where' parameter. Defaults to 5km.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "location0": { + "description": "The location fields may be used to describe a location, in a similar form to that returned in a Adzuna::API::Response::Location object.For example, \"location0=UK&location1=South East England&location2=Surrey\" will performn a search over the county of Surrey.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location1": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location2": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location3": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location4": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location5": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location6": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location7": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "max_days_old": { + "description": "The age of the oldest advertisment in days that will be returned.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "category": { + "description": "The category tag, as returned by the \"category\" endpoint.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "sort_dir": { + "description": "The direction to order the search results.", + "anyOf": [ + { + "$ref": "#/$defs/SortDir" + }, + { + "type": "null" + } + ], + "default": null + }, + "sort_by": { + "description": "The ordering of the search results.", + "anyOf": [ + { + "$ref": "#/$defs/SortKey" + }, + { + "type": "null" + } + ], + "default": null + }, + "salary_min": { + "description": "The minimum salary we wish to get results for.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "salary_max": { + "description": "The maximum salary we wish to get results for.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "salary_include_unknown": { + "description": "If set it \"1\", jobs without a known salary are returned.", + "anyOf": [ + { + "$ref": "#/$defs/Filter" + }, + { + "type": "null" + } + ], + "default": null + }, + "full_time": { + "description": "If set to \"1\", only full time jobs will be returned.", + "anyOf": [ + { + "$ref": "#/$defs/Filter" + }, + { + "type": "null" + } + ], + "default": null + }, + "part_time": { + "description": "If set to \"1\", only part time jobs will be returned.", + "anyOf": [ + { + "$ref": "#/$defs/Filter" + }, + { + "type": "null" + } + ], + "default": null + }, + "contract": { + "description": "If set to \"1\", only contract jobs will be returned.", + "anyOf": [ + { + "$ref": "#/$defs/Filter" + }, + { + "type": "null" + } + ], + "default": null + }, + "permanent": { + "description": "If set to \"1\", only permanent jobs will be returned.", + "anyOf": [ + { + "$ref": "#/$defs/Filter" + }, + { + "type": "null" + } + ], + "default": null + }, + "company": { + "description": "The canonical company name. This may be returned in a Adzuna::API::Response::Company object when a job is returned. A full list of allowed terms in not available through the API.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "country" + ], + "$defs": { + "CountryCode": { + "title": "CountryCode", + "enum": [ + "at", + "au", + "br", + "ca", + "de", + "fr", + "gb", + "in", + "it", + "nl", + "nz", + "pl", + "ru", + "sg", + "us", + "za" + ] + }, + "SortDir": { + "title": "SortDir", + "enum": [ + "down", + "up" + ] + }, + "SortKey": { + "title": "SortKey", + "enum": [ + "date", + "default", + "hybrid", + "relevance", + "salary" + ] + }, + "Filter": { + "title": "Filter", + "enum": [ + "1" + ] + } + } + }, + "target": "HrFlow", + "target_data_schema": { + "title": "HrFlowJob", + "type": "object", + "properties": { + "key": { + "description": "Identification key of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "description": "Custom identifier of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "name": { + "description": "Job title.", + "type": "string" + }, + "location": { + "description": "Job location object.", + "$ref": "#/$defs/Location" + }, + "sections": { + "description": "Job custom sections.", + "type": "array", + "items": { + "$ref": "#/$defs/Section" + } + }, + "url": { + "description": "Job post original URL.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "summary": { + "description": "Brief summary of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "archieved_at": { + "description": "type: datetime ISO8601, Archive date of the Job. The value is null for unarchived Jobs.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "updated_at": { + "description": "type: datetime ISO8601, Last update date of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "created_at": { + "description": "type: datetime ISO8601, Creation date of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "skills": { + "description": "list of skills of the Job.", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Skill" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "languages": { + "description": "list of spoken languages of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "certifications": { + "description": "list of certifications of the Job.", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "courses": { + "description": "list of courses of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "tasks": { + "description": "list of tasks of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "tags": { + "description": "list of tags of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "metadatas": { + "description": "list of metadatas of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "ranges_float": { + "description": "list of ranges of floats", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/RangesFloat" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "ranges_date": { + "description": "list of ranges of dates", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/RangesDate" + } + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name", + "location", + "sections" + ], + "$defs": { + "Location": { + "title": "Location", + "type": "object", + "properties": { + "text": { + "description": "Location text address.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "lat": { + "description": "Geocentric latitude of the Location.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "lng": { + "description": "Geocentric longitude of the Location.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "fields": { + "description": "other location attributes like country, country_code etc", + "anyOf": [ + { + "type": "object" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "Section": { + "title": "Section", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Section of the Job. Example: culture", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "title": { + "description": "Display Title of a Section. Example: Corporate Culture", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "description": { + "description": "Text description of a Section: Example: Our values areNone", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "Skill": { + "title": "Skill", + "type": "object", + "properties": { + "name": { + "description": "Identification name of the skill", + "type": "string" + }, + "type": { + "description": "Type of the skill. hard or soft", + "enum": [ + "hard", + "soft" + ] + }, + "value": { + "description": "Value associated to the skill", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name", + "type" + ] + }, + "GeneralEntitySchema": { + "title": "GeneralEntitySchema", + "type": "object", + "properties": { + "name": { + "description": "Identification name of the Object", + "type": "string" + }, + "value": { + "description": "Value associated to the Object's name", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name" + ] + }, + "RangesFloat": { + "title": "RangesFloat", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Range of floats attached to the Job. Example: salary", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_min": { + "description": "Min value. Example: 500.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_max": { + "description": "Max value. Example: 100.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "unit": { + "description": "Unit of the value. Example: euros.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "RangesDate": { + "title": "RangesDate", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Range of dates attached to the Job. Example: availability.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_min": { + "description": "Min value in datetime ISO 8601, Example: 500.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_max": { + "description": "Max value in datetime ISO 8601, Example: 1000", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + } + } + }, + "push_parameters": { + "title": "CreateCriterias", + "type": "object", + "properties": { + "board_key": { + "description": "HrFlow.ai board key", + "type": "string" + }, + "enrich_with_parsing": { + "description": "When enabled jobs are enriched with HrFlow.ai parsing", + "type": "boolean", + "default": false + } + }, + "required": [ + "board_key" + ], + "$defs": {} + }, + "jsonmap": { + "name": "?.title", + "reference": "?.id | $string", + "created_at": "?.created", + "location": { + "lat": "?.latitude != null ?? .latitude | $float : null", + "lng": "?.longitude != null ?? .longitude | $float : null", + "text": "?.location.display_name || ''" + }, + "url": "?.redirect_url", + "summary": "?.description", + "sections": "?.full_description ?? [{name: 'full_description', title: 'Full Description', description: .full_description}]: []", + "tags": [ + { + "name": "contract_type", + "value": "?.contract_type" + }, + { + "name": "contract_time", + "value": "?.contract_time" + }, + { + "name": "salary_min", + "value": "?.salary_min" + }, + { + "name": "salary_max", + "value": "?.salary_max" + }, + { + "name": "salary_is_predicted", + "value": "?.salary_is_predicted == '1' ?? true : false" + }, + { + "name": "category", + "value": "?.category?.label" + }, + { + "name": "company", + "value": "?.company?.display_name" + } + ] + }, + "workflow": { + "catch_template": "import typing as t\n\nfrom hrflow_connectors.v2 import Adzuna\nfrom hrflow_connectors.v2.core.run import ActionInitError, Reason\n\nCONNECTOR_AUTH_SETTINGS_PREFIX = \"connector_auth_\"\nHRFLOW_AUTH_SETTINGS_PREFIX = \"hrflow_auth_\"\nPULL_PARAMETERS_SETTINGS_PREFIX = \"pull_parameters_\"\nPUSH_PARAMETERS_SETTINGS_PREFIX = \"push_parameters_\"\n\n# << format_placeholder >>\n\n# << logics_placeholder >>\n\n# << callback_placeholder >>\n\n\n\n\n# << event_parser_placeholder >>\n\n\n\ndef workflow(\n \n _request: dict,\n \n settings: dict\n ) -> None:\n if \"__workflow_id\" not in settings:\n return Adzuna.create_jobs_in_hrflow(\n workflow_id=\"\",\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.workflow_id_not_found,\n data=dict(error=\"__workflow_id not found in settings\", settings_keys=list(settings.keys())),\n )\n )\n workflow_id = settings[\"__workflow_id\"]\n\n \n event_parser = globals().get(\"event_parser\", globals().get(\"default_event_parser\"))\n\n if event_parser is not None:\n try:\n _request = event_parser(_request)\n except Exception as e:\n return Adzuna.create_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.event_parsing_failure,\n data=dict(error=e, event=_request),\n )\n )\n \n\n connector_auth = dict()\n for parameter in ('app_id', 'app_key'):\n parameter_name = \"{}{}\".format(CONNECTOR_AUTH_SETTINGS_PREFIX, parameter) \n if parameter_name in settings:\n connector_auth[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n connector_auth[parameter] = _request[parameter_name]\n \n\n hrflow_auth = dict()\n for parameter in ('api_secret', 'api_user'):\n parameter_name = \"{}{}\".format(HRFLOW_AUTH_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n hrflow_auth[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n hrflow_auth[parameter] = _request[parameter_name]\n \n\n pull_parameters = dict()\n for parameter in ('country', 'results_per_page', 'what', 'what_and', 'what_phrase', 'what_or', 'what_exclude', 'title_only', 'where', 'distance', 'location0', 'location1', 'location2', 'location3', 'location4', 'location5', 'location6', 'location7', 'max_days_old', 'category', 'sort_dir', 'sort_by', 'salary_min', 'salary_max', 'salary_include_unknown', 'full_time', 'part_time', 'contract', 'permanent', 'company'):\n parameter_name = \"{}{}\".format(PULL_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n pull_parameters[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n pull_parameters[parameter] = _request[parameter_name]\n \n\n push_parameters = dict()\n for parameter in ('board_key', 'enrich_with_parsing'):\n parameter_name = \"{}{}\".format(PUSH_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n push_parameters[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n push_parameters[parameter] = _request[parameter_name]\n \n\n incremental = settings.get(\"__incremental\")\n\n return Adzuna.create_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=connector_auth,\n hrflow_auth=hrflow_auth,\n pull_parameters=pull_parameters,\n push_parameters=push_parameters,\n logics=globals().get(\"logics\"),\n format=globals().get(\"format\"),\n callback=globals().get(\"callback\"),\n incremental=incremental == \"enable\",\n )", + "pull_template": "import typing as t\n\nfrom hrflow_connectors.v2 import Adzuna\nfrom hrflow_connectors.v2.core.run import ActionInitError, Reason\n\nCONNECTOR_AUTH_SETTINGS_PREFIX = \"connector_auth_\"\nHRFLOW_AUTH_SETTINGS_PREFIX = \"hrflow_auth_\"\nPULL_PARAMETERS_SETTINGS_PREFIX = \"pull_parameters_\"\nPUSH_PARAMETERS_SETTINGS_PREFIX = \"push_parameters_\"\n\n# << format_placeholder >>\n\n# << logics_placeholder >>\n\n# << callback_placeholder >>\n\n\n\ndef workflow(\n \n settings: dict\n ) -> None:\n if \"__workflow_id\" not in settings:\n return Adzuna.create_jobs_in_hrflow(\n workflow_id=\"\",\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.workflow_id_not_found,\n data=dict(error=\"__workflow_id not found in settings\", settings_keys=list(settings.keys())),\n )\n )\n workflow_id = settings[\"__workflow_id\"]\n\n \n\n connector_auth = dict()\n for parameter in ('app_id', 'app_key'):\n parameter_name = \"{}{}\".format(CONNECTOR_AUTH_SETTINGS_PREFIX, parameter) \n if parameter_name in settings:\n connector_auth[parameter] = settings[parameter_name]\n \n\n hrflow_auth = dict()\n for parameter in ('api_secret', 'api_user'):\n parameter_name = \"{}{}\".format(HRFLOW_AUTH_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n hrflow_auth[parameter] = settings[parameter_name]\n \n\n pull_parameters = dict()\n for parameter in ('country', 'results_per_page', 'what', 'what_and', 'what_phrase', 'what_or', 'what_exclude', 'title_only', 'where', 'distance', 'location0', 'location1', 'location2', 'location3', 'location4', 'location5', 'location6', 'location7', 'max_days_old', 'category', 'sort_dir', 'sort_by', 'salary_min', 'salary_max', 'salary_include_unknown', 'full_time', 'part_time', 'contract', 'permanent', 'company'):\n parameter_name = \"{}{}\".format(PULL_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n pull_parameters[parameter] = settings[parameter_name]\n \n\n push_parameters = dict()\n for parameter in ('board_key', 'enrich_with_parsing'):\n parameter_name = \"{}{}\".format(PUSH_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n push_parameters[parameter] = settings[parameter_name]\n \n\n incremental = settings.get(\"__incremental\")\n\n return Adzuna.create_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=connector_auth,\n hrflow_auth=hrflow_auth,\n pull_parameters=pull_parameters,\n push_parameters=push_parameters,\n logics=globals().get(\"logics\"),\n format=globals().get(\"format\"),\n callback=globals().get(\"callback\"),\n incremental=incremental == \"enable\",\n )", + "settings_keys": { + "workflow_id": "__workflow_id", + "incremental": "__incremental", + "connector_auth_prefix": "connector_auth_", + "hrflow_auth_prefix": "hrflow_auth_", + "pull_parameters_prefix": "pull_parameters_", + "push_parameters_prefix": "push_parameters_" + }, + "placeholders": { + "logics": "# << logics_placeholder >>", + "format": "# << format_placeholder >>", + "callback": "# << callback_placeholder >>", + "event_parser": "# << event_parser_placeholder >>" + }, + "expected": { + "activate_incremental": "enable", + "logics_functions_name": "logics", + "format_functions_name": "format", + "callback_functions_name": "callback", + "event_parser_function_name": "event_parser" + } + } + }, + { + "name": "update_jobs_in_hrflow", + "data_type": "job", + "direction": "inbound", + "mode": "update", + "connector_auth_parameters": { + "title": "AuthParameters", + "type": "object", + "properties": { + "app_id": { + "description": "Application ID, supplied by Adzuna", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "app_key": { + "description": "Application key, supplied by Adzuna", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "app_id", + "app_key" + ], + "$defs": {} + }, + "hrflow_auth_parameters": { + "title": "AuthParameters", + "type": "object", + "properties": { + "api_secret": { + "description": "API Key used to access HrFlow.ai API", + "type": "string" + }, + "api_user": { + "description": "User email used to access HrFlow.ai API", + "type": "string" + } + }, + "required": [ + "api_secret", + "api_user" + ], + "$defs": {} + }, + "origin": "Adzuna", + "origin_data_schema": { + "title": "AdzunaJob", + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "created": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "full_description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "redirect_url": { + "type": "string" + }, + "latitude": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "longitude": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "category": { + "$ref": "#/$defs/Category" + }, + "location": { + "$ref": "#/$defs/Location" + }, + "salary_min": { + "type": "integer" + }, + "salary_max": { + "type": "integer" + }, + "salary_is_predicted": { + "$ref": "#/$defs/Flag" + }, + "company": { + "$ref": "#/$defs/Company" + }, + "contract_type": { + "anyOf": [ + { + "$ref": "#/$defs/ContractType" + }, + { + "type": "null" + } + ] + }, + "contract_time": { + "anyOf": [ + { + "$ref": "#/$defs/ContractTime" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "id", + "created", + "title", + "description", + "full_description", + "redirect_url", + "latitude", + "longitude", + "category", + "location", + "salary_min", + "salary_max", + "salary_is_predicted", + "company", + "contract_type", + "contract_time" + ], + "$defs": { + "Category": { + "title": "Category", + "type": "object", + "properties": { + "tag": { + "type": "string" + }, + "label": { + "type": "string" + } + }, + "required": [ + "tag", + "label" + ] + }, + "Location": { + "title": "Location", + "type": "object", + "properties": { + "area": { + "type": "array", + "items": { + "type": "string" + } + }, + "display_name": { + "type": "string" + } + }, + "required": [ + "area", + "display_name" + ] + }, + "Flag": { + "title": "Flag", + "enum": [ + "0", + "1" + ] + }, + "Company": { + "title": "Company", + "type": "object", + "properties": { + "display_name": { + "type": "string" + }, + "canonical_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "display_name", + "canonical_name", + "count" + ] + }, + "ContractType": { + "title": "ContractType", + "enum": [ + "contract", + "permanent" + ] + }, + "ContractTime": { + "title": "ContractTime", + "enum": [ + "full_time", + "part_time" + ] + } + } + }, + "supports_incremental": false, + "pull_parameters": { + "title": "ReadJobsParameters", + "type": "object", + "properties": { + "country": { + "description": "ISO 8601 country code of the country of interest", + "$ref": "#/$defs/CountryCode" + }, + "results_per_page": { + "description": "The number of results to include on a page of search results.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": 50 + }, + "what": { + "description": "The keywords to search for. Multiple terms may be space separated.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "what_and": { + "description": "The keywords to search for, all keywords must be found.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "what_phrase": { + "description": "An entire phrase which must be found in the description or title.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "what_or": { + "description": "The keywords to search for, any keywords may be found. Multiple terms may be space separated.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "what_exclude": { + "description": "Keywords to exclude from the search. Multiple terms may be space separated.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "title_only": { + "description": "Keywords to find, but only in the title. Multiple terms may be space separated.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "where": { + "description": "The geographic centre of the search. Place names, postal codes, etc. may be used.\t", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "distance": { + "description": "The distance in kilometres from the centre of the place described by the 'where' parameter. Defaults to 5km.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "location0": { + "description": "The location fields may be used to describe a location, in a similar form to that returned in a Adzuna::API::Response::Location object.For example, \"location0=UK&location1=South East England&location2=Surrey\" will performn a search over the county of Surrey.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location1": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location2": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location3": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location4": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location5": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location6": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location7": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "max_days_old": { + "description": "The age of the oldest advertisment in days that will be returned.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "category": { + "description": "The category tag, as returned by the \"category\" endpoint.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "sort_dir": { + "description": "The direction to order the search results.", + "anyOf": [ + { + "$ref": "#/$defs/SortDir" + }, + { + "type": "null" + } + ], + "default": null + }, + "sort_by": { + "description": "The ordering of the search results.", + "anyOf": [ + { + "$ref": "#/$defs/SortKey" + }, + { + "type": "null" + } + ], + "default": null + }, + "salary_min": { + "description": "The minimum salary we wish to get results for.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "salary_max": { + "description": "The maximum salary we wish to get results for.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "salary_include_unknown": { + "description": "If set it \"1\", jobs without a known salary are returned.", + "anyOf": [ + { + "$ref": "#/$defs/Filter" + }, + { + "type": "null" + } + ], + "default": null + }, + "full_time": { + "description": "If set to \"1\", only full time jobs will be returned.", + "anyOf": [ + { + "$ref": "#/$defs/Filter" + }, + { + "type": "null" + } + ], + "default": null + }, + "part_time": { + "description": "If set to \"1\", only part time jobs will be returned.", + "anyOf": [ + { + "$ref": "#/$defs/Filter" + }, + { + "type": "null" + } + ], + "default": null + }, + "contract": { + "description": "If set to \"1\", only contract jobs will be returned.", + "anyOf": [ + { + "$ref": "#/$defs/Filter" + }, + { + "type": "null" + } + ], + "default": null + }, + "permanent": { + "description": "If set to \"1\", only permanent jobs will be returned.", + "anyOf": [ + { + "$ref": "#/$defs/Filter" + }, + { + "type": "null" + } + ], + "default": null + }, + "company": { + "description": "The canonical company name. This may be returned in a Adzuna::API::Response::Company object when a job is returned. A full list of allowed terms in not available through the API.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "country" + ], + "$defs": { + "CountryCode": { + "title": "CountryCode", + "enum": [ + "at", + "au", + "br", + "ca", + "de", + "fr", + "gb", + "in", + "it", + "nl", + "nz", + "pl", + "ru", + "sg", + "us", + "za" + ] + }, + "SortDir": { + "title": "SortDir", + "enum": [ + "down", + "up" + ] + }, + "SortKey": { + "title": "SortKey", + "enum": [ + "date", + "default", + "hybrid", + "relevance", + "salary" + ] + }, + "Filter": { + "title": "Filter", + "enum": [ + "1" + ] + } + } + }, + "target": "HrFlow", + "target_data_schema": { + "title": "HrFlowJob", + "type": "object", + "properties": { + "key": { + "description": "Identification key of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "description": "Custom identifier of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "name": { + "description": "Job title.", + "type": "string" + }, + "location": { + "description": "Job location object.", + "$ref": "#/$defs/Location" + }, + "sections": { + "description": "Job custom sections.", + "type": "array", + "items": { + "$ref": "#/$defs/Section" + } + }, + "url": { + "description": "Job post original URL.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "summary": { + "description": "Brief summary of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "archieved_at": { + "description": "type: datetime ISO8601, Archive date of the Job. The value is null for unarchived Jobs.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "updated_at": { + "description": "type: datetime ISO8601, Last update date of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "created_at": { + "description": "type: datetime ISO8601, Creation date of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "skills": { + "description": "list of skills of the Job.", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Skill" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "languages": { + "description": "list of spoken languages of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "certifications": { + "description": "list of certifications of the Job.", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "courses": { + "description": "list of courses of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "tasks": { + "description": "list of tasks of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "tags": { + "description": "list of tags of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "metadatas": { + "description": "list of metadatas of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "ranges_float": { + "description": "list of ranges of floats", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/RangesFloat" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "ranges_date": { + "description": "list of ranges of dates", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/RangesDate" + } + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name", + "location", + "sections" + ], + "$defs": { + "Location": { + "title": "Location", + "type": "object", + "properties": { + "text": { + "description": "Location text address.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "lat": { + "description": "Geocentric latitude of the Location.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "lng": { + "description": "Geocentric longitude of the Location.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "fields": { + "description": "other location attributes like country, country_code etc", + "anyOf": [ + { + "type": "object" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "Section": { + "title": "Section", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Section of the Job. Example: culture", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "title": { + "description": "Display Title of a Section. Example: Corporate Culture", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "description": { + "description": "Text description of a Section: Example: Our values areNone", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "Skill": { + "title": "Skill", + "type": "object", + "properties": { + "name": { + "description": "Identification name of the skill", + "type": "string" + }, + "type": { + "description": "Type of the skill. hard or soft", + "enum": [ + "hard", + "soft" + ] + }, + "value": { + "description": "Value associated to the skill", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name", + "type" + ] + }, + "GeneralEntitySchema": { + "title": "GeneralEntitySchema", + "type": "object", + "properties": { + "name": { + "description": "Identification name of the Object", + "type": "string" + }, + "value": { + "description": "Value associated to the Object's name", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name" + ] + }, + "RangesFloat": { + "title": "RangesFloat", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Range of floats attached to the Job. Example: salary", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_min": { + "description": "Min value. Example: 500.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_max": { + "description": "Max value. Example: 100.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "unit": { + "description": "Unit of the value. Example: euros.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "RangesDate": { + "title": "RangesDate", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Range of dates attached to the Job. Example: availability.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_min": { + "description": "Min value in datetime ISO 8601, Example: 500.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_max": { + "description": "Max value in datetime ISO 8601, Example: 1000", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + } + } + }, + "push_parameters": { + "title": "UpdateCriterias", + "type": "object", + "properties": { + "board_key": { + "description": "HrFlow.ai board key", + "type": "string" + } + }, + "required": [ + "board_key" + ], + "$defs": {} + }, + "jsonmap": { + "name": "?.title", + "reference": "?.id | $string", + "created_at": "?.created", + "location": { + "lat": "?.latitude != null ?? .latitude | $float : null", + "lng": "?.longitude != null ?? .longitude | $float : null", + "text": "?.location.display_name || ''" + }, + "url": "?.redirect_url", + "summary": "?.description", + "sections": "?.full_description ?? [{name: 'full_description', title: 'Full Description', description: .full_description}]: []", + "tags": [ + { + "name": "contract_type", + "value": "?.contract_type" + }, + { + "name": "contract_time", + "value": "?.contract_time" + }, + { + "name": "salary_min", + "value": "?.salary_min" + }, + { + "name": "salary_max", + "value": "?.salary_max" + }, + { + "name": "salary_is_predicted", + "value": "?.salary_is_predicted == '1' ?? true : false" + }, + { + "name": "category", + "value": "?.category?.label" + }, + { + "name": "company", + "value": "?.company?.display_name" + } + ] + }, + "workflow": { + "catch_template": "import typing as t\n\nfrom hrflow_connectors.v2 import Adzuna\nfrom hrflow_connectors.v2.core.run import ActionInitError, Reason\n\nCONNECTOR_AUTH_SETTINGS_PREFIX = \"connector_auth_\"\nHRFLOW_AUTH_SETTINGS_PREFIX = \"hrflow_auth_\"\nPULL_PARAMETERS_SETTINGS_PREFIX = \"pull_parameters_\"\nPUSH_PARAMETERS_SETTINGS_PREFIX = \"push_parameters_\"\n\n# << format_placeholder >>\n\n# << logics_placeholder >>\n\n# << callback_placeholder >>\n\n\n\n\n# << event_parser_placeholder >>\n\n\n\ndef workflow(\n \n _request: dict,\n \n settings: dict\n ) -> None:\n if \"__workflow_id\" not in settings:\n return Adzuna.update_jobs_in_hrflow(\n workflow_id=\"\",\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.workflow_id_not_found,\n data=dict(error=\"__workflow_id not found in settings\", settings_keys=list(settings.keys())),\n )\n )\n workflow_id = settings[\"__workflow_id\"]\n\n \n event_parser = globals().get(\"event_parser\", globals().get(\"default_event_parser\"))\n\n if event_parser is not None:\n try:\n _request = event_parser(_request)\n except Exception as e:\n return Adzuna.update_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.event_parsing_failure,\n data=dict(error=e, event=_request),\n )\n )\n \n\n connector_auth = dict()\n for parameter in ('app_id', 'app_key'):\n parameter_name = \"{}{}\".format(CONNECTOR_AUTH_SETTINGS_PREFIX, parameter) \n if parameter_name in settings:\n connector_auth[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n connector_auth[parameter] = _request[parameter_name]\n \n\n hrflow_auth = dict()\n for parameter in ('api_secret', 'api_user'):\n parameter_name = \"{}{}\".format(HRFLOW_AUTH_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n hrflow_auth[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n hrflow_auth[parameter] = _request[parameter_name]\n \n\n pull_parameters = dict()\n for parameter in ('country', 'results_per_page', 'what', 'what_and', 'what_phrase', 'what_or', 'what_exclude', 'title_only', 'where', 'distance', 'location0', 'location1', 'location2', 'location3', 'location4', 'location5', 'location6', 'location7', 'max_days_old', 'category', 'sort_dir', 'sort_by', 'salary_min', 'salary_max', 'salary_include_unknown', 'full_time', 'part_time', 'contract', 'permanent', 'company'):\n parameter_name = \"{}{}\".format(PULL_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n pull_parameters[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n pull_parameters[parameter] = _request[parameter_name]\n \n\n push_parameters = dict()\n for parameter in ('board_key',):\n parameter_name = \"{}{}\".format(PUSH_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n push_parameters[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n push_parameters[parameter] = _request[parameter_name]\n \n\n incremental = settings.get(\"__incremental\")\n\n return Adzuna.update_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=connector_auth,\n hrflow_auth=hrflow_auth,\n pull_parameters=pull_parameters,\n push_parameters=push_parameters,\n logics=globals().get(\"logics\"),\n format=globals().get(\"format\"),\n callback=globals().get(\"callback\"),\n incremental=incremental == \"enable\",\n )", + "pull_template": "import typing as t\n\nfrom hrflow_connectors.v2 import Adzuna\nfrom hrflow_connectors.v2.core.run import ActionInitError, Reason\n\nCONNECTOR_AUTH_SETTINGS_PREFIX = \"connector_auth_\"\nHRFLOW_AUTH_SETTINGS_PREFIX = \"hrflow_auth_\"\nPULL_PARAMETERS_SETTINGS_PREFIX = \"pull_parameters_\"\nPUSH_PARAMETERS_SETTINGS_PREFIX = \"push_parameters_\"\n\n# << format_placeholder >>\n\n# << logics_placeholder >>\n\n# << callback_placeholder >>\n\n\n\ndef workflow(\n \n settings: dict\n ) -> None:\n if \"__workflow_id\" not in settings:\n return Adzuna.update_jobs_in_hrflow(\n workflow_id=\"\",\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.workflow_id_not_found,\n data=dict(error=\"__workflow_id not found in settings\", settings_keys=list(settings.keys())),\n )\n )\n workflow_id = settings[\"__workflow_id\"]\n\n \n\n connector_auth = dict()\n for parameter in ('app_id', 'app_key'):\n parameter_name = \"{}{}\".format(CONNECTOR_AUTH_SETTINGS_PREFIX, parameter) \n if parameter_name in settings:\n connector_auth[parameter] = settings[parameter_name]\n \n\n hrflow_auth = dict()\n for parameter in ('api_secret', 'api_user'):\n parameter_name = \"{}{}\".format(HRFLOW_AUTH_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n hrflow_auth[parameter] = settings[parameter_name]\n \n\n pull_parameters = dict()\n for parameter in ('country', 'results_per_page', 'what', 'what_and', 'what_phrase', 'what_or', 'what_exclude', 'title_only', 'where', 'distance', 'location0', 'location1', 'location2', 'location3', 'location4', 'location5', 'location6', 'location7', 'max_days_old', 'category', 'sort_dir', 'sort_by', 'salary_min', 'salary_max', 'salary_include_unknown', 'full_time', 'part_time', 'contract', 'permanent', 'company'):\n parameter_name = \"{}{}\".format(PULL_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n pull_parameters[parameter] = settings[parameter_name]\n \n\n push_parameters = dict()\n for parameter in ('board_key',):\n parameter_name = \"{}{}\".format(PUSH_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n push_parameters[parameter] = settings[parameter_name]\n \n\n incremental = settings.get(\"__incremental\")\n\n return Adzuna.update_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=connector_auth,\n hrflow_auth=hrflow_auth,\n pull_parameters=pull_parameters,\n push_parameters=push_parameters,\n logics=globals().get(\"logics\"),\n format=globals().get(\"format\"),\n callback=globals().get(\"callback\"),\n incremental=incremental == \"enable\",\n )", + "settings_keys": { + "workflow_id": "__workflow_id", + "incremental": "__incremental", + "connector_auth_prefix": "connector_auth_", + "hrflow_auth_prefix": "hrflow_auth_", + "pull_parameters_prefix": "pull_parameters_", + "push_parameters_prefix": "push_parameters_" + }, + "placeholders": { + "logics": "# << logics_placeholder >>", + "format": "# << format_placeholder >>", + "callback": "# << callback_placeholder >>", + "event_parser": "# << event_parser_placeholder >>" + }, + "expected": { + "activate_incremental": "enable", + "logics_functions_name": "logics", + "format_functions_name": "format", + "callback_functions_name": "callback", + "event_parser_function_name": "event_parser" + } + } + }, + { + "name": "archive_jobs_in_hrflow", + "data_type": "job", + "direction": "inbound", + "mode": "archive", + "connector_auth_parameters": { + "title": "AuthParameters", + "type": "object", + "properties": { + "app_id": { + "description": "Application ID, supplied by Adzuna", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "app_key": { + "description": "Application key, supplied by Adzuna", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "app_id", + "app_key" + ], + "$defs": {} + }, + "hrflow_auth_parameters": { + "title": "AuthParameters", + "type": "object", + "properties": { + "api_secret": { + "description": "API Key used to access HrFlow.ai API", + "type": "string" + }, + "api_user": { + "description": "User email used to access HrFlow.ai API", + "type": "string" + } + }, + "required": [ + "api_secret", + "api_user" + ], + "$defs": {} + }, + "origin": "Adzuna", + "origin_data_schema": { + "title": "AdzunaJob", + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "created": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "full_description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "redirect_url": { + "type": "string" + }, + "latitude": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "longitude": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] + }, + "category": { + "$ref": "#/$defs/Category" + }, + "location": { + "$ref": "#/$defs/Location" + }, + "salary_min": { + "type": "integer" + }, + "salary_max": { + "type": "integer" + }, + "salary_is_predicted": { + "$ref": "#/$defs/Flag" + }, + "company": { + "$ref": "#/$defs/Company" + }, + "contract_type": { + "anyOf": [ + { + "$ref": "#/$defs/ContractType" + }, + { + "type": "null" + } + ] + }, + "contract_time": { + "anyOf": [ + { + "$ref": "#/$defs/ContractTime" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "id", + "created", + "title", + "description", + "full_description", + "redirect_url", + "latitude", + "longitude", + "category", + "location", + "salary_min", + "salary_max", + "salary_is_predicted", + "company", + "contract_type", + "contract_time" + ], + "$defs": { + "Category": { + "title": "Category", + "type": "object", + "properties": { + "tag": { + "type": "string" + }, + "label": { + "type": "string" + } + }, + "required": [ + "tag", + "label" + ] + }, + "Location": { + "title": "Location", + "type": "object", + "properties": { + "area": { + "type": "array", + "items": { + "type": "string" + } + }, + "display_name": { + "type": "string" + } + }, + "required": [ + "area", + "display_name" + ] + }, + "Flag": { + "title": "Flag", + "enum": [ + "0", + "1" + ] + }, + "Company": { + "title": "Company", + "type": "object", + "properties": { + "display_name": { + "type": "string" + }, + "canonical_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "count": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "display_name", + "canonical_name", + "count" + ] + }, + "ContractType": { + "title": "ContractType", + "enum": [ + "contract", + "permanent" + ] + }, + "ContractTime": { + "title": "ContractTime", + "enum": [ + "full_time", + "part_time" + ] + } + } + }, + "supports_incremental": false, + "pull_parameters": { + "title": "ReadJobsParameters", + "type": "object", + "properties": { + "country": { + "description": "ISO 8601 country code of the country of interest", + "$ref": "#/$defs/CountryCode" + }, + "results_per_page": { + "description": "The number of results to include on a page of search results.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": 50 + }, + "what": { + "description": "The keywords to search for. Multiple terms may be space separated.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "what_and": { + "description": "The keywords to search for, all keywords must be found.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "what_phrase": { + "description": "An entire phrase which must be found in the description or title.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "what_or": { + "description": "The keywords to search for, any keywords may be found. Multiple terms may be space separated.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "what_exclude": { + "description": "Keywords to exclude from the search. Multiple terms may be space separated.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "title_only": { + "description": "Keywords to find, but only in the title. Multiple terms may be space separated.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "where": { + "description": "The geographic centre of the search. Place names, postal codes, etc. may be used.\t", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "distance": { + "description": "The distance in kilometres from the centre of the place described by the 'where' parameter. Defaults to 5km.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "location0": { + "description": "The location fields may be used to describe a location, in a similar form to that returned in a Adzuna::API::Response::Location object.For example, \"location0=UK&location1=South East England&location2=Surrey\" will performn a search over the county of Surrey.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location1": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location2": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location3": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location4": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location5": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location6": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "location7": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "max_days_old": { + "description": "The age of the oldest advertisment in days that will be returned.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "category": { + "description": "The category tag, as returned by the \"category\" endpoint.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "sort_dir": { + "description": "The direction to order the search results.", + "anyOf": [ + { + "$ref": "#/$defs/SortDir" + }, + { + "type": "null" + } + ], + "default": null + }, + "sort_by": { + "description": "The ordering of the search results.", + "anyOf": [ + { + "$ref": "#/$defs/SortKey" + }, + { + "type": "null" + } + ], + "default": null + }, + "salary_min": { + "description": "The minimum salary we wish to get results for.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "salary_max": { + "description": "The maximum salary we wish to get results for.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "salary_include_unknown": { + "description": "If set it \"1\", jobs without a known salary are returned.", + "anyOf": [ + { + "$ref": "#/$defs/Filter" + }, + { + "type": "null" + } + ], + "default": null + }, + "full_time": { + "description": "If set to \"1\", only full time jobs will be returned.", + "anyOf": [ + { + "$ref": "#/$defs/Filter" + }, + { + "type": "null" + } + ], + "default": null + }, + "part_time": { + "description": "If set to \"1\", only part time jobs will be returned.", + "anyOf": [ + { + "$ref": "#/$defs/Filter" + }, + { + "type": "null" + } + ], + "default": null + }, + "contract": { + "description": "If set to \"1\", only contract jobs will be returned.", + "anyOf": [ + { + "$ref": "#/$defs/Filter" + }, + { + "type": "null" + } + ], + "default": null + }, + "permanent": { + "description": "If set to \"1\", only permanent jobs will be returned.", + "anyOf": [ + { + "$ref": "#/$defs/Filter" + }, + { + "type": "null" + } + ], + "default": null + }, + "company": { + "description": "The canonical company name. This may be returned in a Adzuna::API::Response::Company object when a job is returned. A full list of allowed terms in not available through the API.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "country" + ], + "$defs": { + "CountryCode": { + "title": "CountryCode", + "enum": [ + "at", + "au", + "br", + "ca", + "de", + "fr", + "gb", + "in", + "it", + "nl", + "nz", + "pl", + "ru", + "sg", + "us", + "za" + ] + }, + "SortDir": { + "title": "SortDir", + "enum": [ + "down", + "up" + ] + }, + "SortKey": { + "title": "SortKey", + "enum": [ + "date", + "default", + "hybrid", + "relevance", + "salary" + ] + }, + "Filter": { + "title": "Filter", + "enum": [ + "1" + ] + } + } + }, + "target": "HrFlow", + "target_data_schema": { + "title": "HrFlowJob", + "type": "object", + "properties": { + "key": { + "description": "Identification key of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "description": "Custom identifier of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "name": { + "description": "Job title.", + "type": "string" + }, + "location": { + "description": "Job location object.", + "$ref": "#/$defs/Location" + }, + "sections": { + "description": "Job custom sections.", + "type": "array", + "items": { + "$ref": "#/$defs/Section" + } + }, + "url": { + "description": "Job post original URL.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "summary": { + "description": "Brief summary of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "archieved_at": { + "description": "type: datetime ISO8601, Archive date of the Job. The value is null for unarchived Jobs.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "updated_at": { + "description": "type: datetime ISO8601, Last update date of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "created_at": { + "description": "type: datetime ISO8601, Creation date of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "skills": { + "description": "list of skills of the Job.", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Skill" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "languages": { + "description": "list of spoken languages of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "certifications": { + "description": "list of certifications of the Job.", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "courses": { + "description": "list of courses of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "tasks": { + "description": "list of tasks of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "tags": { + "description": "list of tags of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "metadatas": { + "description": "list of metadatas of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "ranges_float": { + "description": "list of ranges of floats", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/RangesFloat" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "ranges_date": { + "description": "list of ranges of dates", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/RangesDate" + } + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name", + "location", + "sections" + ], + "$defs": { + "Location": { + "title": "Location", + "type": "object", + "properties": { + "text": { + "description": "Location text address.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "lat": { + "description": "Geocentric latitude of the Location.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "lng": { + "description": "Geocentric longitude of the Location.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "fields": { + "description": "other location attributes like country, country_code etc", + "anyOf": [ + { + "type": "object" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "Section": { + "title": "Section", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Section of the Job. Example: culture", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "title": { + "description": "Display Title of a Section. Example: Corporate Culture", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "description": { + "description": "Text description of a Section: Example: Our values areNone", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "Skill": { + "title": "Skill", + "type": "object", + "properties": { + "name": { + "description": "Identification name of the skill", + "type": "string" + }, + "type": { + "description": "Type of the skill. hard or soft", + "enum": [ + "hard", + "soft" + ] + }, + "value": { + "description": "Value associated to the skill", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name", + "type" + ] + }, + "GeneralEntitySchema": { + "title": "GeneralEntitySchema", + "type": "object", + "properties": { + "name": { + "description": "Identification name of the Object", + "type": "string" + }, + "value": { + "description": "Value associated to the Object's name", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name" + ] + }, + "RangesFloat": { + "title": "RangesFloat", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Range of floats attached to the Job. Example: salary", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_min": { + "description": "Min value. Example: 500.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_max": { + "description": "Max value. Example: 100.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "unit": { + "description": "Unit of the value. Example: euros.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "RangesDate": { + "title": "RangesDate", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Range of dates attached to the Job. Example: availability.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_min": { + "description": "Min value in datetime ISO 8601, Example: 500.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_max": { + "description": "Max value in datetime ISO 8601, Example: 1000", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + } + } + }, + "push_parameters": { + "title": "ArchiveCriterias", + "type": "object", + "properties": { + "board_key": { + "description": "HrFlow.ai board key", + "type": "string" + } + }, + "required": [ + "board_key" + ], + "$defs": {} + }, + "jsonmap": { + "reference": "?.id | $string" + }, + "workflow": { + "catch_template": "import typing as t\n\nfrom hrflow_connectors.v2 import Adzuna\nfrom hrflow_connectors.v2.core.run import ActionInitError, Reason\n\nCONNECTOR_AUTH_SETTINGS_PREFIX = \"connector_auth_\"\nHRFLOW_AUTH_SETTINGS_PREFIX = \"hrflow_auth_\"\nPULL_PARAMETERS_SETTINGS_PREFIX = \"pull_parameters_\"\nPUSH_PARAMETERS_SETTINGS_PREFIX = \"push_parameters_\"\n\n# << format_placeholder >>\n\n# << logics_placeholder >>\n\n# << callback_placeholder >>\n\n\n\n\n# << event_parser_placeholder >>\n\n\n\ndef workflow(\n \n _request: dict,\n \n settings: dict\n ) -> None:\n if \"__workflow_id\" not in settings:\n return Adzuna.archive_jobs_in_hrflow(\n workflow_id=\"\",\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.workflow_id_not_found,\n data=dict(error=\"__workflow_id not found in settings\", settings_keys=list(settings.keys())),\n )\n )\n workflow_id = settings[\"__workflow_id\"]\n\n \n event_parser = globals().get(\"event_parser\", globals().get(\"default_event_parser\"))\n\n if event_parser is not None:\n try:\n _request = event_parser(_request)\n except Exception as e:\n return Adzuna.archive_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.event_parsing_failure,\n data=dict(error=e, event=_request),\n )\n )\n \n\n connector_auth = dict()\n for parameter in ('app_id', 'app_key'):\n parameter_name = \"{}{}\".format(CONNECTOR_AUTH_SETTINGS_PREFIX, parameter) \n if parameter_name in settings:\n connector_auth[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n connector_auth[parameter] = _request[parameter_name]\n \n\n hrflow_auth = dict()\n for parameter in ('api_secret', 'api_user'):\n parameter_name = \"{}{}\".format(HRFLOW_AUTH_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n hrflow_auth[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n hrflow_auth[parameter] = _request[parameter_name]\n \n\n pull_parameters = dict()\n for parameter in ('country', 'results_per_page', 'what', 'what_and', 'what_phrase', 'what_or', 'what_exclude', 'title_only', 'where', 'distance', 'location0', 'location1', 'location2', 'location3', 'location4', 'location5', 'location6', 'location7', 'max_days_old', 'category', 'sort_dir', 'sort_by', 'salary_min', 'salary_max', 'salary_include_unknown', 'full_time', 'part_time', 'contract', 'permanent', 'company'):\n parameter_name = \"{}{}\".format(PULL_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n pull_parameters[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n pull_parameters[parameter] = _request[parameter_name]\n \n\n push_parameters = dict()\n for parameter in ('board_key',):\n parameter_name = \"{}{}\".format(PUSH_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n push_parameters[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n push_parameters[parameter] = _request[parameter_name]\n \n\n incremental = settings.get(\"__incremental\")\n\n return Adzuna.archive_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=connector_auth,\n hrflow_auth=hrflow_auth,\n pull_parameters=pull_parameters,\n push_parameters=push_parameters,\n logics=globals().get(\"logics\"),\n format=globals().get(\"format\"),\n callback=globals().get(\"callback\"),\n incremental=incremental == \"enable\",\n )", + "pull_template": "import typing as t\n\nfrom hrflow_connectors.v2 import Adzuna\nfrom hrflow_connectors.v2.core.run import ActionInitError, Reason\n\nCONNECTOR_AUTH_SETTINGS_PREFIX = \"connector_auth_\"\nHRFLOW_AUTH_SETTINGS_PREFIX = \"hrflow_auth_\"\nPULL_PARAMETERS_SETTINGS_PREFIX = \"pull_parameters_\"\nPUSH_PARAMETERS_SETTINGS_PREFIX = \"push_parameters_\"\n\n# << format_placeholder >>\n\n# << logics_placeholder >>\n\n# << callback_placeholder >>\n\n\n\ndef workflow(\n \n settings: dict\n ) -> None:\n if \"__workflow_id\" not in settings:\n return Adzuna.archive_jobs_in_hrflow(\n workflow_id=\"\",\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.workflow_id_not_found,\n data=dict(error=\"__workflow_id not found in settings\", settings_keys=list(settings.keys())),\n )\n )\n workflow_id = settings[\"__workflow_id\"]\n\n \n\n connector_auth = dict()\n for parameter in ('app_id', 'app_key'):\n parameter_name = \"{}{}\".format(CONNECTOR_AUTH_SETTINGS_PREFIX, parameter) \n if parameter_name in settings:\n connector_auth[parameter] = settings[parameter_name]\n \n\n hrflow_auth = dict()\n for parameter in ('api_secret', 'api_user'):\n parameter_name = \"{}{}\".format(HRFLOW_AUTH_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n hrflow_auth[parameter] = settings[parameter_name]\n \n\n pull_parameters = dict()\n for parameter in ('country', 'results_per_page', 'what', 'what_and', 'what_phrase', 'what_or', 'what_exclude', 'title_only', 'where', 'distance', 'location0', 'location1', 'location2', 'location3', 'location4', 'location5', 'location6', 'location7', 'max_days_old', 'category', 'sort_dir', 'sort_by', 'salary_min', 'salary_max', 'salary_include_unknown', 'full_time', 'part_time', 'contract', 'permanent', 'company'):\n parameter_name = \"{}{}\".format(PULL_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n pull_parameters[parameter] = settings[parameter_name]\n \n\n push_parameters = dict()\n for parameter in ('board_key',):\n parameter_name = \"{}{}\".format(PUSH_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n push_parameters[parameter] = settings[parameter_name]\n \n\n incremental = settings.get(\"__incremental\")\n\n return Adzuna.archive_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=connector_auth,\n hrflow_auth=hrflow_auth,\n pull_parameters=pull_parameters,\n push_parameters=push_parameters,\n logics=globals().get(\"logics\"),\n format=globals().get(\"format\"),\n callback=globals().get(\"callback\"),\n incremental=incremental == \"enable\",\n )", + "settings_keys": { + "workflow_id": "__workflow_id", + "incremental": "__incremental", + "connector_auth_prefix": "connector_auth_", + "hrflow_auth_prefix": "hrflow_auth_", + "pull_parameters_prefix": "pull_parameters_", + "push_parameters_prefix": "push_parameters_" + }, + "placeholders": { + "logics": "# << logics_placeholder >>", + "format": "# << format_placeholder >>", + "callback": "# << callback_placeholder >>", + "event_parser": "# << event_parser_placeholder >>" + }, + "expected": { + "activate_incremental": "enable", + "logics_functions_name": "logics", + "format_functions_name": "format", + "callback_functions_name": "callback", + "event_parser_function_name": "event_parser" + } + } + } + ] + }, + { + "name": "France Travail (ex: Pole Emploi)", + "type": "JOBBOARD", + "subtype": "francetravail", + "logo": "https://raw.githubusercontent.com/Riminder/hrflow-connectors/master/src/hrflow_connectors/v2/connectors/francetravail/logo.png", + "actions": [ + { + "name": "create_jobs_in_hrflow", + "data_type": "job", + "direction": "inbound", + "mode": "create", + "connector_auth_parameters": { + "title": "AuthParameters", + "type": "object", + "properties": { + "client_id": { + "description": "Client ID used to access France Travail (ex: Pole Emploi) API", + "type": "string" + }, + "client_secret": { + "description": "Client Secret used to access France Travail (ex: Pole Emploi) API", + "type": "string" + } + }, + "required": [ + "client_id", + "client_secret" + ], + "$defs": {} + }, + "hrflow_auth_parameters": { + "title": "AuthParameters", + "type": "object", + "properties": { + "api_secret": { + "description": "API Key used to access HrFlow.ai API", + "type": "string" + }, + "api_user": { + "description": "User email used to access HrFlow.ai API", + "type": "string" + } + }, + "required": [ + "api_secret", + "api_user" + ], + "$defs": {} + }, + "origin": "France Travail (ex: Pole Emploi)", + "origin_data_schema": { + "title": "FranceTravailJobOffer", + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "intitule": { + "type": "string" + }, + "description": { + "type": "string" + }, + "dateCreation": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "dateActualisation": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "lieuTravail": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/JobLocation" + } + ], + "default": null + }, + "romeCode": { + "description": "ROME code of the professionA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/metiers", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "romeLibelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "appellationLibelle": { + "description": "Code of the appellationA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/appellations", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "entreprise": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/Entreprise" + } + ], + "default": null + }, + "typeContrat": { + "description": "Contract type codeA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/typesContrats", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "typeContratLibelle": { + "description": "Contract type labelExample : CDI,CDDA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/typesContrats", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "natureContrat": { + "description": "Code of the nature of contractA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/naturesContrats", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "origineOffre": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/OfferOrigin" + } + ], + "default": null + }, + "offresManqueCandidats": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "experienceExige": { + "anyOf": [ + { + "$ref": "#/$defs/ExperienceRequirement" + }, + { + "type": "null" + } + ], + "default": null + }, + "experienceLibelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "experienceCommentaire": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "formations": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Formation" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "langues": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Langue" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "permis": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Permis" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "outilsBureautiques": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "competences": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Competence" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "salaire": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/Salaire" + } + ], + "default": null + }, + "dureeTravailLibelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeTravailLibelleConverti": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "complementExercice": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "conditionExercice": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "alternance": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "contact": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/Contact" + } + ], + "default": null + }, + "agence": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/Agence" + } + ], + "default": null + }, + "nombrePostes": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "accessibleTH": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "deplacementCode": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "deplacementLibelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "qualificationCode": { + "anyOf": [ + { + "$ref": "#/$defs/QualificationCode" + }, + { + "type": "null" + } + ], + "default": null + }, + "qualificationLibelle": { + "anyOf": [ + { + "$ref": "#/$defs/QualificationLibelle" + }, + { + "type": "null" + } + ], + "default": null + }, + "secteurActivite": { + "description": "NAF codes for sectors of activity. It is possible to specify two NAF codes by separating them with a comma in the character string.Example : 01,02A GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/secteursActivites", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "secteurActiviteLibelle": { + "description": "Sector of activitylabelA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/secteursActivites", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "qualitesProfessionnelles": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/QualitePro" + } + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "id", + "intitule", + "description" + ], + "$defs": { + "JobLocation": { + "title": "JobLocation", + "type": "object", + "properties": { + "libelle": { + "type": "string" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "codepostal": { + "type": "string" + }, + "commune": { + "description": "INSEE code of the communeA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/communes", + "type": "string" + } + }, + "required": [ + "libelle", + "latitude", + "longitude", + "codepostal", + "commune" + ] + }, + "Entreprise": { + "title": "Entreprise", + "type": "object", + "properties": { + "nom": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "logo": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "entrepriseAdaptee": { + "type": "boolean" + } + }, + "required": [ + "nom", + "description", + "logo", + "url", + "entrepriseAdaptee" + ] + }, + "OfferOrigin": { + "title": "OfferOrigin", + "type": "object", + "properties": { + "origine": { + "$ref": "#/$defs/OfferOriginTag" + }, + "urlOrigine": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "partenaires": { + "type": "array", + "items": { + "$ref": "#/$defs/Partner" + } + } + }, + "required": [ + "origine", + "urlOrigine", + "partenaires" + ] + }, + "OfferOriginTag": { + "title": "OfferOriginTag", + "enum": [ + 1, + 2 + ] + }, + "Partner": { + "title": "Partner", + "type": "object", + "properties": { + "nom": { + "type": "string" + }, + "url": { + "type": "string" + }, + "logo": { + "type": "string" + } + }, + "required": [ + "nom", + "url", + "logo" + ] + }, + "ExperienceRequirement": { + "title": "ExperienceRequirement", + "enum": [ + "D", + "E", + "S" + ] + }, + "Formation": { + "title": "Formation", + "type": "object", + "properties": { + "domaineLibelle": { + "type": "string" + }, + "niveauLibelle": { + "description": "Label of the level of the education requiredA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/referentiel/niveauxFormations", + "type": "string" + }, + "commentaire": { + "type": "string" + }, + "exigence": { + "$ref": "#/$defs/Exigence" + } + }, + "required": [ + "domaineLibelle", + "niveauLibelle", + "commentaire", + "exigence" + ] + }, + "Exigence": { + "title": "Exigence", + "enum": [ + "E", + "S" + ] + }, + "Langue": { + "title": "Langue", + "type": "object", + "properties": { + "libelle": { + "description": "Language labelA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/referentiel/langues", + "type": "string" + }, + "exigence": { + "anyOf": [ + { + "$ref": "#/$defs/Exigence" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "libelle", + "exigence" + ] + }, + "Permis": { + "title": "Permis", + "type": "object", + "properties": { + "libelle": { + "description": "requested licenseA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/referentiel/permis", + "type": "string" + }, + "exigence": { + "anyOf": [ + { + "$ref": "#/$defs/Exigence" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "libelle", + "exigence" + ] + }, + "Competence": { + "title": "Competence", + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "libelle": { + "type": "string" + }, + "exigence": { + "anyOf": [ + { + "$ref": "#/$defs/Exigence" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "code", + "libelle", + "exigence" + ] + }, + "Salaire": { + "title": "Salaire", + "type": "object", + "properties": { + "libelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "commentaire": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "complement1": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "complement2": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "libelle", + "commentaire", + "complement1", + "complement2" + ] + }, + "Contact": { + "title": "Contact", + "type": "object", + "properties": { + "nom": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "coordonnees1": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "coordonnees2": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "coordonnees3": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "telephone": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "courriel": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "commentaire": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "urlRecruteur": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "urlPostulation": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "nom", + "coordonnees1", + "coordonnees2", + "coordonnees3", + "telephone", + "courriel", + "commentaire", + "urlRecruteur", + "urlPostulation" + ] + }, + "Agence": { + "title": "Agence", + "type": "object", + "properties": { + "telephone": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "courriel": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "telephone", + "courriel" + ] + }, + "QualificationCode": { + "title": "QualificationCode", + "enum": [ + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9" + ] + }, + "QualificationLibelle": { + "title": "QualificationLibelle", + "enum": [ + "Agent de ma\u00eetrise", + "Cadre", + "Employ\u00e9 non qualifi\u00e9", + "Employ\u00e9 qualifi\u00e9", + "Man\u0153uvre", + "Ouvrier qualifi\u00e9 (P1, P2)", + "Ouvrier qualifi\u00e9 (P3, P4, OHQ)", + "Ouvrier sp\u00e9cialis\u00e9", + "Technicien" + ] + }, + "QualitePro": { + "title": "QualitePro", + "type": "object", + "properties": { + "libelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "libelle", + "description" + ] + } + } + }, + "supports_incremental": false, + "pull_parameters": { + "title": "ReadJobsParameters", + "type": "object", + "properties": { + "range": { + "description": "Pagination of data. The range of results is limited to 150. Format: p-d, where :\n\np is the index (starting at 0) of the first element requested, which must not exceed 3000\nd is the index of the last element requested, which must not exceed 3149", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "sort": { + "description": "Sorting of data", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "domaine": { + "description": "Professional field codeA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint :https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//domaines", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "codeROME": { + "description": "ROME code of the professionA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//metiers", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "theme": { + "description": "Theme of the professionA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//themes", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "appellation": { + "description": "ROME designation code for the offer, see reference belowA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//appellations", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "codeNAF": { + "description": "NAF code of the offer (format 99.99X)A GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//nafs", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "secteurActivite": { + "description": "NAF codes for sectors of activity. It is possible to specify two NAF codes by separating them with a comma in the character string.Example : 01,02A GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//secteursActivites", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "experience": { + "description": "Level of experience required\nPossible values:\n1 -> Less than 1 year of experience\n2 -> From 1 to 3 years of experience\n3 -> More than 3 years of experience", + "anyOf": [ + { + "$ref": "#/$defs/Experience" + }, + { + "type": "null" + } + ], + "default": null + }, + "experienceExigence": { + "description": "Filter offers by experience requirement (D beginner accepted, S experience desired, E experience required)", + "anyOf": [ + { + "$ref": "#/$defs/ExperienceRequirement" + }, + { + "type": "null" + } + ], + "default": null + }, + "typeContrat": { + "description": "Contract type codeExample : CDI,CDDA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//typesContrats", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "natureContrat": { + "description": "Code of the nature of contractA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//naturesContrats", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "origineOffre": { + "description": "Origin of the offer\nPossible values:\n1 -> Job center\n2 -> Partner", + "anyOf": [ + { + "$ref": "#/$defs/OfferOriginTag" + }, + { + "type": "null" + } + ], + "default": null + }, + "qualification": { + "description": "Qualification Code\nPossible values:\n0 -> Non-executive\n9 -> Executive", + "anyOf": [ + { + "$ref": "#/$defs/Qualification" + }, + { + "type": "null" + } + ], + "default": null + }, + "tempsPlein": { + "description": "Promote the use of the WeeklyDuration filter\nPossible values:\nfalse -> Part-time\ntrue -> Full time\nIf the parameter is not filled, then all the offers are returned", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "commune": { + "description": "INSEE code of the communeA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//communes", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "distance": { + "description": "Kilometric distance of the search radius\nDefault value: 10Note: to obtain only the offers of a specific commune, then you must fill in the parameter 'distance=0'.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "departement": { + "description": "Job departmentA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//departements", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "inclureLimitrophes": { + "description": "Include bordering departments in the search", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "region": { + "description": "Code of the region of the offerA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//regions", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "paysContinent": { + "description": "Code of the country or continent of the offerA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//paysAND https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//continents", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "niveauFormation": { + "description": "Level of education requiredA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//niveauxFormations", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "permis": { + "description": "Code of the requested licenseA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//permis", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "motsCles": { + "description": "Search by keyword\n\nEach keyword (or expression) is at least 2 characters long and must\nbe separated by a comma.\nThe search on several keywords is processed via the logical operator \"AND\".\nThe keyword search can be used to search on :\n\n- The title of the offer (title field in the search return)\n- The ROME code (romeCode field in the search return)\n- The ROME label (field romeLibelle in return for the search)\n- The competences label (field competences.libelle in return of the search)\n- The wording of the training fields (field formations.domaineLibelle in\nreturn of the research)\n- The wording of the permits (field permits.label in return of the search)\n- The language label (field languages.label in return of the search)\n- The offer description if found in the offer title and/or the ROME label\n(description field in the search return)\n\nAllowed characters: [aA-zZ]+[0-9]+[space]+[@#$%^&+./-\"\"]", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "salaireMin": { + "description": "Minimum wage, expressed in Euro.If this data is filled in, the code of the type of minimum wage is mandatory.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "periodeSalaire": { + "description": "Period for the calculation of the minimum wage.\nIf this data is filled in, the minimum wage is mandatory.\nPossible values:\nM -> Monthly\nA -> Annual\nH -> Hourly\nC -> Fee", + "anyOf": [ + { + "$ref": "#/$defs/SalaryPeriod" + }, + { + "type": "null" + } + ], + "default": null + }, + "accesTravailleurHandicape": { + "description": "Jobs for which the employer is disabled-friendly", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "offresMRS": { + "description": " Allows you to search for jobs that offer the simulation recruitment method", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "grandDomaine": { + "description": "Code of the major area of the offer", + "anyOf": [ + { + "$ref": "#/$defs/IndustryDomain" + }, + { + "type": "null" + } + ], + "default": null + }, + "experienceExige": { + "description": "Filter offers by experience level.", + "anyOf": [ + { + "$ref": "#/$defs/ExperienceRequirement" + }, + { + "type": "null" + } + ], + "default": null + }, + "publieeDepuis": { + "description": "Maximum number of days since the publication of the offer\nPossible values: 1, 3, 7, 14, 31", + "anyOf": [ + { + "$ref": "#/$defs/PublishedSince" + }, + { + "type": "null" + } + ], + "default": null + }, + "minCreationDate": { + "description": "Minimum offer creation date.\nIf this data is filled in, the maximum offer creation date is mandatory.\nISO-8601 standard (YYYY-MM-DDTHH:MM:SSZ)", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "maxCreationDate": { + "description": "Maximum offer creation date.\nIf this data is filled in, the minimum offer creation date is mandatory.\nISO-8601 standard (YYYY-MM-DDTHH:MM:SSZ)", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "partenaires": { + "description": " This filter allows you to enter your partner code in order to include or exclude your offers from the results according to the selectionmade in the PartnerSelection mode filter\nIt is possible to enter several codes (separator ','). ", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "modeSelectionPartenaires": { + "description": "Selection mode of the partner offers.\n\nThis filter works with the partner criterion and is dependent on the originOffer\ncriterion. Possible values with the results obtained according to the two other filters:\n\n- INCLUS(INCLUDED)\noriginOffer empty : Returns the PE offers and the Partners listed in the Partners\ncriterion\noriginOffer at 2 : Only the offers of the Partners listed in the Partners\ncriterion\n- EXCLU(EXCLUDED)\noriginOffer empty : Return the offers of PE and Partners not listed in the Partners\ncriterion\noriginOffer at 2 : Only the offers of the Partners not listed in the Partners\ncriterion\nNote: In all cases, if originOffer = 1, then only the France Travail (ex: Pole Emploi)\noffers will be returned", + "anyOf": [ + { + "$ref": "#/$defs/PartnerSelectionMode" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeHebdo": { + "description": "Filtre les offres selon la dur\u00e9e hebdomadaire.\nValeurs possibles :\n0 -> Non pr\u00e9cis\u00e9\n1 -> Temps plein\n2 -> Temps partiel", + "anyOf": [ + { + "$ref": "#/$defs/WeeklyDuration" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeHebdoMin": { + "description": "Minimum weekly duration of the offer\nThe value must be in HHMM format, for example : 8h => 800 ; 24h30 => 2430", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeHebdoMax": { + "description": "Maximum weekly duration of the offer\nThe value must be in HHMM format, for example: 8h => 800; 24h30 => 2430", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeContratMin": { + "description": "Minimum duration of the sought contract.\nThe search is done in months (ex: 0.5 for 15 days, 1.0 for 1 month,2.0 for 2 months).\nPositive decimal (Decimal separator: '.')", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeContratMax": { + "description": "Maximum duration of the sought contract.\nThe search is made in months (ex: 0.5 for 15 days, 1.0 for 1 month,2.0 for 2 months).\nPositive decimal (Decimal separator: '.')", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "offresManqueCandidats": { + "description": "Filters offers older than 15 days, with less than 4 applications (of which P\u00f4le emploi is informed)\nfalse -> Offers not concerned\ntrue -> Offers with few candidates", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "entreprisesAdaptees": { + "description": "Filter the offers where the adapted company allows a disabled worker to exercise a professional activity in conditions adapted to his capacities\nfalse -> Offers not concerned\ntrue -> Offers from adapted companies", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [], + "$defs": { + "Experience": { + "title": "Experience", + "enum": [ + "1", + "2", + "3" + ] + }, + "ExperienceRequirement": { + "title": "ExperienceRequirement", + "enum": [ + "D", + "E", + "S" + ] + }, + "OfferOriginTag": { + "title": "OfferOriginTag", + "enum": [ + 1, + 2 + ] + }, + "Qualification": { + "title": "Qualification", + "enum": [ + 0, + 9 + ] + }, + "SalaryPeriod": { + "title": "SalaryPeriod", + "enum": [ + "A", + "C", + "H", + "M" + ] + }, + "IndustryDomain": { + "title": "IndustryDomain", + "enum": [ + "A", + "B", + "C", + "C15", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "L14", + "M", + "M13", + "M14", + "M15", + "M16", + "M17", + "M18", + "N" + ] + }, + "PublishedSince": { + "title": "PublishedSince", + "enum": [ + 1, + 3, + 7, + 14, + 31 + ] + }, + "PartnerSelectionMode": { + "title": "PartnerSelectionMode", + "enum": [ + "EXCLU", + "INCLUS" + ] + }, + "WeeklyDuration": { + "title": "WeeklyDuration", + "enum": [ + "0", + "1", + "2" + ] + } + } + }, + "target": "HrFlow", + "target_data_schema": { + "title": "HrFlowJob", + "type": "object", + "properties": { + "key": { + "description": "Identification key of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "description": "Custom identifier of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "name": { + "description": "Job title.", + "type": "string" + }, + "location": { + "description": "Job location object.", + "$ref": "#/$defs/Location" + }, + "sections": { + "description": "Job custom sections.", + "type": "array", + "items": { + "$ref": "#/$defs/Section" + } + }, + "url": { + "description": "Job post original URL.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "summary": { + "description": "Brief summary of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "archieved_at": { + "description": "type: datetime ISO8601, Archive date of the Job. The value is null for unarchived Jobs.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "updated_at": { + "description": "type: datetime ISO8601, Last update date of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "created_at": { + "description": "type: datetime ISO8601, Creation date of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "skills": { + "description": "list of skills of the Job.", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Skill" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "languages": { + "description": "list of spoken languages of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "certifications": { + "description": "list of certifications of the Job.", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "courses": { + "description": "list of courses of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "tasks": { + "description": "list of tasks of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "tags": { + "description": "list of tags of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "metadatas": { + "description": "list of metadatas of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "ranges_float": { + "description": "list of ranges of floats", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/RangesFloat" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "ranges_date": { + "description": "list of ranges of dates", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/RangesDate" + } + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name", + "location", + "sections" + ], + "$defs": { + "Location": { + "title": "Location", + "type": "object", + "properties": { + "text": { + "description": "Location text address.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "lat": { + "description": "Geocentric latitude of the Location.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "lng": { + "description": "Geocentric longitude of the Location.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "fields": { + "description": "other location attributes like country, country_code etc", + "anyOf": [ + { + "type": "object" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "Section": { + "title": "Section", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Section of the Job. Example: culture", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "title": { + "description": "Display Title of a Section. Example: Corporate Culture", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "description": { + "description": "Text description of a Section: Example: Our values areNone", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "Skill": { + "title": "Skill", + "type": "object", + "properties": { + "name": { + "description": "Identification name of the skill", + "type": "string" + }, + "type": { + "description": "Type of the skill. hard or soft", + "enum": [ + "hard", + "soft" + ] + }, + "value": { + "description": "Value associated to the skill", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name", + "type" + ] + }, + "GeneralEntitySchema": { + "title": "GeneralEntitySchema", + "type": "object", + "properties": { + "name": { + "description": "Identification name of the Object", + "type": "string" + }, + "value": { + "description": "Value associated to the Object's name", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name" + ] + }, + "RangesFloat": { + "title": "RangesFloat", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Range of floats attached to the Job. Example: salary", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_min": { + "description": "Min value. Example: 500.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_max": { + "description": "Max value. Example: 100.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "unit": { + "description": "Unit of the value. Example: euros.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "RangesDate": { + "title": "RangesDate", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Range of dates attached to the Job. Example: availability.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_min": { + "description": "Min value in datetime ISO 8601, Example: 500.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_max": { + "description": "Max value in datetime ISO 8601, Example: 1000", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + } + } + }, + "push_parameters": { + "title": "CreateCriterias", + "type": "object", + "properties": { + "board_key": { + "description": "HrFlow.ai board key", + "type": "string" + }, + "enrich_with_parsing": { + "description": "When enabled jobs are enriched with HrFlow.ai parsing", + "type": "boolean", + "default": false + } + }, + "required": [ + "board_key" + ], + "$defs": {} + }, + "jsonmap": { + "name": "?.intitule", + "reference": "?.id", + "created_at": "?.dateCreation", + "updated_at": "?.dateActualisation", + "location": "?.lieuTravail ?? {lat: .lieuTravail?.latitude, lng: .lieuTravail?.longitude, text: $concat(.lieuTravail?.libelle >> '', ' ', .lieuTravail?.codePostal >> '') | $strip}: {lat: null, lng: null, text: ''}", + "url": "?.origineOffre?.urlOrigine", + "summary": "?.description", + "requirements": "?.formations ?? $map($concat(.niveauLibelle || '', ' en ', .domaineLibelle || '')) | $join('\n')", + "skills": "?.competences ?? $map({name: .libelle, value: null, type: hard}) : []", + "languages": "?.langues ?? $map({name: .libelle, value: null}) : []", + "sections": [ + { + "name": "company_description", + "title": "'Company Description'", + "description": "?.entreprise?.description" + } + ], + "tags": [ + { + "name": "rome_code", + "value": "?.romeCode" + }, + { + "name": "rome_label", + "value": "?.romeLibelle" + }, + { + "name": "contract_nature", + "value": "?.natureContrat" + }, + { + "name": "contract_type", + "value": "?.typeContratLibelle" + }, + { + "name": "accessible_to_disabled", + "value": "?.accessibleTH" + }, + { + "name": "is_apprenticeship", + "value": "?.alternance" + }, + { + "name": "experience_required", + "value": "?.experienceExige == 'E' ?? true : false" + }, + { + "name": "experience_description", + "value": "?.experienceLibelle" + }, + { + "name": "salary_description", + "value": "?.salaire?.libelle" + }, + { + "name": "working_hours_description", + "value": "?.dureeTravailLibelle" + }, + { + "name": "working_hours_type", + "value": "?.dureeTravailLibelleConverti" + }, + { + "name": "qualification_label", + "value": "?.qualificationLibelle" + }, + { + "name": "sector_of_activity", + "value": "?.secteurActiviteLibelle" + }, + { + "name": "company_name", + "value": "?.entreprise?.nom" + }, + { + "name": "company_description", + "value": "?.entreprise?.description" + }, + { + "name": "company_website", + "value": "?.entreprise?.url" + }, + { + "name": "recruiter_name", + "value": "?.contact?.nom" + }, + { + "name": "recruiter_email", + "value": "?.contact?.courriel" + }, + { + "name": "recruiter_phone", + "value": "?.contact?.telephone" + }, + { + "name": "recruiter_website", + "value": "?.contact?.urlRecruteur" + }, + { + "name": "application_url", + "value": "?.contact?.urlPostulation" + } + ] + }, + "workflow": { + "catch_template": "import typing as t\n\nfrom hrflow_connectors.v2 import FranceTravail\nfrom hrflow_connectors.v2.core.run import ActionInitError, Reason\n\nCONNECTOR_AUTH_SETTINGS_PREFIX = \"connector_auth_\"\nHRFLOW_AUTH_SETTINGS_PREFIX = \"hrflow_auth_\"\nPULL_PARAMETERS_SETTINGS_PREFIX = \"pull_parameters_\"\nPUSH_PARAMETERS_SETTINGS_PREFIX = \"push_parameters_\"\n\n# << format_placeholder >>\n\n# << logics_placeholder >>\n\n# << callback_placeholder >>\n\n\n\n\n# << event_parser_placeholder >>\n\n\n\ndef workflow(\n \n _request: dict,\n \n settings: dict\n ) -> None:\n if \"__workflow_id\" not in settings:\n return FranceTravail.create_jobs_in_hrflow(\n workflow_id=\"\",\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.workflow_id_not_found,\n data=dict(error=\"__workflow_id not found in settings\", settings_keys=list(settings.keys())),\n )\n )\n workflow_id = settings[\"__workflow_id\"]\n\n \n event_parser = globals().get(\"event_parser\", globals().get(\"default_event_parser\"))\n\n if event_parser is not None:\n try:\n _request = event_parser(_request)\n except Exception as e:\n return FranceTravail.create_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.event_parsing_failure,\n data=dict(error=e, event=_request),\n )\n )\n \n\n connector_auth = dict()\n for parameter in ('client_id', 'client_secret'):\n parameter_name = \"{}{}\".format(CONNECTOR_AUTH_SETTINGS_PREFIX, parameter) \n if parameter_name in settings:\n connector_auth[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n connector_auth[parameter] = _request[parameter_name]\n \n\n hrflow_auth = dict()\n for parameter in ('api_secret', 'api_user'):\n parameter_name = \"{}{}\".format(HRFLOW_AUTH_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n hrflow_auth[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n hrflow_auth[parameter] = _request[parameter_name]\n \n\n pull_parameters = dict()\n for parameter in ('range', 'sort', 'domaine', 'codeROME', 'theme', 'appellation', 'codeNAF', 'secteurActivite', 'experience', 'experienceExigence', 'typeContrat', 'natureContrat', 'origineOffre', 'qualification', 'tempsPlein', 'commune', 'distance', 'departement', 'inclureLimitrophes', 'region', 'paysContinent', 'niveauFormation', 'permis', 'motsCles', 'salaireMin', 'periodeSalaire', 'accesTravailleurHandicape', 'offresMRS', 'grandDomaine', 'experienceExige', 'publieeDepuis', 'minCreationDate', 'maxCreationDate', 'partenaires', 'modeSelectionPartenaires', 'dureeHebdo', 'dureeHebdoMin', 'dureeHebdoMax', 'dureeContratMin', 'dureeContratMax', 'offresManqueCandidats', 'entreprisesAdaptees'):\n parameter_name = \"{}{}\".format(PULL_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n pull_parameters[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n pull_parameters[parameter] = _request[parameter_name]\n \n\n push_parameters = dict()\n for parameter in ('board_key', 'enrich_with_parsing'):\n parameter_name = \"{}{}\".format(PUSH_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n push_parameters[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n push_parameters[parameter] = _request[parameter_name]\n \n\n incremental = settings.get(\"__incremental\")\n\n return FranceTravail.create_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=connector_auth,\n hrflow_auth=hrflow_auth,\n pull_parameters=pull_parameters,\n push_parameters=push_parameters,\n logics=globals().get(\"logics\"),\n format=globals().get(\"format\"),\n callback=globals().get(\"callback\"),\n incremental=incremental == \"enable\",\n )", + "pull_template": "import typing as t\n\nfrom hrflow_connectors.v2 import FranceTravail\nfrom hrflow_connectors.v2.core.run import ActionInitError, Reason\n\nCONNECTOR_AUTH_SETTINGS_PREFIX = \"connector_auth_\"\nHRFLOW_AUTH_SETTINGS_PREFIX = \"hrflow_auth_\"\nPULL_PARAMETERS_SETTINGS_PREFIX = \"pull_parameters_\"\nPUSH_PARAMETERS_SETTINGS_PREFIX = \"push_parameters_\"\n\n# << format_placeholder >>\n\n# << logics_placeholder >>\n\n# << callback_placeholder >>\n\n\n\ndef workflow(\n \n settings: dict\n ) -> None:\n if \"__workflow_id\" not in settings:\n return FranceTravail.create_jobs_in_hrflow(\n workflow_id=\"\",\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.workflow_id_not_found,\n data=dict(error=\"__workflow_id not found in settings\", settings_keys=list(settings.keys())),\n )\n )\n workflow_id = settings[\"__workflow_id\"]\n\n \n\n connector_auth = dict()\n for parameter in ('client_id', 'client_secret'):\n parameter_name = \"{}{}\".format(CONNECTOR_AUTH_SETTINGS_PREFIX, parameter) \n if parameter_name in settings:\n connector_auth[parameter] = settings[parameter_name]\n \n\n hrflow_auth = dict()\n for parameter in ('api_secret', 'api_user'):\n parameter_name = \"{}{}\".format(HRFLOW_AUTH_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n hrflow_auth[parameter] = settings[parameter_name]\n \n\n pull_parameters = dict()\n for parameter in ('range', 'sort', 'domaine', 'codeROME', 'theme', 'appellation', 'codeNAF', 'secteurActivite', 'experience', 'experienceExigence', 'typeContrat', 'natureContrat', 'origineOffre', 'qualification', 'tempsPlein', 'commune', 'distance', 'departement', 'inclureLimitrophes', 'region', 'paysContinent', 'niveauFormation', 'permis', 'motsCles', 'salaireMin', 'periodeSalaire', 'accesTravailleurHandicape', 'offresMRS', 'grandDomaine', 'experienceExige', 'publieeDepuis', 'minCreationDate', 'maxCreationDate', 'partenaires', 'modeSelectionPartenaires', 'dureeHebdo', 'dureeHebdoMin', 'dureeHebdoMax', 'dureeContratMin', 'dureeContratMax', 'offresManqueCandidats', 'entreprisesAdaptees'):\n parameter_name = \"{}{}\".format(PULL_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n pull_parameters[parameter] = settings[parameter_name]\n \n\n push_parameters = dict()\n for parameter in ('board_key', 'enrich_with_parsing'):\n parameter_name = \"{}{}\".format(PUSH_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n push_parameters[parameter] = settings[parameter_name]\n \n\n incremental = settings.get(\"__incremental\")\n\n return FranceTravail.create_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=connector_auth,\n hrflow_auth=hrflow_auth,\n pull_parameters=pull_parameters,\n push_parameters=push_parameters,\n logics=globals().get(\"logics\"),\n format=globals().get(\"format\"),\n callback=globals().get(\"callback\"),\n incremental=incremental == \"enable\",\n )", + "settings_keys": { + "workflow_id": "__workflow_id", + "incremental": "__incremental", + "connector_auth_prefix": "connector_auth_", + "hrflow_auth_prefix": "hrflow_auth_", + "pull_parameters_prefix": "pull_parameters_", + "push_parameters_prefix": "push_parameters_" + }, + "placeholders": { + "logics": "# << logics_placeholder >>", + "format": "# << format_placeholder >>", + "callback": "# << callback_placeholder >>", + "event_parser": "# << event_parser_placeholder >>" + }, + "expected": { + "activate_incremental": "enable", + "logics_functions_name": "logics", + "format_functions_name": "format", + "callback_functions_name": "callback", + "event_parser_function_name": "event_parser" + } + } + }, + { + "name": "update_jobs_in_hrflow", + "data_type": "job", + "direction": "inbound", + "mode": "update", + "connector_auth_parameters": { + "title": "AuthParameters", + "type": "object", + "properties": { + "client_id": { + "description": "Client ID used to access France Travail (ex: Pole Emploi) API", + "type": "string" + }, + "client_secret": { + "description": "Client Secret used to access France Travail (ex: Pole Emploi) API", + "type": "string" + } + }, + "required": [ + "client_id", + "client_secret" + ], + "$defs": {} + }, + "hrflow_auth_parameters": { + "title": "AuthParameters", + "type": "object", + "properties": { + "api_secret": { + "description": "API Key used to access HrFlow.ai API", + "type": "string" + }, + "api_user": { + "description": "User email used to access HrFlow.ai API", + "type": "string" + } + }, + "required": [ + "api_secret", + "api_user" + ], + "$defs": {} + }, + "origin": "France Travail (ex: Pole Emploi)", + "origin_data_schema": { + "title": "FranceTravailJobOffer", + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "intitule": { + "type": "string" + }, + "description": { + "type": "string" + }, + "dateCreation": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "dateActualisation": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "lieuTravail": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/JobLocation" + } + ], + "default": null + }, + "romeCode": { + "description": "ROME code of the professionA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/metiers", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "romeLibelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "appellationLibelle": { + "description": "Code of the appellationA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/appellations", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "entreprise": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/Entreprise" + } + ], + "default": null + }, + "typeContrat": { + "description": "Contract type codeA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/typesContrats", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "typeContratLibelle": { + "description": "Contract type labelExample : CDI,CDDA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/typesContrats", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "natureContrat": { + "description": "Code of the nature of contractA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/naturesContrats", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "origineOffre": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/OfferOrigin" + } + ], + "default": null + }, + "offresManqueCandidats": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "experienceExige": { + "anyOf": [ + { + "$ref": "#/$defs/ExperienceRequirement" + }, + { + "type": "null" + } + ], + "default": null + }, + "experienceLibelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "experienceCommentaire": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "formations": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Formation" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "langues": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Langue" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "permis": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Permis" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "outilsBureautiques": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "competences": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Competence" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "salaire": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/Salaire" + } + ], + "default": null + }, + "dureeTravailLibelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeTravailLibelleConverti": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "complementExercice": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "conditionExercice": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "alternance": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "contact": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/Contact" + } + ], + "default": null + }, + "agence": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/Agence" + } + ], + "default": null + }, + "nombrePostes": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "accessibleTH": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "deplacementCode": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "deplacementLibelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "qualificationCode": { + "anyOf": [ + { + "$ref": "#/$defs/QualificationCode" + }, + { + "type": "null" + } + ], + "default": null + }, + "qualificationLibelle": { + "anyOf": [ + { + "$ref": "#/$defs/QualificationLibelle" + }, + { + "type": "null" + } + ], + "default": null + }, + "secteurActivite": { + "description": "NAF codes for sectors of activity. It is possible to specify two NAF codes by separating them with a comma in the character string.Example : 01,02A GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/secteursActivites", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "secteurActiviteLibelle": { + "description": "Sector of activitylabelA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/secteursActivites", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "qualitesProfessionnelles": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/QualitePro" + } + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "id", + "intitule", + "description" + ], + "$defs": { + "JobLocation": { + "title": "JobLocation", + "type": "object", + "properties": { + "libelle": { + "type": "string" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "codepostal": { + "type": "string" + }, + "commune": { + "description": "INSEE code of the communeA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/communes", + "type": "string" + } + }, + "required": [ + "libelle", + "latitude", + "longitude", + "codepostal", + "commune" + ] + }, + "Entreprise": { + "title": "Entreprise", + "type": "object", + "properties": { + "nom": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "logo": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "entrepriseAdaptee": { + "type": "boolean" + } + }, + "required": [ + "nom", + "description", + "logo", + "url", + "entrepriseAdaptee" + ] + }, + "OfferOrigin": { + "title": "OfferOrigin", + "type": "object", + "properties": { + "origine": { + "$ref": "#/$defs/OfferOriginTag" + }, + "urlOrigine": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "partenaires": { + "type": "array", + "items": { + "$ref": "#/$defs/Partner" + } + } + }, + "required": [ + "origine", + "urlOrigine", + "partenaires" + ] + }, + "OfferOriginTag": { + "title": "OfferOriginTag", + "enum": [ + 1, + 2 + ] + }, + "Partner": { + "title": "Partner", + "type": "object", + "properties": { + "nom": { + "type": "string" + }, + "url": { + "type": "string" + }, + "logo": { + "type": "string" + } + }, + "required": [ + "nom", + "url", + "logo" + ] + }, + "ExperienceRequirement": { + "title": "ExperienceRequirement", + "enum": [ + "D", + "E", + "S" + ] + }, + "Formation": { + "title": "Formation", + "type": "object", + "properties": { + "domaineLibelle": { + "type": "string" + }, + "niveauLibelle": { + "description": "Label of the level of the education requiredA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/referentiel/niveauxFormations", + "type": "string" + }, + "commentaire": { + "type": "string" + }, + "exigence": { + "$ref": "#/$defs/Exigence" + } + }, + "required": [ + "domaineLibelle", + "niveauLibelle", + "commentaire", + "exigence" + ] + }, + "Exigence": { + "title": "Exigence", + "enum": [ + "E", + "S" + ] + }, + "Langue": { + "title": "Langue", + "type": "object", + "properties": { + "libelle": { + "description": "Language labelA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/referentiel/langues", + "type": "string" + }, + "exigence": { + "anyOf": [ + { + "$ref": "#/$defs/Exigence" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "libelle", + "exigence" + ] + }, + "Permis": { + "title": "Permis", + "type": "object", + "properties": { + "libelle": { + "description": "requested licenseA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/referentiel/permis", + "type": "string" + }, + "exigence": { + "anyOf": [ + { + "$ref": "#/$defs/Exigence" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "libelle", + "exigence" + ] + }, + "Competence": { + "title": "Competence", + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "libelle": { + "type": "string" + }, + "exigence": { + "anyOf": [ + { + "$ref": "#/$defs/Exigence" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "code", + "libelle", + "exigence" + ] + }, + "Salaire": { + "title": "Salaire", + "type": "object", + "properties": { + "libelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "commentaire": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "complement1": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "complement2": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "libelle", + "commentaire", + "complement1", + "complement2" + ] + }, + "Contact": { + "title": "Contact", + "type": "object", + "properties": { + "nom": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "coordonnees1": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "coordonnees2": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "coordonnees3": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "telephone": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "courriel": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "commentaire": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "urlRecruteur": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "urlPostulation": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "nom", + "coordonnees1", + "coordonnees2", + "coordonnees3", + "telephone", + "courriel", + "commentaire", + "urlRecruteur", + "urlPostulation" + ] + }, + "Agence": { + "title": "Agence", + "type": "object", + "properties": { + "telephone": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "courriel": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "telephone", + "courriel" + ] + }, + "QualificationCode": { + "title": "QualificationCode", + "enum": [ + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9" + ] + }, + "QualificationLibelle": { + "title": "QualificationLibelle", + "enum": [ + "Agent de ma\u00eetrise", + "Cadre", + "Employ\u00e9 non qualifi\u00e9", + "Employ\u00e9 qualifi\u00e9", + "Man\u0153uvre", + "Ouvrier qualifi\u00e9 (P1, P2)", + "Ouvrier qualifi\u00e9 (P3, P4, OHQ)", + "Ouvrier sp\u00e9cialis\u00e9", + "Technicien" + ] + }, + "QualitePro": { + "title": "QualitePro", + "type": "object", + "properties": { + "libelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "libelle", + "description" + ] + } + } + }, + "supports_incremental": false, + "pull_parameters": { + "title": "ReadJobsParameters", + "type": "object", + "properties": { + "range": { + "description": "Pagination of data. The range of results is limited to 150. Format: p-d, where :\n\np is the index (starting at 0) of the first element requested, which must not exceed 3000\nd is the index of the last element requested, which must not exceed 3149", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "sort": { + "description": "Sorting of data", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "domaine": { + "description": "Professional field codeA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint :https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//domaines", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "codeROME": { + "description": "ROME code of the professionA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//metiers", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "theme": { + "description": "Theme of the professionA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//themes", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "appellation": { + "description": "ROME designation code for the offer, see reference belowA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//appellations", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "codeNAF": { + "description": "NAF code of the offer (format 99.99X)A GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//nafs", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "secteurActivite": { + "description": "NAF codes for sectors of activity. It is possible to specify two NAF codes by separating them with a comma in the character string.Example : 01,02A GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//secteursActivites", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "experience": { + "description": "Level of experience required\nPossible values:\n1 -> Less than 1 year of experience\n2 -> From 1 to 3 years of experience\n3 -> More than 3 years of experience", + "anyOf": [ + { + "$ref": "#/$defs/Experience" + }, + { + "type": "null" + } + ], + "default": null + }, + "experienceExigence": { + "description": "Filter offers by experience requirement (D beginner accepted, S experience desired, E experience required)", + "anyOf": [ + { + "$ref": "#/$defs/ExperienceRequirement" + }, + { + "type": "null" + } + ], + "default": null + }, + "typeContrat": { + "description": "Contract type codeExample : CDI,CDDA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//typesContrats", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "natureContrat": { + "description": "Code of the nature of contractA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//naturesContrats", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "origineOffre": { + "description": "Origin of the offer\nPossible values:\n1 -> Job center\n2 -> Partner", + "anyOf": [ + { + "$ref": "#/$defs/OfferOriginTag" + }, + { + "type": "null" + } + ], + "default": null + }, + "qualification": { + "description": "Qualification Code\nPossible values:\n0 -> Non-executive\n9 -> Executive", + "anyOf": [ + { + "$ref": "#/$defs/Qualification" + }, + { + "type": "null" + } + ], + "default": null + }, + "tempsPlein": { + "description": "Promote the use of the WeeklyDuration filter\nPossible values:\nfalse -> Part-time\ntrue -> Full time\nIf the parameter is not filled, then all the offers are returned", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "commune": { + "description": "INSEE code of the communeA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//communes", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "distance": { + "description": "Kilometric distance of the search radius\nDefault value: 10Note: to obtain only the offers of a specific commune, then you must fill in the parameter 'distance=0'.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "departement": { + "description": "Job departmentA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//departements", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "inclureLimitrophes": { + "description": "Include bordering departments in the search", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "region": { + "description": "Code of the region of the offerA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//regions", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "paysContinent": { + "description": "Code of the country or continent of the offerA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//paysAND https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//continents", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "niveauFormation": { + "description": "Level of education requiredA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//niveauxFormations", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "permis": { + "description": "Code of the requested licenseA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//permis", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "motsCles": { + "description": "Search by keyword\n\nEach keyword (or expression) is at least 2 characters long and must\nbe separated by a comma.\nThe search on several keywords is processed via the logical operator \"AND\".\nThe keyword search can be used to search on :\n\n- The title of the offer (title field in the search return)\n- The ROME code (romeCode field in the search return)\n- The ROME label (field romeLibelle in return for the search)\n- The competences label (field competences.libelle in return of the search)\n- The wording of the training fields (field formations.domaineLibelle in\nreturn of the research)\n- The wording of the permits (field permits.label in return of the search)\n- The language label (field languages.label in return of the search)\n- The offer description if found in the offer title and/or the ROME label\n(description field in the search return)\n\nAllowed characters: [aA-zZ]+[0-9]+[space]+[@#$%^&+./-\"\"]", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "salaireMin": { + "description": "Minimum wage, expressed in Euro.If this data is filled in, the code of the type of minimum wage is mandatory.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "periodeSalaire": { + "description": "Period for the calculation of the minimum wage.\nIf this data is filled in, the minimum wage is mandatory.\nPossible values:\nM -> Monthly\nA -> Annual\nH -> Hourly\nC -> Fee", + "anyOf": [ + { + "$ref": "#/$defs/SalaryPeriod" + }, + { + "type": "null" + } + ], + "default": null + }, + "accesTravailleurHandicape": { + "description": "Jobs for which the employer is disabled-friendly", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "offresMRS": { + "description": " Allows you to search for jobs that offer the simulation recruitment method", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "grandDomaine": { + "description": "Code of the major area of the offer", + "anyOf": [ + { + "$ref": "#/$defs/IndustryDomain" + }, + { + "type": "null" + } + ], + "default": null + }, + "experienceExige": { + "description": "Filter offers by experience level.", + "anyOf": [ + { + "$ref": "#/$defs/ExperienceRequirement" + }, + { + "type": "null" + } + ], + "default": null + }, + "publieeDepuis": { + "description": "Maximum number of days since the publication of the offer\nPossible values: 1, 3, 7, 14, 31", + "anyOf": [ + { + "$ref": "#/$defs/PublishedSince" + }, + { + "type": "null" + } + ], + "default": null + }, + "minCreationDate": { + "description": "Minimum offer creation date.\nIf this data is filled in, the maximum offer creation date is mandatory.\nISO-8601 standard (YYYY-MM-DDTHH:MM:SSZ)", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "maxCreationDate": { + "description": "Maximum offer creation date.\nIf this data is filled in, the minimum offer creation date is mandatory.\nISO-8601 standard (YYYY-MM-DDTHH:MM:SSZ)", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "partenaires": { + "description": " This filter allows you to enter your partner code in order to include or exclude your offers from the results according to the selectionmade in the PartnerSelection mode filter\nIt is possible to enter several codes (separator ','). ", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "modeSelectionPartenaires": { + "description": "Selection mode of the partner offers.\n\nThis filter works with the partner criterion and is dependent on the originOffer\ncriterion. Possible values with the results obtained according to the two other filters:\n\n- INCLUS(INCLUDED)\noriginOffer empty : Returns the PE offers and the Partners listed in the Partners\ncriterion\noriginOffer at 2 : Only the offers of the Partners listed in the Partners\ncriterion\n- EXCLU(EXCLUDED)\noriginOffer empty : Return the offers of PE and Partners not listed in the Partners\ncriterion\noriginOffer at 2 : Only the offers of the Partners not listed in the Partners\ncriterion\nNote: In all cases, if originOffer = 1, then only the France Travail (ex: Pole Emploi)\noffers will be returned", + "anyOf": [ + { + "$ref": "#/$defs/PartnerSelectionMode" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeHebdo": { + "description": "Filtre les offres selon la dur\u00e9e hebdomadaire.\nValeurs possibles :\n0 -> Non pr\u00e9cis\u00e9\n1 -> Temps plein\n2 -> Temps partiel", + "anyOf": [ + { + "$ref": "#/$defs/WeeklyDuration" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeHebdoMin": { + "description": "Minimum weekly duration of the offer\nThe value must be in HHMM format, for example : 8h => 800 ; 24h30 => 2430", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeHebdoMax": { + "description": "Maximum weekly duration of the offer\nThe value must be in HHMM format, for example: 8h => 800; 24h30 => 2430", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeContratMin": { + "description": "Minimum duration of the sought contract.\nThe search is done in months (ex: 0.5 for 15 days, 1.0 for 1 month,2.0 for 2 months).\nPositive decimal (Decimal separator: '.')", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeContratMax": { + "description": "Maximum duration of the sought contract.\nThe search is made in months (ex: 0.5 for 15 days, 1.0 for 1 month,2.0 for 2 months).\nPositive decimal (Decimal separator: '.')", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "offresManqueCandidats": { + "description": "Filters offers older than 15 days, with less than 4 applications (of which P\u00f4le emploi is informed)\nfalse -> Offers not concerned\ntrue -> Offers with few candidates", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "entreprisesAdaptees": { + "description": "Filter the offers where the adapted company allows a disabled worker to exercise a professional activity in conditions adapted to his capacities\nfalse -> Offers not concerned\ntrue -> Offers from adapted companies", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [], + "$defs": { + "Experience": { + "title": "Experience", + "enum": [ + "1", + "2", + "3" + ] + }, + "ExperienceRequirement": { + "title": "ExperienceRequirement", + "enum": [ + "D", + "E", + "S" + ] + }, + "OfferOriginTag": { + "title": "OfferOriginTag", + "enum": [ + 1, + 2 + ] + }, + "Qualification": { + "title": "Qualification", + "enum": [ + 0, + 9 + ] + }, + "SalaryPeriod": { + "title": "SalaryPeriod", + "enum": [ + "A", + "C", + "H", + "M" + ] + }, + "IndustryDomain": { + "title": "IndustryDomain", + "enum": [ + "A", + "B", + "C", + "C15", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "L14", + "M", + "M13", + "M14", + "M15", + "M16", + "M17", + "M18", + "N" + ] + }, + "PublishedSince": { + "title": "PublishedSince", + "enum": [ + 1, + 3, + 7, + 14, + 31 + ] + }, + "PartnerSelectionMode": { + "title": "PartnerSelectionMode", + "enum": [ + "EXCLU", + "INCLUS" + ] + }, + "WeeklyDuration": { + "title": "WeeklyDuration", + "enum": [ + "0", + "1", + "2" + ] + } + } + }, + "target": "HrFlow", + "target_data_schema": { + "title": "HrFlowJob", + "type": "object", + "properties": { + "key": { + "description": "Identification key of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "description": "Custom identifier of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "name": { + "description": "Job title.", + "type": "string" + }, + "location": { + "description": "Job location object.", + "$ref": "#/$defs/Location" + }, + "sections": { + "description": "Job custom sections.", + "type": "array", + "items": { + "$ref": "#/$defs/Section" + } + }, + "url": { + "description": "Job post original URL.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "summary": { + "description": "Brief summary of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "archieved_at": { + "description": "type: datetime ISO8601, Archive date of the Job. The value is null for unarchived Jobs.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "updated_at": { + "description": "type: datetime ISO8601, Last update date of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "created_at": { + "description": "type: datetime ISO8601, Creation date of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "skills": { + "description": "list of skills of the Job.", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Skill" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "languages": { + "description": "list of spoken languages of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "certifications": { + "description": "list of certifications of the Job.", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "courses": { + "description": "list of courses of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "tasks": { + "description": "list of tasks of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "tags": { + "description": "list of tags of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "metadatas": { + "description": "list of metadatas of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "ranges_float": { + "description": "list of ranges of floats", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/RangesFloat" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "ranges_date": { + "description": "list of ranges of dates", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/RangesDate" + } + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name", + "location", + "sections" + ], + "$defs": { + "Location": { + "title": "Location", + "type": "object", + "properties": { + "text": { + "description": "Location text address.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "lat": { + "description": "Geocentric latitude of the Location.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "lng": { + "description": "Geocentric longitude of the Location.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "fields": { + "description": "other location attributes like country, country_code etc", + "anyOf": [ + { + "type": "object" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "Section": { + "title": "Section", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Section of the Job. Example: culture", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "title": { + "description": "Display Title of a Section. Example: Corporate Culture", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "description": { + "description": "Text description of a Section: Example: Our values areNone", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "Skill": { + "title": "Skill", + "type": "object", + "properties": { + "name": { + "description": "Identification name of the skill", + "type": "string" + }, + "type": { + "description": "Type of the skill. hard or soft", + "enum": [ + "hard", + "soft" + ] + }, + "value": { + "description": "Value associated to the skill", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name", + "type" + ] + }, + "GeneralEntitySchema": { + "title": "GeneralEntitySchema", + "type": "object", + "properties": { + "name": { + "description": "Identification name of the Object", + "type": "string" + }, + "value": { + "description": "Value associated to the Object's name", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name" + ] + }, + "RangesFloat": { + "title": "RangesFloat", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Range of floats attached to the Job. Example: salary", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_min": { + "description": "Min value. Example: 500.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_max": { + "description": "Max value. Example: 100.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "unit": { + "description": "Unit of the value. Example: euros.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "RangesDate": { + "title": "RangesDate", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Range of dates attached to the Job. Example: availability.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_min": { + "description": "Min value in datetime ISO 8601, Example: 500.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_max": { + "description": "Max value in datetime ISO 8601, Example: 1000", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + } + } + }, + "push_parameters": { + "title": "UpdateCriterias", + "type": "object", + "properties": { + "board_key": { + "description": "HrFlow.ai board key", + "type": "string" + } + }, + "required": [ + "board_key" + ], + "$defs": {} + }, + "jsonmap": { + "name": "?.intitule", + "reference": "?.id", + "created_at": "?.dateCreation", + "updated_at": "?.dateActualisation", + "location": "?.lieuTravail ?? {lat: .lieuTravail?.latitude, lng: .lieuTravail?.longitude, text: $concat(.lieuTravail?.libelle >> '', ' ', .lieuTravail?.codePostal >> '') | $strip}: {lat: null, lng: null, text: ''}", + "url": "?.origineOffre?.urlOrigine", + "summary": "?.description", + "requirements": "?.formations ?? $map($concat(.niveauLibelle || '', ' en ', .domaineLibelle || '')) | $join('\n')", + "skills": "?.competences ?? $map({name: .libelle, value: null, type: hard}) : []", + "languages": "?.langues ?? $map({name: .libelle, value: null}) : []", + "sections": [ + { + "name": "company_description", + "title": "'Company Description'", + "description": "?.entreprise?.description" + } + ], + "tags": [ + { + "name": "rome_code", + "value": "?.romeCode" + }, + { + "name": "rome_label", + "value": "?.romeLibelle" + }, + { + "name": "contract_nature", + "value": "?.natureContrat" + }, + { + "name": "contract_type", + "value": "?.typeContratLibelle" + }, + { + "name": "accessible_to_disabled", + "value": "?.accessibleTH" + }, + { + "name": "is_apprenticeship", + "value": "?.alternance" + }, + { + "name": "experience_required", + "value": "?.experienceExige == 'E' ?? true : false" + }, + { + "name": "experience_description", + "value": "?.experienceLibelle" + }, + { + "name": "salary_description", + "value": "?.salaire?.libelle" + }, + { + "name": "working_hours_description", + "value": "?.dureeTravailLibelle" + }, + { + "name": "working_hours_type", + "value": "?.dureeTravailLibelleConverti" + }, + { + "name": "qualification_label", + "value": "?.qualificationLibelle" + }, + { + "name": "sector_of_activity", + "value": "?.secteurActiviteLibelle" + }, + { + "name": "company_name", + "value": "?.entreprise?.nom" + }, + { + "name": "company_description", + "value": "?.entreprise?.description" + }, + { + "name": "company_website", + "value": "?.entreprise?.url" + }, + { + "name": "recruiter_name", + "value": "?.contact?.nom" + }, + { + "name": "recruiter_email", + "value": "?.contact?.courriel" + }, + { + "name": "recruiter_phone", + "value": "?.contact?.telephone" + }, + { + "name": "recruiter_website", + "value": "?.contact?.urlRecruteur" + }, + { + "name": "application_url", + "value": "?.contact?.urlPostulation" + } + ] + }, + "workflow": { + "catch_template": "import typing as t\n\nfrom hrflow_connectors.v2 import FranceTravail\nfrom hrflow_connectors.v2.core.run import ActionInitError, Reason\n\nCONNECTOR_AUTH_SETTINGS_PREFIX = \"connector_auth_\"\nHRFLOW_AUTH_SETTINGS_PREFIX = \"hrflow_auth_\"\nPULL_PARAMETERS_SETTINGS_PREFIX = \"pull_parameters_\"\nPUSH_PARAMETERS_SETTINGS_PREFIX = \"push_parameters_\"\n\n# << format_placeholder >>\n\n# << logics_placeholder >>\n\n# << callback_placeholder >>\n\n\n\n\n# << event_parser_placeholder >>\n\n\n\ndef workflow(\n \n _request: dict,\n \n settings: dict\n ) -> None:\n if \"__workflow_id\" not in settings:\n return FranceTravail.update_jobs_in_hrflow(\n workflow_id=\"\",\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.workflow_id_not_found,\n data=dict(error=\"__workflow_id not found in settings\", settings_keys=list(settings.keys())),\n )\n )\n workflow_id = settings[\"__workflow_id\"]\n\n \n event_parser = globals().get(\"event_parser\", globals().get(\"default_event_parser\"))\n\n if event_parser is not None:\n try:\n _request = event_parser(_request)\n except Exception as e:\n return FranceTravail.update_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.event_parsing_failure,\n data=dict(error=e, event=_request),\n )\n )\n \n\n connector_auth = dict()\n for parameter in ('client_id', 'client_secret'):\n parameter_name = \"{}{}\".format(CONNECTOR_AUTH_SETTINGS_PREFIX, parameter) \n if parameter_name in settings:\n connector_auth[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n connector_auth[parameter] = _request[parameter_name]\n \n\n hrflow_auth = dict()\n for parameter in ('api_secret', 'api_user'):\n parameter_name = \"{}{}\".format(HRFLOW_AUTH_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n hrflow_auth[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n hrflow_auth[parameter] = _request[parameter_name]\n \n\n pull_parameters = dict()\n for parameter in ('range', 'sort', 'domaine', 'codeROME', 'theme', 'appellation', 'codeNAF', 'secteurActivite', 'experience', 'experienceExigence', 'typeContrat', 'natureContrat', 'origineOffre', 'qualification', 'tempsPlein', 'commune', 'distance', 'departement', 'inclureLimitrophes', 'region', 'paysContinent', 'niveauFormation', 'permis', 'motsCles', 'salaireMin', 'periodeSalaire', 'accesTravailleurHandicape', 'offresMRS', 'grandDomaine', 'experienceExige', 'publieeDepuis', 'minCreationDate', 'maxCreationDate', 'partenaires', 'modeSelectionPartenaires', 'dureeHebdo', 'dureeHebdoMin', 'dureeHebdoMax', 'dureeContratMin', 'dureeContratMax', 'offresManqueCandidats', 'entreprisesAdaptees'):\n parameter_name = \"{}{}\".format(PULL_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n pull_parameters[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n pull_parameters[parameter] = _request[parameter_name]\n \n\n push_parameters = dict()\n for parameter in ('board_key',):\n parameter_name = \"{}{}\".format(PUSH_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n push_parameters[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n push_parameters[parameter] = _request[parameter_name]\n \n\n incremental = settings.get(\"__incremental\")\n\n return FranceTravail.update_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=connector_auth,\n hrflow_auth=hrflow_auth,\n pull_parameters=pull_parameters,\n push_parameters=push_parameters,\n logics=globals().get(\"logics\"),\n format=globals().get(\"format\"),\n callback=globals().get(\"callback\"),\n incremental=incremental == \"enable\",\n )", + "pull_template": "import typing as t\n\nfrom hrflow_connectors.v2 import FranceTravail\nfrom hrflow_connectors.v2.core.run import ActionInitError, Reason\n\nCONNECTOR_AUTH_SETTINGS_PREFIX = \"connector_auth_\"\nHRFLOW_AUTH_SETTINGS_PREFIX = \"hrflow_auth_\"\nPULL_PARAMETERS_SETTINGS_PREFIX = \"pull_parameters_\"\nPUSH_PARAMETERS_SETTINGS_PREFIX = \"push_parameters_\"\n\n# << format_placeholder >>\n\n# << logics_placeholder >>\n\n# << callback_placeholder >>\n\n\n\ndef workflow(\n \n settings: dict\n ) -> None:\n if \"__workflow_id\" not in settings:\n return FranceTravail.update_jobs_in_hrflow(\n workflow_id=\"\",\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.workflow_id_not_found,\n data=dict(error=\"__workflow_id not found in settings\", settings_keys=list(settings.keys())),\n )\n )\n workflow_id = settings[\"__workflow_id\"]\n\n \n\n connector_auth = dict()\n for parameter in ('client_id', 'client_secret'):\n parameter_name = \"{}{}\".format(CONNECTOR_AUTH_SETTINGS_PREFIX, parameter) \n if parameter_name in settings:\n connector_auth[parameter] = settings[parameter_name]\n \n\n hrflow_auth = dict()\n for parameter in ('api_secret', 'api_user'):\n parameter_name = \"{}{}\".format(HRFLOW_AUTH_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n hrflow_auth[parameter] = settings[parameter_name]\n \n\n pull_parameters = dict()\n for parameter in ('range', 'sort', 'domaine', 'codeROME', 'theme', 'appellation', 'codeNAF', 'secteurActivite', 'experience', 'experienceExigence', 'typeContrat', 'natureContrat', 'origineOffre', 'qualification', 'tempsPlein', 'commune', 'distance', 'departement', 'inclureLimitrophes', 'region', 'paysContinent', 'niveauFormation', 'permis', 'motsCles', 'salaireMin', 'periodeSalaire', 'accesTravailleurHandicape', 'offresMRS', 'grandDomaine', 'experienceExige', 'publieeDepuis', 'minCreationDate', 'maxCreationDate', 'partenaires', 'modeSelectionPartenaires', 'dureeHebdo', 'dureeHebdoMin', 'dureeHebdoMax', 'dureeContratMin', 'dureeContratMax', 'offresManqueCandidats', 'entreprisesAdaptees'):\n parameter_name = \"{}{}\".format(PULL_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n pull_parameters[parameter] = settings[parameter_name]\n \n\n push_parameters = dict()\n for parameter in ('board_key',):\n parameter_name = \"{}{}\".format(PUSH_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n push_parameters[parameter] = settings[parameter_name]\n \n\n incremental = settings.get(\"__incremental\")\n\n return FranceTravail.update_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=connector_auth,\n hrflow_auth=hrflow_auth,\n pull_parameters=pull_parameters,\n push_parameters=push_parameters,\n logics=globals().get(\"logics\"),\n format=globals().get(\"format\"),\n callback=globals().get(\"callback\"),\n incremental=incremental == \"enable\",\n )", + "settings_keys": { + "workflow_id": "__workflow_id", + "incremental": "__incremental", + "connector_auth_prefix": "connector_auth_", + "hrflow_auth_prefix": "hrflow_auth_", + "pull_parameters_prefix": "pull_parameters_", + "push_parameters_prefix": "push_parameters_" + }, + "placeholders": { + "logics": "# << logics_placeholder >>", + "format": "# << format_placeholder >>", + "callback": "# << callback_placeholder >>", + "event_parser": "# << event_parser_placeholder >>" + }, + "expected": { + "activate_incremental": "enable", + "logics_functions_name": "logics", + "format_functions_name": "format", + "callback_functions_name": "callback", + "event_parser_function_name": "event_parser" + } + } + }, + { + "name": "archive_jobs_in_hrflow", + "data_type": "job", + "direction": "inbound", + "mode": "archive", + "connector_auth_parameters": { + "title": "AuthParameters", + "type": "object", + "properties": { + "client_id": { + "description": "Client ID used to access France Travail (ex: Pole Emploi) API", + "type": "string" + }, + "client_secret": { + "description": "Client Secret used to access France Travail (ex: Pole Emploi) API", + "type": "string" + } + }, + "required": [ + "client_id", + "client_secret" + ], + "$defs": {} + }, + "hrflow_auth_parameters": { + "title": "AuthParameters", + "type": "object", + "properties": { + "api_secret": { + "description": "API Key used to access HrFlow.ai API", + "type": "string" + }, + "api_user": { + "description": "User email used to access HrFlow.ai API", + "type": "string" + } + }, + "required": [ + "api_secret", + "api_user" + ], + "$defs": {} + }, + "origin": "France Travail (ex: Pole Emploi)", + "origin_data_schema": { + "title": "FranceTravailJobOffer", + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "intitule": { + "type": "string" + }, + "description": { + "type": "string" + }, + "dateCreation": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "dateActualisation": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "lieuTravail": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/JobLocation" + } + ], + "default": null + }, + "romeCode": { + "description": "ROME code of the professionA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/metiers", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "romeLibelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "appellationLibelle": { + "description": "Code of the appellationA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/appellations", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "entreprise": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/Entreprise" + } + ], + "default": null + }, + "typeContrat": { + "description": "Contract type codeA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/typesContrats", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "typeContratLibelle": { + "description": "Contract type labelExample : CDI,CDDA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/typesContrats", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "natureContrat": { + "description": "Code of the nature of contractA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/naturesContrats", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "origineOffre": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/OfferOrigin" + } + ], + "default": null + }, + "offresManqueCandidats": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "experienceExige": { + "anyOf": [ + { + "$ref": "#/$defs/ExperienceRequirement" + }, + { + "type": "null" + } + ], + "default": null + }, + "experienceLibelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "experienceCommentaire": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "formations": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Formation" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "langues": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Langue" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "permis": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Permis" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "outilsBureautiques": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "competences": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Competence" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "salaire": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/Salaire" + } + ], + "default": null + }, + "dureeTravailLibelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeTravailLibelleConverti": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "complementExercice": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "conditionExercice": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "alternance": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "contact": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/Contact" + } + ], + "default": null + }, + "agence": { + "anyOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/Agence" + } + ], + "default": null + }, + "nombrePostes": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "accessibleTH": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "deplacementCode": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "deplacementLibelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "qualificationCode": { + "anyOf": [ + { + "$ref": "#/$defs/QualificationCode" + }, + { + "type": "null" + } + ], + "default": null + }, + "qualificationLibelle": { + "anyOf": [ + { + "$ref": "#/$defs/QualificationLibelle" + }, + { + "type": "null" + } + ], + "default": null + }, + "secteurActivite": { + "description": "NAF codes for sectors of activity. It is possible to specify two NAF codes by separating them with a comma in the character string.Example : 01,02A GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/secteursActivites", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "secteurActiviteLibelle": { + "description": "Sector of activitylabelA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/secteursActivites", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "qualitesProfessionnelles": { + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/QualitePro" + } + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "id", + "intitule", + "description" + ], + "$defs": { + "JobLocation": { + "title": "JobLocation", + "type": "object", + "properties": { + "libelle": { + "type": "string" + }, + "latitude": { + "type": "number" + }, + "longitude": { + "type": "number" + }, + "codepostal": { + "type": "string" + }, + "commune": { + "description": "INSEE code of the communeA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/communes", + "type": "string" + } + }, + "required": [ + "libelle", + "latitude", + "longitude", + "codepostal", + "commune" + ] + }, + "Entreprise": { + "title": "Entreprise", + "type": "object", + "properties": { + "nom": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "logo": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "url": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "entrepriseAdaptee": { + "type": "boolean" + } + }, + "required": [ + "nom", + "description", + "logo", + "url", + "entrepriseAdaptee" + ] + }, + "OfferOrigin": { + "title": "OfferOrigin", + "type": "object", + "properties": { + "origine": { + "$ref": "#/$defs/OfferOriginTag" + }, + "urlOrigine": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "partenaires": { + "type": "array", + "items": { + "$ref": "#/$defs/Partner" + } + } + }, + "required": [ + "origine", + "urlOrigine", + "partenaires" + ] + }, + "OfferOriginTag": { + "title": "OfferOriginTag", + "enum": [ + 1, + 2 + ] + }, + "Partner": { + "title": "Partner", + "type": "object", + "properties": { + "nom": { + "type": "string" + }, + "url": { + "type": "string" + }, + "logo": { + "type": "string" + } + }, + "required": [ + "nom", + "url", + "logo" + ] + }, + "ExperienceRequirement": { + "title": "ExperienceRequirement", + "enum": [ + "D", + "E", + "S" + ] + }, + "Formation": { + "title": "Formation", + "type": "object", + "properties": { + "domaineLibelle": { + "type": "string" + }, + "niveauLibelle": { + "description": "Label of the level of the education requiredA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/referentiel/niveauxFormations", + "type": "string" + }, + "commentaire": { + "type": "string" + }, + "exigence": { + "$ref": "#/$defs/Exigence" + } + }, + "required": [ + "domaineLibelle", + "niveauLibelle", + "commentaire", + "exigence" + ] + }, + "Exigence": { + "title": "Exigence", + "enum": [ + "E", + "S" + ] + }, + "Langue": { + "title": "Langue", + "type": "object", + "properties": { + "libelle": { + "description": "Language labelA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/referentiel/langues", + "type": "string" + }, + "exigence": { + "anyOf": [ + { + "$ref": "#/$defs/Exigence" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "libelle", + "exigence" + ] + }, + "Permis": { + "title": "Permis", + "type": "object", + "properties": { + "libelle": { + "description": "requested licenseA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/referentiel/permis", + "type": "string" + }, + "exigence": { + "anyOf": [ + { + "$ref": "#/$defs/Exigence" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "libelle", + "exigence" + ] + }, + "Competence": { + "title": "Competence", + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "libelle": { + "type": "string" + }, + "exigence": { + "anyOf": [ + { + "$ref": "#/$defs/Exigence" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "code", + "libelle", + "exigence" + ] + }, + "Salaire": { + "title": "Salaire", + "type": "object", + "properties": { + "libelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "commentaire": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "complement1": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "complement2": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "libelle", + "commentaire", + "complement1", + "complement2" + ] + }, + "Contact": { + "title": "Contact", + "type": "object", + "properties": { + "nom": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "coordonnees1": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "coordonnees2": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "coordonnees3": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "telephone": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "courriel": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "commentaire": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "urlRecruteur": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "urlPostulation": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "nom", + "coordonnees1", + "coordonnees2", + "coordonnees3", + "telephone", + "courriel", + "commentaire", + "urlRecruteur", + "urlPostulation" + ] + }, + "Agence": { + "title": "Agence", + "type": "object", + "properties": { + "telephone": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "courriel": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "telephone", + "courriel" + ] + }, + "QualificationCode": { + "title": "QualificationCode", + "enum": [ + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9" + ] + }, + "QualificationLibelle": { + "title": "QualificationLibelle", + "enum": [ + "Agent de ma\u00eetrise", + "Cadre", + "Employ\u00e9 non qualifi\u00e9", + "Employ\u00e9 qualifi\u00e9", + "Man\u0153uvre", + "Ouvrier qualifi\u00e9 (P1, P2)", + "Ouvrier qualifi\u00e9 (P3, P4, OHQ)", + "Ouvrier sp\u00e9cialis\u00e9", + "Technicien" + ] + }, + "QualitePro": { + "title": "QualitePro", + "type": "object", + "properties": { + "libelle": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "libelle", + "description" + ] + } + } + }, + "supports_incremental": false, + "pull_parameters": { + "title": "ReadJobsParameters", + "type": "object", + "properties": { + "range": { + "description": "Pagination of data. The range of results is limited to 150. Format: p-d, where :\n\np is the index (starting at 0) of the first element requested, which must not exceed 3000\nd is the index of the last element requested, which must not exceed 3149", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "sort": { + "description": "Sorting of data", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "domaine": { + "description": "Professional field codeA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint :https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//domaines", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "codeROME": { + "description": "ROME code of the professionA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//metiers", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "theme": { + "description": "Theme of the professionA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//themes", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "appellation": { + "description": "ROME designation code for the offer, see reference belowA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//appellations", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "codeNAF": { + "description": "NAF code of the offer (format 99.99X)A GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//nafs", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "secteurActivite": { + "description": "NAF codes for sectors of activity. It is possible to specify two NAF codes by separating them with a comma in the character string.Example : 01,02A GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//secteursActivites", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "experience": { + "description": "Level of experience required\nPossible values:\n1 -> Less than 1 year of experience\n2 -> From 1 to 3 years of experience\n3 -> More than 3 years of experience", + "anyOf": [ + { + "$ref": "#/$defs/Experience" + }, + { + "type": "null" + } + ], + "default": null + }, + "experienceExigence": { + "description": "Filter offers by experience requirement (D beginner accepted, S experience desired, E experience required)", + "anyOf": [ + { + "$ref": "#/$defs/ExperienceRequirement" + }, + { + "type": "null" + } + ], + "default": null + }, + "typeContrat": { + "description": "Contract type codeExample : CDI,CDDA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//typesContrats", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "natureContrat": { + "description": "Code of the nature of contractA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//naturesContrats", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "origineOffre": { + "description": "Origin of the offer\nPossible values:\n1 -> Job center\n2 -> Partner", + "anyOf": [ + { + "$ref": "#/$defs/OfferOriginTag" + }, + { + "type": "null" + } + ], + "default": null + }, + "qualification": { + "description": "Qualification Code\nPossible values:\n0 -> Non-executive\n9 -> Executive", + "anyOf": [ + { + "$ref": "#/$defs/Qualification" + }, + { + "type": "null" + } + ], + "default": null + }, + "tempsPlein": { + "description": "Promote the use of the WeeklyDuration filter\nPossible values:\nfalse -> Part-time\ntrue -> Full time\nIf the parameter is not filled, then all the offers are returned", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "commune": { + "description": "INSEE code of the communeA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//communes", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "distance": { + "description": "Kilometric distance of the search radius\nDefault value: 10Note: to obtain only the offers of a specific commune, then you must fill in the parameter 'distance=0'.", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "departement": { + "description": "Job departmentA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//departements", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "inclureLimitrophes": { + "description": "Include bordering departments in the search", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "region": { + "description": "Code of the region of the offerA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//regions", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "paysContinent": { + "description": "Code of the country or continent of the offerA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//paysAND https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//continents", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "niveauFormation": { + "description": "Level of education requiredA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//niveauxFormations", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "permis": { + "description": "Code of the requested licenseA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//permis", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "motsCles": { + "description": "Search by keyword\n\nEach keyword (or expression) is at least 2 characters long and must\nbe separated by a comma.\nThe search on several keywords is processed via the logical operator \"AND\".\nThe keyword search can be used to search on :\n\n- The title of the offer (title field in the search return)\n- The ROME code (romeCode field in the search return)\n- The ROME label (field romeLibelle in return for the search)\n- The competences label (field competences.libelle in return of the search)\n- The wording of the training fields (field formations.domaineLibelle in\nreturn of the research)\n- The wording of the permits (field permits.label in return of the search)\n- The language label (field languages.label in return of the search)\n- The offer description if found in the offer title and/or the ROME label\n(description field in the search return)\n\nAllowed characters: [aA-zZ]+[0-9]+[space]+[@#$%^&+./-\"\"]", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "salaireMin": { + "description": "Minimum wage, expressed in Euro.If this data is filled in, the code of the type of minimum wage is mandatory.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "periodeSalaire": { + "description": "Period for the calculation of the minimum wage.\nIf this data is filled in, the minimum wage is mandatory.\nPossible values:\nM -> Monthly\nA -> Annual\nH -> Hourly\nC -> Fee", + "anyOf": [ + { + "$ref": "#/$defs/SalaryPeriod" + }, + { + "type": "null" + } + ], + "default": null + }, + "accesTravailleurHandicape": { + "description": "Jobs for which the employer is disabled-friendly", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "offresMRS": { + "description": " Allows you to search for jobs that offer the simulation recruitment method", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "grandDomaine": { + "description": "Code of the major area of the offer", + "anyOf": [ + { + "$ref": "#/$defs/IndustryDomain" + }, + { + "type": "null" + } + ], + "default": null + }, + "experienceExige": { + "description": "Filter offers by experience level.", + "anyOf": [ + { + "$ref": "#/$defs/ExperienceRequirement" + }, + { + "type": "null" + } + ], + "default": null + }, + "publieeDepuis": { + "description": "Maximum number of days since the publication of the offer\nPossible values: 1, 3, 7, 14, 31", + "anyOf": [ + { + "$ref": "#/$defs/PublishedSince" + }, + { + "type": "null" + } + ], + "default": null + }, + "minCreationDate": { + "description": "Minimum offer creation date.\nIf this data is filled in, the maximum offer creation date is mandatory.\nISO-8601 standard (YYYY-MM-DDTHH:MM:SSZ)", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "maxCreationDate": { + "description": "Maximum offer creation date.\nIf this data is filled in, the minimum offer creation date is mandatory.\nISO-8601 standard (YYYY-MM-DDTHH:MM:SSZ)", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "partenaires": { + "description": " This filter allows you to enter your partner code in order to include or exclude your offers from the results according to the selectionmade in the PartnerSelection mode filter\nIt is possible to enter several codes (separator ','). ", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "modeSelectionPartenaires": { + "description": "Selection mode of the partner offers.\n\nThis filter works with the partner criterion and is dependent on the originOffer\ncriterion. Possible values with the results obtained according to the two other filters:\n\n- INCLUS(INCLUDED)\noriginOffer empty : Returns the PE offers and the Partners listed in the Partners\ncriterion\noriginOffer at 2 : Only the offers of the Partners listed in the Partners\ncriterion\n- EXCLU(EXCLUDED)\noriginOffer empty : Return the offers of PE and Partners not listed in the Partners\ncriterion\noriginOffer at 2 : Only the offers of the Partners not listed in the Partners\ncriterion\nNote: In all cases, if originOffer = 1, then only the France Travail (ex: Pole Emploi)\noffers will be returned", + "anyOf": [ + { + "$ref": "#/$defs/PartnerSelectionMode" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeHebdo": { + "description": "Filtre les offres selon la dur\u00e9e hebdomadaire.\nValeurs possibles :\n0 -> Non pr\u00e9cis\u00e9\n1 -> Temps plein\n2 -> Temps partiel", + "anyOf": [ + { + "$ref": "#/$defs/WeeklyDuration" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeHebdoMin": { + "description": "Minimum weekly duration of the offer\nThe value must be in HHMM format, for example : 8h => 800 ; 24h30 => 2430", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeHebdoMax": { + "description": "Maximum weekly duration of the offer\nThe value must be in HHMM format, for example: 8h => 800; 24h30 => 2430", + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeContratMin": { + "description": "Minimum duration of the sought contract.\nThe search is done in months (ex: 0.5 for 15 days, 1.0 for 1 month,2.0 for 2 months).\nPositive decimal (Decimal separator: '.')", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "dureeContratMax": { + "description": "Maximum duration of the sought contract.\nThe search is made in months (ex: 0.5 for 15 days, 1.0 for 1 month,2.0 for 2 months).\nPositive decimal (Decimal separator: '.')", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "offresManqueCandidats": { + "description": "Filters offers older than 15 days, with less than 4 applications (of which P\u00f4le emploi is informed)\nfalse -> Offers not concerned\ntrue -> Offers with few candidates", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + }, + "entreprisesAdaptees": { + "description": "Filter the offers where the adapted company allows a disabled worker to exercise a professional activity in conditions adapted to his capacities\nfalse -> Offers not concerned\ntrue -> Offers from adapted companies", + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [], + "$defs": { + "Experience": { + "title": "Experience", + "enum": [ + "1", + "2", + "3" + ] + }, + "ExperienceRequirement": { + "title": "ExperienceRequirement", + "enum": [ + "D", + "E", + "S" + ] + }, + "OfferOriginTag": { + "title": "OfferOriginTag", + "enum": [ + 1, + 2 + ] + }, + "Qualification": { + "title": "Qualification", + "enum": [ + 0, + 9 + ] + }, + "SalaryPeriod": { + "title": "SalaryPeriod", + "enum": [ + "A", + "C", + "H", + "M" + ] + }, + "IndustryDomain": { + "title": "IndustryDomain", + "enum": [ + "A", + "B", + "C", + "C15", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "L14", + "M", + "M13", + "M14", + "M15", + "M16", + "M17", + "M18", + "N" + ] + }, + "PublishedSince": { + "title": "PublishedSince", + "enum": [ + 1, + 3, + 7, + 14, + 31 + ] + }, + "PartnerSelectionMode": { + "title": "PartnerSelectionMode", + "enum": [ + "EXCLU", + "INCLUS" + ] + }, + "WeeklyDuration": { + "title": "WeeklyDuration", + "enum": [ + "0", + "1", + "2" + ] + } + } + }, + "target": "HrFlow", + "target_data_schema": { + "title": "HrFlowJob", + "type": "object", + "properties": { + "key": { + "description": "Identification key of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "reference": { + "description": "Custom identifier of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "name": { + "description": "Job title.", + "type": "string" + }, + "location": { + "description": "Job location object.", + "$ref": "#/$defs/Location" + }, + "sections": { + "description": "Job custom sections.", + "type": "array", + "items": { + "$ref": "#/$defs/Section" + } + }, + "url": { + "description": "Job post original URL.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "summary": { + "description": "Brief summary of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "archieved_at": { + "description": "type: datetime ISO8601, Archive date of the Job. The value is null for unarchived Jobs.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "updated_at": { + "description": "type: datetime ISO8601, Last update date of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "created_at": { + "description": "type: datetime ISO8601, Creation date of the Job.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "skills": { + "description": "list of skills of the Job.", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/Skill" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "languages": { + "description": "list of spoken languages of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "certifications": { + "description": "list of certifications of the Job.", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "courses": { + "description": "list of courses of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "tasks": { + "description": "list of tasks of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "tags": { + "description": "list of tags of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "metadatas": { + "description": "list of metadatas of the Job", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/GeneralEntitySchema" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "ranges_float": { + "description": "list of ranges of floats", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/RangesFloat" + } + }, + { + "type": "null" + } + ], + "default": null + }, + "ranges_date": { + "description": "list of ranges of dates", + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/RangesDate" + } + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name", + "location", + "sections" + ], + "$defs": { + "Location": { + "title": "Location", + "type": "object", + "properties": { + "text": { + "description": "Location text address.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "lat": { + "description": "Geocentric latitude of the Location.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "lng": { + "description": "Geocentric longitude of the Location.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "fields": { + "description": "other location attributes like country, country_code etc", + "anyOf": [ + { + "type": "object" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "Section": { + "title": "Section", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Section of the Job. Example: culture", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "title": { + "description": "Display Title of a Section. Example: Corporate Culture", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "description": { + "description": "Text description of a Section: Example: Our values areNone", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "Skill": { + "title": "Skill", + "type": "object", + "properties": { + "name": { + "description": "Identification name of the skill", + "type": "string" + }, + "type": { + "description": "Type of the skill. hard or soft", + "enum": [ + "hard", + "soft" + ] + }, + "value": { + "description": "Value associated to the skill", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name", + "type" + ] + }, + "GeneralEntitySchema": { + "title": "GeneralEntitySchema", + "type": "object", + "properties": { + "name": { + "description": "Identification name of the Object", + "type": "string" + }, + "value": { + "description": "Value associated to the Object's name", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [ + "name" + ] + }, + "RangesFloat": { + "title": "RangesFloat", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Range of floats attached to the Job. Example: salary", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_min": { + "description": "Min value. Example: 500.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_max": { + "description": "Max value. Example: 100.", + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "default": null + }, + "unit": { + "description": "Unit of the value. Example: euros.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + }, + "RangesDate": { + "title": "RangesDate", + "type": "object", + "properties": { + "name": { + "description": "Identification name of a Range of dates attached to the Job. Example: availability.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_min": { + "description": "Min value in datetime ISO 8601, Example: 500.", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + }, + "value_max": { + "description": "Max value in datetime ISO 8601, Example: 1000", + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null + } + }, + "required": [] + } + } + }, + "push_parameters": { + "title": "ArchiveCriterias", + "type": "object", + "properties": { + "board_key": { + "description": "HrFlow.ai board key", + "type": "string" + } + }, + "required": [ + "board_key" + ], + "$defs": {} + }, + "jsonmap": { + "reference": "?._id" + }, + "workflow": { + "catch_template": "import typing as t\n\nfrom hrflow_connectors.v2 import FranceTravail\nfrom hrflow_connectors.v2.core.run import ActionInitError, Reason\n\nCONNECTOR_AUTH_SETTINGS_PREFIX = \"connector_auth_\"\nHRFLOW_AUTH_SETTINGS_PREFIX = \"hrflow_auth_\"\nPULL_PARAMETERS_SETTINGS_PREFIX = \"pull_parameters_\"\nPUSH_PARAMETERS_SETTINGS_PREFIX = \"push_parameters_\"\n\n# << format_placeholder >>\n\n# << logics_placeholder >>\n\n# << callback_placeholder >>\n\n\n\n\n# << event_parser_placeholder >>\n\n\n\ndef workflow(\n \n _request: dict,\n \n settings: dict\n ) -> None:\n if \"__workflow_id\" not in settings:\n return FranceTravail.archive_jobs_in_hrflow(\n workflow_id=\"\",\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.workflow_id_not_found,\n data=dict(error=\"__workflow_id not found in settings\", settings_keys=list(settings.keys())),\n )\n )\n workflow_id = settings[\"__workflow_id\"]\n\n \n event_parser = globals().get(\"event_parser\", globals().get(\"default_event_parser\"))\n\n if event_parser is not None:\n try:\n _request = event_parser(_request)\n except Exception as e:\n return FranceTravail.archive_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.event_parsing_failure,\n data=dict(error=e, event=_request),\n )\n )\n \n\n connector_auth = dict()\n for parameter in ('client_id', 'client_secret'):\n parameter_name = \"{}{}\".format(CONNECTOR_AUTH_SETTINGS_PREFIX, parameter) \n if parameter_name in settings:\n connector_auth[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n connector_auth[parameter] = _request[parameter_name]\n \n\n hrflow_auth = dict()\n for parameter in ('api_secret', 'api_user'):\n parameter_name = \"{}{}\".format(HRFLOW_AUTH_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n hrflow_auth[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n hrflow_auth[parameter] = _request[parameter_name]\n \n\n pull_parameters = dict()\n for parameter in ('range', 'sort', 'domaine', 'codeROME', 'theme', 'appellation', 'codeNAF', 'secteurActivite', 'experience', 'experienceExigence', 'typeContrat', 'natureContrat', 'origineOffre', 'qualification', 'tempsPlein', 'commune', 'distance', 'departement', 'inclureLimitrophes', 'region', 'paysContinent', 'niveauFormation', 'permis', 'motsCles', 'salaireMin', 'periodeSalaire', 'accesTravailleurHandicape', 'offresMRS', 'grandDomaine', 'experienceExige', 'publieeDepuis', 'minCreationDate', 'maxCreationDate', 'partenaires', 'modeSelectionPartenaires', 'dureeHebdo', 'dureeHebdoMin', 'dureeHebdoMax', 'dureeContratMin', 'dureeContratMax', 'offresManqueCandidats', 'entreprisesAdaptees'):\n parameter_name = \"{}{}\".format(PULL_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n pull_parameters[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n pull_parameters[parameter] = _request[parameter_name]\n \n\n push_parameters = dict()\n for parameter in ('board_key',):\n parameter_name = \"{}{}\".format(PUSH_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n push_parameters[parameter] = settings[parameter_name]\n \n if parameter_name in _request:\n push_parameters[parameter] = _request[parameter_name]\n \n\n incremental = settings.get(\"__incremental\")\n\n return FranceTravail.archive_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=connector_auth,\n hrflow_auth=hrflow_auth,\n pull_parameters=pull_parameters,\n push_parameters=push_parameters,\n logics=globals().get(\"logics\"),\n format=globals().get(\"format\"),\n callback=globals().get(\"callback\"),\n incremental=incremental == \"enable\",\n )", + "pull_template": "import typing as t\n\nfrom hrflow_connectors.v2 import FranceTravail\nfrom hrflow_connectors.v2.core.run import ActionInitError, Reason\n\nCONNECTOR_AUTH_SETTINGS_PREFIX = \"connector_auth_\"\nHRFLOW_AUTH_SETTINGS_PREFIX = \"hrflow_auth_\"\nPULL_PARAMETERS_SETTINGS_PREFIX = \"pull_parameters_\"\nPUSH_PARAMETERS_SETTINGS_PREFIX = \"push_parameters_\"\n\n# << format_placeholder >>\n\n# << logics_placeholder >>\n\n# << callback_placeholder >>\n\n\n\ndef workflow(\n \n settings: dict\n ) -> None:\n if \"__workflow_id\" not in settings:\n return FranceTravail.archive_jobs_in_hrflow(\n workflow_id=\"\",\n connector_auth=dict(),\n hrflow_auth=dict(),\n pull_parameters=dict(),\n push_parameters=dict(),\n init_error=ActionInitError(\n reason=Reason.workflow_id_not_found,\n data=dict(error=\"__workflow_id not found in settings\", settings_keys=list(settings.keys())),\n )\n )\n workflow_id = settings[\"__workflow_id\"]\n\n \n\n connector_auth = dict()\n for parameter in ('client_id', 'client_secret'):\n parameter_name = \"{}{}\".format(CONNECTOR_AUTH_SETTINGS_PREFIX, parameter) \n if parameter_name in settings:\n connector_auth[parameter] = settings[parameter_name]\n \n\n hrflow_auth = dict()\n for parameter in ('api_secret', 'api_user'):\n parameter_name = \"{}{}\".format(HRFLOW_AUTH_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n hrflow_auth[parameter] = settings[parameter_name]\n \n\n pull_parameters = dict()\n for parameter in ('range', 'sort', 'domaine', 'codeROME', 'theme', 'appellation', 'codeNAF', 'secteurActivite', 'experience', 'experienceExigence', 'typeContrat', 'natureContrat', 'origineOffre', 'qualification', 'tempsPlein', 'commune', 'distance', 'departement', 'inclureLimitrophes', 'region', 'paysContinent', 'niveauFormation', 'permis', 'motsCles', 'salaireMin', 'periodeSalaire', 'accesTravailleurHandicape', 'offresMRS', 'grandDomaine', 'experienceExige', 'publieeDepuis', 'minCreationDate', 'maxCreationDate', 'partenaires', 'modeSelectionPartenaires', 'dureeHebdo', 'dureeHebdoMin', 'dureeHebdoMax', 'dureeContratMin', 'dureeContratMax', 'offresManqueCandidats', 'entreprisesAdaptees'):\n parameter_name = \"{}{}\".format(PULL_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n pull_parameters[parameter] = settings[parameter_name]\n \n\n push_parameters = dict()\n for parameter in ('board_key',):\n parameter_name = \"{}{}\".format(PUSH_PARAMETERS_SETTINGS_PREFIX, parameter)\n if parameter_name in settings:\n push_parameters[parameter] = settings[parameter_name]\n \n\n incremental = settings.get(\"__incremental\")\n\n return FranceTravail.archive_jobs_in_hrflow(\n workflow_id=workflow_id,\n connector_auth=connector_auth,\n hrflow_auth=hrflow_auth,\n pull_parameters=pull_parameters,\n push_parameters=push_parameters,\n logics=globals().get(\"logics\"),\n format=globals().get(\"format\"),\n callback=globals().get(\"callback\"),\n incremental=incremental == \"enable\",\n )", + "settings_keys": { + "workflow_id": "__workflow_id", + "incremental": "__incremental", + "connector_auth_prefix": "connector_auth_", + "hrflow_auth_prefix": "hrflow_auth_", + "pull_parameters_prefix": "pull_parameters_", + "push_parameters_prefix": "push_parameters_" + }, + "placeholders": { + "logics": "# << logics_placeholder >>", + "format": "# << format_placeholder >>", + "callback": "# << callback_placeholder >>", + "event_parser": "# << event_parser_placeholder >>" + }, + "expected": { + "activate_incremental": "enable", + "logics_functions_name": "logics", + "format_functions_name": "format", + "callback_functions_name": "callback", + "event_parser_function_name": "event_parser" + } + } + } + ] } ] } \ No newline at end of file diff --git a/src/hrflow_connectors/__init__.py b/src/hrflow_connectors/__init__.py index ffcef0300..a39fbb69a 100644 --- a/src/hrflow_connectors/__init__.py +++ b/src/hrflow_connectors/__init__.py @@ -10,7 +10,6 @@ from hrflow_connectors.v1.connectors.jobology import Jobology from hrflow_connectors.v1.connectors.lever import Lever from hrflow_connectors.v1.connectors.meteojob import Meteojob -from hrflow_connectors.v1.connectors.poleemploi import PoleEmploi from hrflow_connectors.v1.connectors.recruitee import Recruitee from hrflow_connectors.v1.connectors.salesforce import Salesforce from hrflow_connectors.v1.connectors.sapsuccessfactors import SAPSuccessFactors @@ -26,7 +25,6 @@ __CONNECTORS__ = [ SmartRecruiters, TalentSoft, - PoleEmploi, Adzuna, Recruitee, Workable, diff --git a/src/hrflow_connectors/v1/data/connectors.json b/src/hrflow_connectors/v1/data/connectors.json index 90cf558cb..f498ea467 100644 --- a/src/hrflow_connectors/v1/data/connectors.json +++ b/src/hrflow_connectors/v1/data/connectors.json @@ -872,9 +872,9 @@ "pre_v2_updated_at": "" }, { - "name": "Pole Emploi", + "name": "France Travail (ex: Pole Emploi)", "type": "Job Board", - "subtype": "poleemploi", + "subtype": "francetravail", "status": "opensource", "release_date": "15/07/2022", "pre_v2_updated_at": "24/10/2024" diff --git a/src/hrflow_connectors/v2/__init__.py b/src/hrflow_connectors/v2/__init__.py index 6e3ebf6c5..7eddc5ee6 100644 --- a/src/hrflow_connectors/v2/__init__.py +++ b/src/hrflow_connectors/v2/__init__.py @@ -1,5 +1,7 @@ from hrflow_connectors.v2.connectors.admen import Admen +from hrflow_connectors.v2.connectors.adzuna import Adzuna from hrflow_connectors.v2.connectors.bullhorn import Bullhorn +from hrflow_connectors.v2.connectors.francetravail import FranceTravail from hrflow_connectors.v2.connectors.hubspot import Hubspot from hrflow_connectors.v2.connectors.recruitee import Recruitee from hrflow_connectors.v2.connectors.smartrecruiters import SmartRecruiters @@ -11,4 +13,13 @@ hrflow_connectors_docs as hrflow_connectors_docs, ) -__CONNECTORS__ = [Bullhorn, ZohoRecruit, Admen, SmartRecruiters, Hubspot, Recruitee] +__CONNECTORS__ = [ + Bullhorn, + ZohoRecruit, + Admen, + SmartRecruiters, + Hubspot, + Recruitee, + Adzuna, + FranceTravail, +] diff --git a/src/hrflow_connectors/v2/connectors/admen/README.md b/src/hrflow_connectors/v2/connectors/admen/README.md index 549bf572f..097b934af 100644 --- a/src/hrflow_connectors/v2/connectors/admen/README.md +++ b/src/hrflow_connectors/v2/connectors/admen/README.md @@ -1,7 +1,7 @@ # 📖 Summary - [📖 Summary](#📖-summary) -- [💼 About Admen](#💼-about-admen) - - [😍 Why is it a big deal for Admen customers & partners?](#😍-why-is-it-a-big-deal-for-admen-customers--partners) +- [💼 About Ad-men](#💼-about-ad-men) + - [😍 Why is it a big deal for Ad-men customers & partners?](#😍-why-is-it-a-big-deal-for-ad-men-customers--partners) - [🔧 How does it work?](#🔧-how-does-it-work) - [📊 Data integration capabilities:](#📊-data-integration-capabilities) - [🧠 Artificial Intelligence capabilities:](#🧠-artificial-intelligence-capabilities) @@ -11,7 +11,7 @@ - [👏 Special Thanks](#👏-special-thanks) -# 💼 About Admen +# 💼 About Ad-men > Need an efficient, high-performance HR solution for managing your applications? @@ -19,23 +19,29 @@ Choose AD-Men, the No. 1 software for recruitment agencies. -## 😍 Why is it a big deal for Admen customers & partners? +## 😍 Why is it a big deal for Ad-men customers & partners? This new connector will enable: -- ⚡ A Fastlane Talent & Workforce data integration for Admen customers & partners -- 🤖 Cutting-edge AI-powered Talent Experiences & Recruiter Experiences for Admen customers +- ⚡ A Fastlane Talent & Workforce data integration for Ad-men customers & partners +- 🤖 Cutting-edge AI-powered Talent Experiences & Recruiter Experiences for Ad-men customers # 🔧 How does it work? ## 📊 Data integration capabilities: -- ⬅️ Send Profiles data from Admen to a Destination of your choice. -- ➡️ Send Profiles data from a Source of your choice to Admen. -- ⬅️ Send Jobs data from Admen to a Destination of your choice. -- ➡️ Send Jobs data from a Source of your choice to Admen. +- ⬅️ Send Profiles data from Ad-men to a Destination of your choice. +- ➡️ Send Profiles data from a Source of your choice to Ad-men. +- ⬅️ Send Jobs data from Ad-men to a Destination of your choice. +- ➡️ Send Jobs data from a Source of your choice to Ad-men. +

+ +

+ +

## 🧠 Artificial Intelligence capabilities: - Extract, Structure, and Categorize Talent & Workforce data -- Search, Score, and Match Profiles & Jobs with our APIs and AI Widgets (**Matching Custom Tab in Admen**) +- Search, Score, and Match Profiles & Jobs with our APIs and AI Widgets (**Matching Custom Tab in Ad-men**) # 🔌 Connector Actions @@ -56,12 +62,6 @@ This new connector will enable:

-

- -

- -

# 💍 Quick Start Examples @@ -83,8 +83,8 @@ For more code details checkout connector code. # 🔗 Useful Links -- 📄Visit [Admen](https://www.ad-rh.com/) to learn more. -- 💻 [Connector code](https://github.com/Riminder/hrflow-connectors/tree/master/src/hrflow_connectors/connectors/admen) on our Github. +- 📄 Visit [Ad-men](https://www.ad-rh.com/) to learn more. +- 💻 [Connector code](https://github.com/Riminder/hrflow-connectors/tree/master/src/hrflow_connectors/v2/connectors/admen) on our Github. # 👏 Special Thanks diff --git a/src/hrflow_connectors/v2/connectors/adzuna/README.md b/src/hrflow_connectors/v2/connectors/adzuna/README.md new file mode 100644 index 000000000..f9fbce038 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/adzuna/README.md @@ -0,0 +1,87 @@ +# 📖 Summary +- [📖 Summary](#📖-summary) +- [💼 About Adzuna](#💼-about-adzuna) + - [😍 Why is it a big deal for Adzuna customers & partners?](#😍-why-is-it-a-big-deal-for-adzuna-customers--partners) +- [🔧 How does it work?](#🔧-how-does-it-work) + - [📊 Data integration capabilities:](#📊-data-integration-capabilities) + - [🧠 Artificial Intelligence capabilities:](#🧠-artificial-intelligence-capabilities) +- [🔌 Connector Actions](#🔌-connector-actions) +- [💍 Quick Start Examples](#💍-quick-start-examples) +- [🔗 Useful Links](#🔗-useful-links) +- [👏 Special Thanks](#👏-special-thanks) + + +# 💼 About Adzuna + +> Find Every Job, Everywhere with Adzuna + +Adzuna is a smarter, more transparent job search engine that helps you dodge the thousands of irrelevant jobs so you can zero in on the right role faster. + +

+ +

+ +## 😍 Why is it a big deal for Adzuna customers & partners? + +This new connector will enable: +- ⚡ A Fastlane Talent & Workforce data integration for Adzuna customers & partners +- 🤖 Cutting-edge AI-powered Talent Experiences & Recruiter Experiences for Adzuna customers + +# 🔧 How does it work? +## 📊 Data integration capabilities: +- ⬅️ Send Profiles data from Adzuna to a Destination of your choice. +- ➡️ Send Profiles data from a Source of your choice to Adzuna. +- ⬅️ Send Jobs data from Adzuna to a Destination of your choice. +- ➡️ Send Jobs data from a Source of your choice to Adzuna. + + +

+ + +

+ + +## 🧠 Artificial Intelligence capabilities: +- Extract, Structure, and Categorize Talent & Workforce data +- Search, Score, and Match Profiles & Jobs with our APIs and AI Widgets (**Matching Custom Tab in Adzuna**) + + +# 🔌 Connector Actions +

+ +| Action | Description | +| ------- | ----------- | +| [**Create jobs in hrflow**](docs/create_jobs_in_hrflow.md) | Send **created** 'job(s)' _from_ _to_ HrFlow | +| [**Update jobs in hrflow**](docs/update_jobs_in_hrflow.md) | Send **updated** 'job(s)' _from_ _to_ HrFlow | +| [**Archive jobs in hrflow**](docs/archive_jobs_in_hrflow.md) | Send **archived** 'job(s)' _from_ _to_ HrFlow | + + +

+ + +# 💍 Quick Start Examples + +To make sure you can successfully run the latest versions of the example scripts, you have to **install the package from PyPi**. + + +To browse the examples of actions corresponding to released versions of 🤗 this connector, you just need to import the module like this : + + +

+ +

+ +Once the connector module is imported, you can leverage all the different actions that it offers. + +For more code details checkout connector code. + + +# 🔗 Useful Links + +- 📄 Visit [Adzuna](https://www.adzuna.fr/) to learn more. +- ⚙️ API documentation : (https://developer.adzuna.com/docs/search) +- 💻 [Connector code](https://github.com/Riminder/hrflow-connectors/tree/master/src/hrflow_connectors/v2/connectors/adzuna) on our Github. + + +# 👏 Special Thanks +- 💻 HrFlow.ai : [Nedhir Ebnou](https://github.com/nedhirouebnou) - Software Engineer \ No newline at end of file diff --git a/src/hrflow_connectors/v2/connectors/adzuna/__init__.py b/src/hrflow_connectors/v2/connectors/adzuna/__init__.py new file mode 100644 index 000000000..e4cb6ed11 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/adzuna/__init__.py @@ -0,0 +1 @@ +from hrflow_connectors.v2.connectors.adzuna.connector import Adzuna # noqa diff --git a/src/hrflow_connectors/v2/connectors/adzuna/aisles.py b/src/hrflow_connectors/v2/connectors/adzuna/aisles.py new file mode 100644 index 000000000..ec6e7b917 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/adzuna/aisles.py @@ -0,0 +1,323 @@ +import typing as t +from enum import Enum +from logging import LoggerAdapter + +import requests +from msgspec import Meta, Struct +from msgspec.structs import asdict +from typing_extensions import Annotated + +from hrflow_connectors.v2.connectors.adzuna.schemas import AdzunaJob +from hrflow_connectors.v2.core.common import Entity +from hrflow_connectors.v2.core.warehouse import ( + Aisle, + Criterias, + Endpoint, + Endpoints, + ReadOperation, + merge, +) + +ADZUNA_BASE_URL = "http://api.adzuna.com/v1/api" +SEARCH_JOBS_ENDPOINT = Endpoint( + name="Get Adzuna jobs", + description="Use this endpoint to retrieve Adzuna's job advertisement listings.", + url="https://api.adzuna.com/v1/doc/Search.md", +) + +MAX_NUMBER_OF_PAGES = 10 + + +class CountryCode(str, Enum): + GB = "gb" + AT = "at" + AU = "au" + BR = "br" + CA = "ca" + DE = "de" + FR = "fr" + IN = "in" + IT = "it" + NL = "nl" + NZ = "nz" + PL = "pl" + RU = "ru" + SG = "sg" + US = "us" + ZA = "za" + + +class SortDir(str, Enum): + UP = "up" + DOWN = "down" + + +class SortKey(str, Enum): + DEFAULT = "default" + HYBRID = "hybrid" + DATE = "date" + SALARY = "salary" + RELEVANCE = "relevance" + + +class Filter(str, Enum): + ON = "1" + + +class AuthParameters(Struct): + app_id: Annotated[ + t.Optional[str], + Meta( + description="Application ID, supplied by Adzuna", + ), + ] + app_key: Annotated[ + t.Optional[str], + Meta( + description="Application key, supplied by Adzuna", + ), + ] + + +class ReadJobsParameters(Struct): + country: Annotated[ + CountryCode, + Meta( + description="ISO 8601 country code of the country of interest", + ), + ] + results_per_page: Annotated[ + t.Optional[int], + Meta( + description="The number of results to include on a page of search results.", + ), + ] = 50 + what: Annotated[ + t.Optional[str], + Meta( + description=( + "The keywords to search for. Multiple terms may be space separated." + ), + ), + ] = None + what_and: Annotated[ + t.Optional[str], + Meta( + description="The keywords to search for, all keywords must be found.", + ), + ] = None + what_phrase: Annotated[ + t.Optional[str], + Meta( + description=( + "An entire phrase which must be found in the description or title." + ), + ), + ] = None + what_or: Annotated[ + t.Optional[str], + Meta( + description=( + "The keywords to search for, any keywords may be found. Multiple terms" + " may be space separated." + ), + ), + ] = None + what_exclude: Annotated[ + t.Optional[str], + Meta( + description=( + "Keywords to exclude from the search. Multiple terms may be space" + " separated." + ), + ), + ] = None + title_only: Annotated[ + t.Optional[str], + Meta( + description=( + "Keywords to find, but only in the title. Multiple terms may be space" + " separated." + ), + ), + ] = None + where: Annotated[ + t.Optional[str], + Meta( + description=( + "The geographic centre of the search. Place names, postal codes, etc." + " may be used. " + ), + ), + ] = None + distance: Annotated[ + t.Optional[int], + Meta( + description=( + "The distance in kilometres from the centre of the place described by" + " the 'where' parameter. Defaults to 5km." + ), + ), + ] = None + location0: Annotated[ + t.Optional[str], + Meta( + description=( + """The location fields may be used to describe a location,""" + """ in a similar form to that returned in """ + """a Adzuna::API::Response::Location object.For example,""" + """ "location0=UK&location1=South East England&location2=Surrey" """ + """ will performn a search over the county of Surrey.""" + ), + ), + ] = None + location1: t.Optional[str] = None + + location2: t.Optional[str] = None + + location3: t.Optional[str] = None + + location4: t.Optional[str] = None + + location5: t.Optional[str] = None + + location6: t.Optional[str] = None + + location7: t.Optional[str] = None + + max_days_old: Annotated[ + t.Optional[int], + Meta( + description=( + "The age of the oldest advertisment in days that will be returned." + ), + ), + ] = None + category: Annotated[ + t.Optional[str], + Meta( + description='The category tag, as returned by the "category" endpoint.', + ), + ] = None + sort_dir: Annotated[ + t.Optional[SortDir], + Meta( + description="The direction to order the search results.", + ), + ] = None + sort_by: Annotated[ + t.Optional[SortKey], + Meta( + description="The ordering of the search results.", + ), + ] = None + salary_min: Annotated[ + t.Optional[int], + Meta( + description="The minimum salary we wish to get results for.", + ), + ] = None + salary_max: Annotated[ + t.Optional[int], + Meta( + description="The maximum salary we wish to get results for.", + ), + ] = None + salary_include_unknown: Annotated[ + t.Optional[Filter], + Meta( + description="""If set it "1", jobs without a known salary are returned.""", + ), + ] = None + full_time: Annotated[ + t.Optional[Filter], + Meta( + description="""If set to "1", only full time jobs will be returned.""", + ), + ] = None + part_time: Annotated[ + t.Optional[Filter], + Meta( + description="""If set to "1", only part time jobs will be returned.""", + ), + ] = None + contract: Annotated[ + t.Optional[Filter], + Meta( + description="""If set to "1", only contract jobs will be returned.""", + ), + ] = None + permanent: Annotated[ + t.Optional[Filter], + Meta( + description="""If set to "1", only permanent jobs will be returned.""", + ), + ] = None + company: Annotated[ + t.Optional[str], + Meta( + description=( + "The canonical company name. This may be returned in a" + " Adzuna::API::Response::Company object when a job is returned. A full" + " list of allowed terms in not available through the API." + ), + ), + ] = None + + +def read( + adapter: LoggerAdapter, + auth_parameters: AuthParameters, + parameters: ReadJobsParameters, + incremental: bool, + incremental_token: t.Optional[str], +) -> t.Iterable[t.Dict]: + params = asdict(parameters) + page = 1 + country = params.pop("country") + params["app_id"] = auth_parameters.app_id + params["app_key"] = auth_parameters.app_key + + while True: + ADZUNA_JOBS_SEARCH_ENDPOINT = "{}/jobs/{}/search/{}".format( + ADZUNA_BASE_URL, country.value, page + ) + response = requests.get( + ADZUNA_JOBS_SEARCH_ENDPOINT, + params=params, + ) + if response.status_code // 100 != 2: + adapter.error( + "Failed to pull jobs from Adzuna params={}" + " status_code={} response={}".format( + params, response.status_code, response.text + ) + ) + raise Exception("Failed to pull jobs from Adzuna") + + jobs = response.json()["results"] + for job in jobs: + yield job + + page += 1 + if len(jobs) == 0 or page == MAX_NUMBER_OF_PAGES: + break + + +JobsAisle = Aisle( + name=Entity.job, + schema=AdzunaJob, + read=ReadOperation( + criterias=Criterias( + create=ReadJobsParameters, + update=ReadJobsParameters, + archive=ReadJobsParameters, + ), + function=merge(create=read, update=read, archive=read), + endpoints=Endpoints( + create=SEARCH_JOBS_ENDPOINT, + update=SEARCH_JOBS_ENDPOINT, + archive=SEARCH_JOBS_ENDPOINT, + ), + ), +) diff --git a/src/hrflow_connectors/v2/connectors/adzuna/connector.py b/src/hrflow_connectors/v2/connectors/adzuna/connector.py new file mode 100644 index 000000000..5f6f09aa9 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/adzuna/connector.py @@ -0,0 +1,76 @@ +import typing as t + +from hrflow_connectors.v2.connectors.adzuna.warehouse import AdzunaWarehouse +from hrflow_connectors.v2.core.common import Direction, Entity, Mode +from hrflow_connectors.v2.core.connector import Connector, ConnectorType, Flow + + +def get_tags(adzuna_job: t.Dict) -> t.List[t.Dict]: + t = lambda name, value: dict(name=name, value=value) + tags = [ + t("contract_type", adzuna_job.get("contract_type")), + t("contract_time", adzuna_job.get("contract_time")), + t("salary_min", adzuna_job.get("salary_min")), + t("salary_max", adzuna_job.get("salary_max")), + t( + "salary_is_predicted", + adzuna_job.get("salary_is_predicted", 0) == 1, + ), + t("category", adzuna_job.get("category", {}).get("label")), + t("company", adzuna_job.get("company", {}).get("display_name")), + ] + return tags + + +def format_job( + adzuna_job: t.Dict, +) -> t.Dict: + job = dict( + name=adzuna_job.get("title"), + reference=str(adzuna_job.get("id")), + created_at=adzuna_job.get("created"), + location=dict( + lat=adzuna_job.get("latitude"), + lng=adzuna_job.get("longitude"), + text=adzuna_job.get("location", {}).get("display_name", ""), + ), + url=adzuna_job.get("redirect_url"), + summary=adzuna_job.get("description"), + sections=( + [ + dict( + name="full_description", + title="Full Description", + description=adzuna_job.get("full_description"), + ) + ] + if adzuna_job.get("full_description") + else [] + ), + tags=get_tags(adzuna_job), + ) + return job + + +def format_archive(adzuna_job: t.Dict) -> t.Dict: + return dict(reference=str(adzuna_job.get("id"))) + + +DESCRIPTION = ( + "Find Every Job, Everywhere with Adzuna\n\nAdzuna is a smarter, more transparent" + " job search engine that helps you dodge the thousands of irrelevant jobs so you" + " can zero in on the right role faster." +) +Adzuna = Connector( + name="Adzuna", + type=ConnectorType.JobBoard, + subtype="adzuna", + description=DESCRIPTION, + url="https://www.adzuna.fr/", + warehouse=AdzunaWarehouse, + flows=( + Flow(Mode.create, Entity.job, Direction.inbound, format=format_job), + Flow(Mode.update, Entity.job, Direction.inbound, format=format_job), + Flow(Mode.archive, Entity.job, Direction.inbound, format=format_archive), + ), +) diff --git a/src/hrflow_connectors/v2/connectors/adzuna/connector.pyi b/src/hrflow_connectors/v2/connectors/adzuna/connector.pyi new file mode 100644 index 000000000..39b7d36cb --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/adzuna/connector.pyi @@ -0,0 +1,9 @@ +# This file is generated automatically +from hrflow_connectors.v2.core.connector import Connector, PublicActionInterface + +class AdzunaProto(Connector): + create_jobs_in_hrflow: PublicActionInterface + update_jobs_in_hrflow: PublicActionInterface + archive_jobs_in_hrflow: PublicActionInterface + +Adzuna: AdzunaProto \ No newline at end of file diff --git a/src/hrflow_connectors/v2/connectors/adzuna/docs/archive_jobs_in_hrflow.md b/src/hrflow_connectors/v2/connectors/adzuna/docs/archive_jobs_in_hrflow.md new file mode 100644 index 000000000..91d841990 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/adzuna/docs/archive_jobs_in_hrflow.md @@ -0,0 +1,143 @@ +# Archive jobs in hrflow +`Adzuna` :arrow_right: `HrFlow` + +Send **archived** 'job(s)' _from_ Adzuna _to_ HrFlow + + +**Adzuna endpoint used :** +| Endpoint | Description | +| --------- | ----------- | +| [**Get Adzuna jobs**](https://api.adzuna.com/v1/doc/Search.md) | Use this endpoint to retrieve Adzuna's job advertisement listings. | + + + +## Adzuna Auth Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `app_id` :red_circle: | `string\|null` | None | Application ID, supplied by Adzuna | +| `app_key` :red_circle: | `string\|null` | None | Application key, supplied by Adzuna | + +## HrFlow.ai Auth Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `api_secret` :red_circle: | `string` | None | API Key used to access HrFlow.ai API | +| `api_user` :red_circle: | `string` | None | User email used to access HrFlow.ai API | + +## Pull Parameters (Adzuna) + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `country` :red_circle: | `Literal['at','au','br','ca','de','fr','gb','in','it','nl','nz','pl','ru','sg','us','za']` | None | ISO 8601 country code of the country of interest | +| `results_per_page` | `integer\|null` | 50 | The number of results to include on a page of search results. | +| `what` | `string\|null` | None | The keywords to search for. Multiple terms may be space separated. | +| `what_and` | `string\|null` | None | The keywords to search for, all keywords must be found. | +| `what_phrase` | `string\|null` | None | An entire phrase which must be found in the description or title. | +| `what_or` | `string\|null` | None | The keywords to search for, any keywords may be found. Multiple terms may be space separated. | +| `what_exclude` | `string\|null` | None | Keywords to exclude from the search. Multiple terms may be space separated. | +| `title_only` | `string\|null` | None | Keywords to find, but only in the title. Multiple terms may be space separated. | +| `where` | `string\|null` | None | The geographic centre of the search. Place names, postal codes, etc. may be used. | +| `distance` | `integer\|null` | None | The distance in kilometres from the centre of the place described by the 'where' parameter. Defaults to 5km. | +| `location0` | `string\|null` | None | The location fields may be used to describe a location, in a similar form to that returned in a Adzuna::API::Response::Location object.For example, "location0=UK&location1=South East England&location2=Surrey" will performn a search over the county of Surrey. | +| `location1` | `string\|null` | None | | +| `location2` | `string\|null` | None | | +| `location3` | `string\|null` | None | | +| `location4` | `string\|null` | None | | +| `location5` | `string\|null` | None | | +| `location6` | `string\|null` | None | | +| `location7` | `string\|null` | None | | +| `max_days_old` | `integer\|null` | None | The age of the oldest advertisment in days that will be returned. | +| `category` | `string\|null` | None | The category tag, as returned by the "category" endpoint. | +| `sort_dir` | `Literal['down','up']\|null` | None | The direction to order the search results. | +| `sort_by` | `Literal['date','default','hybrid','relevance','salary']\|null` | None | The ordering of the search results. | +| `salary_min` | `integer\|null` | None | The minimum salary we wish to get results for. | +| `salary_max` | `integer\|null` | None | The maximum salary we wish to get results for. | +| `salary_include_unknown` | `Literal['1']\|null` | None | If set it "1", jobs without a known salary are returned. | +| `full_time` | `Literal['1']\|null` | None | If set to "1", only full time jobs will be returned. | +| `part_time` | `Literal['1']\|null` | None | If set to "1", only part time jobs will be returned. | +| `contract` | `Literal['1']\|null` | None | If set to "1", only contract jobs will be returned. | +| `permanent` | `Literal['1']\|null` | None | If set to "1", only permanent jobs will be returned. | +| `company` | `string\|null` | None | The canonical company name. This may be returned in a Adzuna::API::Response::Company object when a job is returned. A full list of allowed terms in not available through the API. | + +## Push Parameters (HrFlow) + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `board_key` :red_circle: | `string` | None | HrFlow.ai board key | + +## Other Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `workflow_id` :red_circle: | `string` | None | A stable identifier used for persisting in incremental mode | +| `logics` :red_circle: | `array\|null` | None | A list of functions called in sequence with each item pulled from the origin. Each function might either return it's argument or None to discard the item. Any item discarded is eventually not pushed to the target | +| `format` | `Callable\|null` | None | A formatting function to apply on items pulled before the push | +| `callback` | `Callable\|null` | None | Registers a callback function to be called at the of a successful execution | +| `persist` | `boolean` | True | When False has the effect of running in dry mode. Items are pulled but not pushed to the target | +| `incremental` | `boolean` | False | Controls the incremental reading execution mode | + +:red_circle: : *required* + +## Example + +```python +import logging +from hrflow_connectors.v2 import Adzuna + + +logging.basicConfig(level=logging.INFO) + + +Adzuna.archive_jobs_in_hrflow( + workflow_id=..., + logics=..., + connector_auth=dict( + app_id=..., + app_key=..., + ), + hrflow_auth=dict( + api_secret=..., + api_user=..., + ), + pull_parameters=dict( + country=..., + results_per_page=..., + what=..., + what_and=..., + what_phrase=..., + what_or=..., + what_exclude=..., + title_only=..., + where=..., + distance=..., + location0=..., + location1=..., + location2=..., + location3=..., + location4=..., + location5=..., + location6=..., + location7=..., + max_days_old=..., + category=..., + sort_dir=..., + sort_by=..., + salary_min=..., + salary_max=..., + salary_include_unknown=..., + full_time=..., + part_time=..., + contract=..., + permanent=..., + company=..., + ), + push_parameters=dict( + board_key=..., + ), + format=..., + callback=..., + persist=..., + incremental=... +) +``` \ No newline at end of file diff --git a/src/hrflow_connectors/v2/connectors/adzuna/docs/create_jobs_in_hrflow.md b/src/hrflow_connectors/v2/connectors/adzuna/docs/create_jobs_in_hrflow.md new file mode 100644 index 000000000..09410f224 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/adzuna/docs/create_jobs_in_hrflow.md @@ -0,0 +1,145 @@ +# Create jobs in hrflow +`Adzuna` :arrow_right: `HrFlow` + +Send **created** 'job(s)' _from_ Adzuna _to_ HrFlow + + +**Adzuna endpoint used :** +| Endpoint | Description | +| --------- | ----------- | +| [**Get Adzuna jobs**](https://api.adzuna.com/v1/doc/Search.md) | Use this endpoint to retrieve Adzuna's job advertisement listings. | + + + +## Adzuna Auth Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `app_id` :red_circle: | `string\|null` | None | Application ID, supplied by Adzuna | +| `app_key` :red_circle: | `string\|null` | None | Application key, supplied by Adzuna | + +## HrFlow.ai Auth Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `api_secret` :red_circle: | `string` | None | API Key used to access HrFlow.ai API | +| `api_user` :red_circle: | `string` | None | User email used to access HrFlow.ai API | + +## Pull Parameters (Adzuna) + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `country` :red_circle: | `Literal['at','au','br','ca','de','fr','gb','in','it','nl','nz','pl','ru','sg','us','za']` | None | ISO 8601 country code of the country of interest | +| `results_per_page` | `integer\|null` | 50 | The number of results to include on a page of search results. | +| `what` | `string\|null` | None | The keywords to search for. Multiple terms may be space separated. | +| `what_and` | `string\|null` | None | The keywords to search for, all keywords must be found. | +| `what_phrase` | `string\|null` | None | An entire phrase which must be found in the description or title. | +| `what_or` | `string\|null` | None | The keywords to search for, any keywords may be found. Multiple terms may be space separated. | +| `what_exclude` | `string\|null` | None | Keywords to exclude from the search. Multiple terms may be space separated. | +| `title_only` | `string\|null` | None | Keywords to find, but only in the title. Multiple terms may be space separated. | +| `where` | `string\|null` | None | The geographic centre of the search. Place names, postal codes, etc. may be used. | +| `distance` | `integer\|null` | None | The distance in kilometres from the centre of the place described by the 'where' parameter. Defaults to 5km. | +| `location0` | `string\|null` | None | The location fields may be used to describe a location, in a similar form to that returned in a Adzuna::API::Response::Location object.For example, "location0=UK&location1=South East England&location2=Surrey" will performn a search over the county of Surrey. | +| `location1` | `string\|null` | None | | +| `location2` | `string\|null` | None | | +| `location3` | `string\|null` | None | | +| `location4` | `string\|null` | None | | +| `location5` | `string\|null` | None | | +| `location6` | `string\|null` | None | | +| `location7` | `string\|null` | None | | +| `max_days_old` | `integer\|null` | None | The age of the oldest advertisment in days that will be returned. | +| `category` | `string\|null` | None | The category tag, as returned by the "category" endpoint. | +| `sort_dir` | `Literal['down','up']\|null` | None | The direction to order the search results. | +| `sort_by` | `Literal['date','default','hybrid','relevance','salary']\|null` | None | The ordering of the search results. | +| `salary_min` | `integer\|null` | None | The minimum salary we wish to get results for. | +| `salary_max` | `integer\|null` | None | The maximum salary we wish to get results for. | +| `salary_include_unknown` | `Literal['1']\|null` | None | If set it "1", jobs without a known salary are returned. | +| `full_time` | `Literal['1']\|null` | None | If set to "1", only full time jobs will be returned. | +| `part_time` | `Literal['1']\|null` | None | If set to "1", only part time jobs will be returned. | +| `contract` | `Literal['1']\|null` | None | If set to "1", only contract jobs will be returned. | +| `permanent` | `Literal['1']\|null` | None | If set to "1", only permanent jobs will be returned. | +| `company` | `string\|null` | None | The canonical company name. This may be returned in a Adzuna::API::Response::Company object when a job is returned. A full list of allowed terms in not available through the API. | + +## Push Parameters (HrFlow) + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `board_key` :red_circle: | `string` | None | HrFlow.ai board key | +| `enrich_with_parsing` | `boolean` | False | When enabled jobs are enriched with HrFlow.ai parsing | + +## Other Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `workflow_id` :red_circle: | `string` | None | A stable identifier used for persisting in incremental mode | +| `logics` :red_circle: | `array\|null` | None | A list of functions called in sequence with each item pulled from the origin. Each function might either return it's argument or None to discard the item. Any item discarded is eventually not pushed to the target | +| `format` | `Callable\|null` | None | A formatting function to apply on items pulled before the push | +| `callback` | `Callable\|null` | None | Registers a callback function to be called at the of a successful execution | +| `persist` | `boolean` | True | When False has the effect of running in dry mode. Items are pulled but not pushed to the target | +| `incremental` | `boolean` | False | Controls the incremental reading execution mode | + +:red_circle: : *required* + +## Example + +```python +import logging +from hrflow_connectors.v2 import Adzuna + + +logging.basicConfig(level=logging.INFO) + + +Adzuna.create_jobs_in_hrflow( + workflow_id=..., + logics=..., + connector_auth=dict( + app_id=..., + app_key=..., + ), + hrflow_auth=dict( + api_secret=..., + api_user=..., + ), + pull_parameters=dict( + country=..., + results_per_page=..., + what=..., + what_and=..., + what_phrase=..., + what_or=..., + what_exclude=..., + title_only=..., + where=..., + distance=..., + location0=..., + location1=..., + location2=..., + location3=..., + location4=..., + location5=..., + location6=..., + location7=..., + max_days_old=..., + category=..., + sort_dir=..., + sort_by=..., + salary_min=..., + salary_max=..., + salary_include_unknown=..., + full_time=..., + part_time=..., + contract=..., + permanent=..., + company=..., + ), + push_parameters=dict( + board_key=..., + enrich_with_parsing=..., + ), + format=..., + callback=..., + persist=..., + incremental=... +) +``` \ No newline at end of file diff --git a/src/hrflow_connectors/v2/connectors/adzuna/docs/update_jobs_in_hrflow.md b/src/hrflow_connectors/v2/connectors/adzuna/docs/update_jobs_in_hrflow.md new file mode 100644 index 000000000..5fe33e65e --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/adzuna/docs/update_jobs_in_hrflow.md @@ -0,0 +1,143 @@ +# Update jobs in hrflow +`Adzuna` :arrow_right: `HrFlow` + +Send **updated** 'job(s)' _from_ Adzuna _to_ HrFlow + + +**Adzuna endpoint used :** +| Endpoint | Description | +| --------- | ----------- | +| [**Get Adzuna jobs**](https://api.adzuna.com/v1/doc/Search.md) | Use this endpoint to retrieve Adzuna's job advertisement listings. | + + + +## Adzuna Auth Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `app_id` :red_circle: | `string\|null` | None | Application ID, supplied by Adzuna | +| `app_key` :red_circle: | `string\|null` | None | Application key, supplied by Adzuna | + +## HrFlow.ai Auth Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `api_secret` :red_circle: | `string` | None | API Key used to access HrFlow.ai API | +| `api_user` :red_circle: | `string` | None | User email used to access HrFlow.ai API | + +## Pull Parameters (Adzuna) + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `country` :red_circle: | `Literal['at','au','br','ca','de','fr','gb','in','it','nl','nz','pl','ru','sg','us','za']` | None | ISO 8601 country code of the country of interest | +| `results_per_page` | `integer\|null` | 50 | The number of results to include on a page of search results. | +| `what` | `string\|null` | None | The keywords to search for. Multiple terms may be space separated. | +| `what_and` | `string\|null` | None | The keywords to search for, all keywords must be found. | +| `what_phrase` | `string\|null` | None | An entire phrase which must be found in the description or title. | +| `what_or` | `string\|null` | None | The keywords to search for, any keywords may be found. Multiple terms may be space separated. | +| `what_exclude` | `string\|null` | None | Keywords to exclude from the search. Multiple terms may be space separated. | +| `title_only` | `string\|null` | None | Keywords to find, but only in the title. Multiple terms may be space separated. | +| `where` | `string\|null` | None | The geographic centre of the search. Place names, postal codes, etc. may be used. | +| `distance` | `integer\|null` | None | The distance in kilometres from the centre of the place described by the 'where' parameter. Defaults to 5km. | +| `location0` | `string\|null` | None | The location fields may be used to describe a location, in a similar form to that returned in a Adzuna::API::Response::Location object.For example, "location0=UK&location1=South East England&location2=Surrey" will performn a search over the county of Surrey. | +| `location1` | `string\|null` | None | | +| `location2` | `string\|null` | None | | +| `location3` | `string\|null` | None | | +| `location4` | `string\|null` | None | | +| `location5` | `string\|null` | None | | +| `location6` | `string\|null` | None | | +| `location7` | `string\|null` | None | | +| `max_days_old` | `integer\|null` | None | The age of the oldest advertisment in days that will be returned. | +| `category` | `string\|null` | None | The category tag, as returned by the "category" endpoint. | +| `sort_dir` | `Literal['down','up']\|null` | None | The direction to order the search results. | +| `sort_by` | `Literal['date','default','hybrid','relevance','salary']\|null` | None | The ordering of the search results. | +| `salary_min` | `integer\|null` | None | The minimum salary we wish to get results for. | +| `salary_max` | `integer\|null` | None | The maximum salary we wish to get results for. | +| `salary_include_unknown` | `Literal['1']\|null` | None | If set it "1", jobs without a known salary are returned. | +| `full_time` | `Literal['1']\|null` | None | If set to "1", only full time jobs will be returned. | +| `part_time` | `Literal['1']\|null` | None | If set to "1", only part time jobs will be returned. | +| `contract` | `Literal['1']\|null` | None | If set to "1", only contract jobs will be returned. | +| `permanent` | `Literal['1']\|null` | None | If set to "1", only permanent jobs will be returned. | +| `company` | `string\|null` | None | The canonical company name. This may be returned in a Adzuna::API::Response::Company object when a job is returned. A full list of allowed terms in not available through the API. | + +## Push Parameters (HrFlow) + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `board_key` :red_circle: | `string` | None | HrFlow.ai board key | + +## Other Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `workflow_id` :red_circle: | `string` | None | A stable identifier used for persisting in incremental mode | +| `logics` :red_circle: | `array\|null` | None | A list of functions called in sequence with each item pulled from the origin. Each function might either return it's argument or None to discard the item. Any item discarded is eventually not pushed to the target | +| `format` | `Callable\|null` | None | A formatting function to apply on items pulled before the push | +| `callback` | `Callable\|null` | None | Registers a callback function to be called at the of a successful execution | +| `persist` | `boolean` | True | When False has the effect of running in dry mode. Items are pulled but not pushed to the target | +| `incremental` | `boolean` | False | Controls the incremental reading execution mode | + +:red_circle: : *required* + +## Example + +```python +import logging +from hrflow_connectors.v2 import Adzuna + + +logging.basicConfig(level=logging.INFO) + + +Adzuna.update_jobs_in_hrflow( + workflow_id=..., + logics=..., + connector_auth=dict( + app_id=..., + app_key=..., + ), + hrflow_auth=dict( + api_secret=..., + api_user=..., + ), + pull_parameters=dict( + country=..., + results_per_page=..., + what=..., + what_and=..., + what_phrase=..., + what_or=..., + what_exclude=..., + title_only=..., + where=..., + distance=..., + location0=..., + location1=..., + location2=..., + location3=..., + location4=..., + location5=..., + location6=..., + location7=..., + max_days_old=..., + category=..., + sort_dir=..., + sort_by=..., + salary_min=..., + salary_max=..., + salary_include_unknown=..., + full_time=..., + part_time=..., + contract=..., + permanent=..., + company=..., + ), + push_parameters=dict( + board_key=..., + ), + format=..., + callback=..., + persist=..., + incremental=... +) +``` \ No newline at end of file diff --git a/src/hrflow_connectors/v2/connectors/adzuna/logo.png b/src/hrflow_connectors/v2/connectors/adzuna/logo.png new file mode 100644 index 000000000..24b37ca82 Binary files /dev/null and b/src/hrflow_connectors/v2/connectors/adzuna/logo.png differ diff --git a/src/hrflow_connectors/v2/connectors/adzuna/mappings/format/archive_jobs_in_hrflow.json b/src/hrflow_connectors/v2/connectors/adzuna/mappings/format/archive_jobs_in_hrflow.json new file mode 100644 index 000000000..88224dabb --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/adzuna/mappings/format/archive_jobs_in_hrflow.json @@ -0,0 +1,3 @@ +{ + "reference": "?.id | $string" +} diff --git a/src/hrflow_connectors/v2/connectors/adzuna/mappings/format/create_jobs_in_hrflow.json b/src/hrflow_connectors/v2/connectors/adzuna/mappings/format/create_jobs_in_hrflow.json new file mode 100644 index 000000000..42d354e0a --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/adzuna/mappings/format/create_jobs_in_hrflow.json @@ -0,0 +1,43 @@ +{ + "name": "?.title", + "reference": "?.id | $string", + "created_at": "?.created", + "location": { + "lat": "?.latitude != null ?? .latitude | $float : null", + "lng": "?.longitude != null ?? .longitude | $float : null", + "text": "?.location.display_name || ''" + }, + "url": "?.redirect_url", + "summary": "?.description", + "sections": "?.full_description ?? [{name: 'full_description', title: 'Full Description', description: .full_description}]: []", + "tags": [ + { + "name": "contract_type", + "value": "?.contract_type" + }, + { + "name": "contract_time", + "value": "?.contract_time" + }, + { + "name": "salary_min", + "value": "?.salary_min" + }, + { + "name": "salary_max", + "value": "?.salary_max" + }, + { + "name": "salary_is_predicted", + "value": "?.salary_is_predicted == '1' ?? true : false" + }, + { + "name": "category", + "value": "?.category?.label" + }, + { + "name": "company", + "value": "?.company?.display_name" + } + ] +} diff --git a/src/hrflow_connectors/v2/connectors/adzuna/mappings/format/update_jobs_in_hrflow.json b/src/hrflow_connectors/v2/connectors/adzuna/mappings/format/update_jobs_in_hrflow.json new file mode 100644 index 000000000..42d354e0a --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/adzuna/mappings/format/update_jobs_in_hrflow.json @@ -0,0 +1,43 @@ +{ + "name": "?.title", + "reference": "?.id | $string", + "created_at": "?.created", + "location": { + "lat": "?.latitude != null ?? .latitude | $float : null", + "lng": "?.longitude != null ?? .longitude | $float : null", + "text": "?.location.display_name || ''" + }, + "url": "?.redirect_url", + "summary": "?.description", + "sections": "?.full_description ?? [{name: 'full_description', title: 'Full Description', description: .full_description}]: []", + "tags": [ + { + "name": "contract_type", + "value": "?.contract_type" + }, + { + "name": "contract_time", + "value": "?.contract_time" + }, + { + "name": "salary_min", + "value": "?.salary_min" + }, + { + "name": "salary_max", + "value": "?.salary_max" + }, + { + "name": "salary_is_predicted", + "value": "?.salary_is_predicted == '1' ?? true : false" + }, + { + "name": "category", + "value": "?.category?.label" + }, + { + "name": "company", + "value": "?.company?.display_name" + } + ] +} diff --git a/src/hrflow_connectors/v2/connectors/adzuna/notebooks/.gitkeep b/src/hrflow_connectors/v2/connectors/adzuna/notebooks/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/src/hrflow_connectors/v2/connectors/adzuna/schemas.py b/src/hrflow_connectors/v2/connectors/adzuna/schemas.py new file mode 100644 index 000000000..4acdd0fd9 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/adzuna/schemas.py @@ -0,0 +1,68 @@ +import datetime +import typing as t +from enum import Enum + +import msgspec +from msgspec import Struct + + +class Category(Struct): + tag: str + label: str + + +class Location(msgspec.Struct): + area: t.List[str] + display_name: str + + +class ContractType(str, Enum): + PERMANENT = "permanent" + CONTRACT = "contract" + + +class Flag(str, Enum): + YES = "1" + NO = "0" + + +class ContractTime(str, Enum): + FULL_TIME = "full_time" + PART_TIME = "part_time" + + +class Company(msgspec.Struct): + display_name: str + canonical_name: t.Optional[str] + count: t.Optional[int] + + +class AdzunaJob(Struct): + id: str + created: str + title: str + description: str + full_description: t.Optional[str] + redirect_url: str + latitude: t.Optional[float] + longitude: t.Optional[float] + category: Category + location: Location + salary_min: int + salary_max: int + salary_is_predicted: Flag + company: Company + contract_type: t.Optional[ContractType] + contract_time: t.Optional[ContractTime] + + def __post_init__(self): + self._validate_created() + + def _validate_created(self): + try: + datetime.date.fromisoformat(self.created) + except ValueError: + raise ValueError( + f"Invalid time format given '{self.created}', expected ISO 8601 format" + " (YYYY-MM-DDTHH:MM:SSZ)" + ) diff --git a/src/hrflow_connectors/v2/connectors/adzuna/test-config.yaml b/src/hrflow_connectors/v2/connectors/adzuna/test-config.yaml new file mode 100644 index 000000000..a73b9cce0 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/adzuna/test-config.yaml @@ -0,0 +1,79 @@ +actions: + create_jobs_in_hrflow: + - id: valid_parameters + connector_auth: + app_id: $__APP_ID + app_key: $__APP_KEY + hrflow_auth: + api_secret: $__API_SECRET + api_user: $__API_USER + pull_parameters: + country: "gb" + results_per_page: 20 + what: "javascript developer" + what_exclude: "java" + where: "london" + sort_by: "salary" + salary_min: 90000 + full_time: "1" + permanent: "1" + push_parameters: + board_key: $__BOARD_KEY + status: success + - id: no_client_credentials + connector_auth: {} + hrflow_auth: + api_secret: $__API_SECRET + api_user: $__API_USER + pull_parameters: + what: "javascript developer" + push_parameters: + board_key: $__BOARD_KEY + status: fatal + reason: bad_origin_parameters + - id: no_hrflow_board_key + connector_auth: + app_id: $__APP_ID + app_key: $__APP_KEY + hrflow_auth: + api_secret: $__API_SECRET + api_user: $__API_USER + pull_parameters: + country: "us" + push_parameters: {} + status: fatal + reason: bad_target_parameters + - id: invalid_client_credentials + connector_auth: + app_id: bad_client_id + app_key: bad_client_secret + hrflow_auth: + api_secret: $__API_SECRET + api_user: $__API_USER + pull_parameters: + country: "us" + push_parameters: + board_key: $__BOARD_KEY + status: fatal + reason: read_failure + - id: invalid_hrflow_api_secret + connector_auth: + app_id: $__APP_ID + app_key: $__APP_KEY + hrflow_auth: + api_secret: bad_api_secret + api_user: $__API_USER + pull_parameters: + country: "gb" + results_per_page: 20 + what: "javascript developer" + what_exclude: "java" + where: "london" + sort_by: "salary" + salary_min: 90000 + full_time: "1" + permanent: "1" + push_parameters: + board_key: $__BOARD_KEY + status: fatal + reason: write_failure diff --git a/src/hrflow_connectors/v2/connectors/adzuna/warehouse.py b/src/hrflow_connectors/v2/connectors/adzuna/warehouse.py new file mode 100644 index 000000000..a1040f4ea --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/adzuna/warehouse.py @@ -0,0 +1,4 @@ +from hrflow_connectors.v2.connectors.adzuna.aisles import AuthParameters, JobsAisle +from hrflow_connectors.v2.core.warehouse import Warehouse + +AdzunaWarehouse = Warehouse(auth=AuthParameters, aisles=(JobsAisle,)) diff --git a/src/hrflow_connectors/v2/connectors/francetravail/README.md b/src/hrflow_connectors/v2/connectors/francetravail/README.md new file mode 100644 index 000000000..f58918153 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/francetravail/README.md @@ -0,0 +1,83 @@ +# 📖 Summary +- [📖 Summary](#📖-summary) +- [💼 About France Travail (ex: Pole Emploi)](#💼-about-france-travail-(ex:-pole-emploi)) + - [😍 Why is it a big deal for France Travail (ex: Pole Emploi) customers & partners?](#😍-why-is-it-a-big-deal-for-france-travail-(ex:-pole-emploi)-customers--partners) +- [🔧 How does it work?](#🔧-how-does-it-work) + - [📊 Data integration capabilities:](#📊-data-integration-capabilities) + - [🧠 Artificial Intelligence capabilities:](#🧠-artificial-intelligence-capabilities) +- [🔌 Connector Actions](#🔌-connector-actions) +- [💍 Quick Start Examples](#💍-quick-start-examples) +- [🔗 Useful Links](#🔗-useful-links) +- [👏 Special Thanks](#👏-special-thanks) + + +# 💼 About France Travail (ex: Pole Emploi) + +> France Travail, formerly Pôle emploi until 31 December 2023, is a public administrative body responsible for employment in France. It was created on 19 December 2008 from the merger of the Agence nationale pour l'emploi and the Association pour l'emploi dans l'industrie et le commerce. + +

+ +

+ +## 😍 Why is it a big deal for France Travail (ex: Pole Emploi) customers & partners? + +This new connector will enable: +- ⚡ A Fastlane Talent & Workforce data integration for France Travail (ex: Pole Emploi) customers & partners +- 🤖 Cutting-edge AI-powered Talent Experiences & Recruiter Experiences for France Travail (ex: Pole Emploi) customers + +# 🔧 How does it work? +## 📊 Data integration capabilities: +- ⬅️ Send Profiles data from France Travail (ex: Pole Emploi) to a Destination of your choice. +- ➡️ Send Profiles data from a Source of your choice to France Travail (ex: Pole Emploi). +- ⬅️ Send Jobs data from France Travail (ex: Pole Emploi) to a Destination of your choice. +- ➡️ Send Jobs data from a Source of your choice to France Travail (ex: Pole Emploi). + +

+ + +

+ + +## 🧠 Artificial Intelligence capabilities: +- Extract, Structure, and Categorize Talent & Workforce data +- Search, Score, and Match Profiles & Jobs with our APIs and AI Widgets (**Matching Custom Tab in France Travail (ex: Pole Emploi)**) + + +# 🔌 Connector Actions +

+ +| Action | Description | +| ------- | ----------- | +| [**Create jobs in hrflow**](docs/create_jobs_in_hrflow.md) | Send **created** 'job(s)' _from_ _to_ HrFlow | +| [**Update jobs in hrflow**](docs/update_jobs_in_hrflow.md) | Send **updated** 'job(s)' _from_ _to_ HrFlow | +| [**Archive jobs in hrflow**](docs/archive_jobs_in_hrflow.md) | Send **archived** 'job(s)' _from_ _to_ HrFlow | + + +

+ + +# 💍 Quick Start Examples + +To make sure you can successfully run the latest versions of the example scripts, you have to **install the package from PyPi**. + + +To browse the examples of actions corresponding to released versions of 🤗 this connector, you just need to import the module like this : + +

+ +

+ +Once the connector module is imported, you can leverage all the different actions that it offers. + +For more code details checkout connector code. + + +# 🔗 Useful Links + +- 📄 Visit [France Travail (ex: Pole Emploi)](https://www.francetravail.fr/) to learn more. +- ⚙️ API documentation : (https://francetravail.io/produits-partages/documentation/utilisation-api-france-travail) +- 💻 [Connector code](https://github.com/Riminder/hrflow-connectors/tree/master/src/hrflow_connectors/v2/connectors/francetravail) on our Github. + + +# 👏 Special Thanks +- 💻 HrFlow.ai : [Nedhir Ebnou](https://github.com/nedhirouebnou) - Software Engineer \ No newline at end of file diff --git a/src/hrflow_connectors/v2/connectors/francetravail/__init__.py b/src/hrflow_connectors/v2/connectors/francetravail/__init__.py new file mode 100644 index 000000000..fdbcd4d9a --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/francetravail/__init__.py @@ -0,0 +1,3 @@ +from hrflow_connectors.v2.connectors.francetravail.connector import ( # noqa + FranceTravail, +) diff --git a/src/hrflow_connectors/v2/connectors/francetravail/aisles.py b/src/hrflow_connectors/v2/connectors/francetravail/aisles.py new file mode 100644 index 000000000..584d7aecf --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/francetravail/aisles.py @@ -0,0 +1,662 @@ +import typing as t +from enum import Enum, IntEnum +from logging import LoggerAdapter + +import requests +from msgspec import Meta, Struct +from msgspec import json as msgspec_json +from typing_extensions import Annotated + +from hrflow_connectors.v2.connectors.francetravail.schemas import ( + ExperienceRequirement, + FranceTravailJobOffer, + OfferOriginTag, + validate_date, +) +from hrflow_connectors.v2.core.common import Entity +from hrflow_connectors.v2.core.warehouse import ( + Aisle, + Criterias, + Endpoint, + Endpoints, + ReadOperation, + merge, +) + +API_BASE_URL = "https://api.francetravail.io/partenaire/offresdemploi" +JOBS_SEARCH_URL = ("{}/v2/offres/search").format(API_BASE_URL) + +REFERENCES_URL = ("{}/v2/referentiel/").format(API_BASE_URL) + +SEARCH_JOBS_ENDPOINT = Endpoint( + name="Get all jobs", + description=( + "Endpoint to search offers based on selection criteria. The list of returned" + " offers is paginated.The range of results is limited to 150.The request method" + " is `GET`" + ), + url=JOBS_SEARCH_URL, +) +TOKEN_GENERATOR_URL = ( + "https://entreprise.francetravail.fr/connexion/oauth2/access_token" +) + +GRANT_TYPE = "client_credentials" +TOKEN_SCOPE = "api_offresdemploiv2 o2dsoffre" + +MOTS_CLES_DESCRIPTION = """Search by keyword + +Each keyword (or expression) is at least 2 characters long and must +be separated by a comma. +The search on several keywords is processed via the logical operator "AND". +The keyword search can be used to search on : + +- The title of the offer (title field in the search return) +- The ROME code (romeCode field in the search return) +- The ROME label (field romeLibelle in return for the search) +- The competences label (field competences.libelle in return of the search) +- The wording of the training fields (field formations.domaineLibelle in +return of the research) +- The wording of the permits (field permits.label in return of the search) +- The language label (field languages.label in return of the search) +- The offer description if found in the offer title and/or the ROME label +(description field in the search return) + +Allowed characters: [aA-zZ]+[0-9]+[space]+[@#$%^&+./-""]""" + +MODESELECTIONPARTENAIRES_DESCRIPTION = """Selection mode of the partner offers. + +This filter works with the partner criterion and is dependent on the originOffer +criterion. Possible values with the results obtained according to the two other filters: + +- INCLUS(INCLUDED) +originOffer empty : Returns the PE offers and the Partners listed in the Partners +criterion +originOffer at 2 : Only the offers of the Partners listed in the Partners +criterion +- EXCLU(EXCLUDED) +originOffer empty : Return the offers of PE and Partners not listed in the Partners +criterion +originOffer at 2 : Only the offers of the Partners not listed in the Partners +criterion +Note: In all cases, if originOffer = 1, then only the France Travail (ex: Pole Emploi) +offers will be returned""" + + +class Experience(str, Enum): + LESS_THAN_ONE_YEAR = "1" + ONE_TO_THREE_YEARS = "2" + MORE_THAN_THREE_YEARS = "3" + + +class Qualification(IntEnum): + NON_EXECUTIVE = 0 + EXECUTIVE = 9 + + +class SalaryPeriod(str, Enum): + MONTHLY = "M" + ANNUALLY = "A" + HOURLY = "H" + FEE_FOR_SERVICE = "C" + + +class IndustryDomain(str, Enum): + AGRICULTURE = "A" + ARTS = "B" + BANKING_INSURANCE = "C" + REAL_ESTATE = "C15" + RETAIL = "D" + MEDIA_COMMUNICATION = "E" + CONSTRUCTION = "F" + HOSPITALITY_TOURISM = "G" + INDUSTRY = "H" + INSTALLATION_MAINTENANCE = "I" + HEALTHCARE = "J" + PERSONAL_COMMUNITY_SERVICES = "K" + PERFORMING_ARTS = "L" + SPORT = "L14" + PURCHASING_ACCOUNTING_MANAGEMENT = "M" + EXECUTIVE_MANAGEMENT = "M13" + CONSULTING_RESEARCH = "M14" + HUMAN_RESOURCES = "M15" + SECRETARIAL_ASSISTANTSHIP = "M16" + MARKETING_SALES_STRATEGY = "M17" + COMPUTER_TELECOMMUNICATION = "M18" + TRANSPORTATION_LOGISTICS = "N" + + +class PublishedSince(IntEnum): + ONE_DAY = 1 + THREE_DAYS = 3 + SEVEN_DAYS = 7 + FOURTEEN_DAYS = 14 + THIRTY_ONE_DAYS = 31 + + +class PartnerSelectionMode(str, Enum): + INCLUDE = "INCLUS" + EXCLUDE = "EXCLU" + + +class WeeklyDuration(str, Enum): + NOT_SPECIFIED = "0" + FULL_TIME = "1" + PART_TIME = "2" + + +class AuthParameters(Struct): + client_id: Annotated[ + str, + Meta( + description="Client ID used to access France Travail (ex: Pole Emploi) API", + ), + ] + client_secret: Annotated[ + str, + Meta( + description=( + "Client Secret used to access France Travail (ex: Pole Emploi) API" + ), + ), + ] + + +class ReadJobsParameters(Struct, omit_defaults=True): + range: Annotated[ + t.Optional[str], + Meta( + description=( + "Pagination of data. The range of results is limited to 150. Format:" + " p-d, where :\n\np is the index (starting at 0) of the first element" + " requested, which must not exceed 3000\nd is the index of the last" + " element requested, which must not exceed 3149" + ), + ), + ] = None + sort: Annotated[ + t.Optional[int], + Meta( + description="Sorting of data", + ), + ] = None + domaine: Annotated[ + t.Optional[str], + Meta( + description=( + "Professional field code" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + " to this endpoint :" + f"{REFERENCES_URL}/domaines" + ), + ), + ] = None + codeROME: Annotated[ + t.Optional[str], + Meta( + description=( + "ROME code of the profession" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + " to this endpoint :" + f" {REFERENCES_URL}/metiers" + ), + ), + ] = None + theme: Annotated[ + t.Optional[str], + Meta( + description=( + "Theme of the profession" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + " to this endpoint :" + f" {REFERENCES_URL}/themes" + ), + ), + ] = None + appellation: Annotated[ + t.Optional[str], + Meta( + description=( + "ROME designation code for the offer, see reference below" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + " to this endpoint :" + f" {REFERENCES_URL}/appellations" + ), + ), + ] = None + codeNAF: Annotated[ + t.Optional[str], + Meta( + description=( + "NAF code of the offer (format 99.99X)" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + " to this endpoint :" + f" {REFERENCES_URL}/nafs" + ), + ), + ] = None + secteurActivite: Annotated[ + t.Optional[str], + Meta( + description=( + "NAF codes for sectors of activity. It is possible to specify two NAF" + " codes by separating them with a comma in the character" + " string.Example : 01,02A GET request for the list of accepted choices" + " from the Offres d'emploi API to this endpoint :" + f" {REFERENCES_URL}/secteursActivites" + ), + ), + ] = None + experience: Annotated[ + t.Optional[Experience], + Meta( + description=( + "Level of experience required\nPossible values:\n1 -> Less than 1 year" + " of experience\n2 -> From 1 to 3 years of experience\n3 -> More than 3" + " years of experience" + ), + ), + ] = None + experienceExigence: Annotated[ + t.Optional[ExperienceRequirement], + Meta( + description=( + "Filter offers by experience requirement (D beginner accepted, S" + " experience desired, E experience required)" + ), + ), + ] = None + typeContrat: Annotated[ + t.Optional[str], + Meta( + description=( + "Contract type code" + "Example : CDI,CDD" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + " to this endpoint :" + f" {REFERENCES_URL}/typesContrats" + ), + ), + ] = None + natureContrat: Annotated[ + t.Optional[str], + Meta( + description=( + "Code of the nature of contract" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + " to this endpoint :" + f" {REFERENCES_URL}/naturesContrats" + ), + ), + ] = None + origineOffre: Annotated[ + t.Optional[OfferOriginTag], + Meta( + description=( + "Origin of the offer\nPossible values:\n1 -> Job center\n2 -> Partner" + ), + ), + ] = None + qualification: Annotated[ + t.Optional[Qualification], + Meta( + description=( + "Qualification Code\nPossible values:\n0 -> Non-executive\n9 ->" + " Executive" + ), + ), + ] = None + tempsPlein: Annotated[ + t.Optional[bool], + Meta( + description=( + "Promote the use of the WeeklyDuration filter\nPossible values:\nfalse" + " -> Part-time\ntrue -> Full time\nIf the parameter is not filled, then" + " all the offers are returned" + ), + ), + ] = None + commune: Annotated[ + t.Optional[str], + Meta( + description=( + "INSEE code of the commune" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + "to this endpoint :" + f" {REFERENCES_URL}/communes" + ), + ), + ] = None + distance: Annotated[ + t.Optional[int], + Meta( + description=( + "Kilometric distance of the search radius\nDefault value: 10Note: to" + " obtain only the offers of a specific commune, then you must fill in" + " the parameter 'distance=0'." + ), + ), + ] = None + # distance=0 pour pour obtenir seulement les offres d'une commune spécifique + departement: Annotated[ + t.Optional[str], + Meta( + description=( + "Job department" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + "to this endpoint :" + f" {REFERENCES_URL}/departements" + ), + ), + ] = None + inclureLimitrophes: Annotated[ + t.Optional[bool], + Meta( + description="Include bordering departments in the search", + ), + ] = None + region: Annotated[ + t.Optional[str], + Meta( + description=( + "Code of the region of the offer" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + "to this endpoint :" + f" {REFERENCES_URL}/regions" + ), + ), + ] = None + paysContinent: Annotated[ + t.Optional[str], + Meta( + description=( + "Code of the country or continent of the offer" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + "to this endpoint :" + f" {REFERENCES_URL}/pays" + f"AND {REFERENCES_URL}/continents" + ), + ), + ] = None + niveauFormation: Annotated[ + t.Optional[str], + Meta( + description=( + "Level of education required" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + "to this endpoint :" + f" {REFERENCES_URL}/niveauxFormations" + ), + ), + ] = None + permis: Annotated[ + t.Optional[str], + Meta( + description=( + "Code of the requested license" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + "to this endpoint :" + f" {REFERENCES_URL}/permis" + ), + ), + ] = None + motsCles: Annotated[ + t.Optional[str], + Meta( + description=MOTS_CLES_DESCRIPTION, + ), + ] = None + salaireMin: Annotated[ + t.Optional[float], + Meta( + description=( + "Minimum wage, expressed in Euro.If this data is filled in, the code of" + " the type of minimum wage is mandatory." + ), + ), + ] = None # If this field is set, then periodeSalaire is required. + periodeSalaire: Annotated[ + t.Optional[SalaryPeriod], + Meta( + description=( + "Period for the calculation of the minimum wage.\nIf this data is" + " filled in, the minimum wage is mandatory.\nPossible values:\nM ->" + " Monthly\nA -> Annual\nH -> Hourly\nC -> Fee" + ), + ), + ] = None # If this field is set, then salaireMin is required. + accesTravailleurHandicape: Annotated[ + t.Optional[bool], + Meta( + description="Jobs for which the employer is disabled-friendly", + ), + ] = None + offresMRS: Annotated[ + t.Optional[bool], + Meta( + description=( + " Allows you to search for jobs that offer the simulation recruitment" + " method" + ), + ), + ] = None + grandDomaine: Annotated[ + t.Optional[IndustryDomain], + Meta( + description="Code of the major area of the offer", + ), + ] = None + experienceExige: Annotated[ + t.Optional[ExperienceRequirement], + Meta( + description="Filter offers by experience level.", + ), + ] = None + publieeDepuis: Annotated[ + t.Optional[PublishedSince], + Meta( + description=( + "Maximum number of days since the publication of the offer\nPossible" + " values: 1, 3, 7, 14, 31" + ), + ), + ] = None + minCreationDate: Annotated[ + t.Optional[str], + Meta( + description=( + "Minimum offer creation date.\nIf this data is filled in, the maximum" + " offer creation date is mandatory.\nISO-8601 standard" + " (YYYY-MM-DDTHH:MM:SSZ)" + ), + ), + ] = None # If this field is set, then minCreationDate is required. + maxCreationDate: Annotated[ + t.Optional[str], + Meta( + description=( + "Maximum offer creation date.\nIf this data is filled in, the minimum" + " offer creation date is mandatory.\nISO-8601 standard" + " (YYYY-MM-DDTHH:MM:SSZ)" + ), + ), + ] = None # If this field is set, then maxCreationDate is required. + + partenaires: Annotated[ + t.Optional[str], + Meta( + description=( + " This filter allows you to enter your partner code in order to include" + " or exclude your offers from the results according to the" + " selectionmade in the PartnerSelection mode filter\nIt is possible to" + " enter several codes (separator ','). " + ), + ), + ] = None # Il est possible de saisir plusieurs codes (séparateur ","). + modeSelectionPartenaires: Annotated[ + t.Optional[PartnerSelectionMode], + Meta( + description=MODESELECTIONPARTENAIRES_DESCRIPTION, + ), + ] = None # If this field is set, then maxCreationDate is required. + + dureeHebdo: Annotated[ + t.Optional[WeeklyDuration], + Meta( + description=( + "Filtre les offres selon la durée hebdomadaire.\nValeurs possibles :\n0" + " -> Non précisé\n1 -> Temps plein\n2 -> Temps partiel" + ), + ), + ] = None + dureeHebdoMin: Annotated[ + t.Optional[int], + Meta( + description=( + "Minimum weekly duration of the offer\nThe value must be in HHMM" + " format, for example : 8h => 800 ; 24h30 => 2430" + ), + ), + ] = None # format HHMM + dureeHebdoMax: Annotated[ + t.Optional[int], + Meta( + description=( + "Maximum weekly duration of the offer\nThe value must be in HHMM" + " format, for example: 8h => 800; 24h30 => 2430" + ), + ), + ] = None # format HHMM + dureeContratMin: Annotated[ + t.Optional[float], + Meta( + description=( + "Minimum duration of the sought contract.\nThe search is done in months" + " (ex: 0.5 for 15 days, 1.0 for 1 month,2.0 for 2 months).\nPositive" + " decimal (Decimal separator: '.')" + ), + ), + ] = None + dureeContratMax: Annotated[ + t.Optional[float], + Meta( + description=( + "Maximum duration of the sought contract.\nThe search is made in months" + " (ex: 0.5 for 15 days, 1.0 for 1 month,2.0 for 2 months).\nPositive" + " decimal (Decimal separator: '.')" + ), + ), + ] = None + offresManqueCandidats: Annotated[ + t.Optional[bool], + Meta( + description=( + "Filters offers older than 15 days, with less than 4 applications (of" + " which Pôle emploi is informed)\nfalse -> Offers not concerned\ntrue" + " -> Offers with few candidates" + ), + ), + ] = None + entreprisesAdaptees: Annotated[ + t.Optional[bool], + Meta( + description=( + "Filter the offers where the adapted company allows a disabled worker" + " to exercise a professional activity in conditions adapted to his" + " capacities\nfalse -> Offers not concerned\ntrue -> Offers from" + " adapted companies" + ), + ), + ] = None + + def __post_init__(self): + # Validate date fields + validate_date(self.minCreationDate, "minCreationDate") + validate_date(self.maxCreationDate, "maxCreationDate") + + +def get_poleemploi_auth_token(client_id: str, client_secret: str) -> str: + response = requests.post( + TOKEN_GENERATOR_URL, + headers={ + "Content-Type": "application/x-www-form-urlencoded", + }, + data=dict( + grant_type=GRANT_TYPE, + scope=TOKEN_SCOPE, + client_id=client_id, + client_secret=client_secret, + ), + params=dict( + realm="/partenaire", + ), + ) + if response.status_code != 200: + raise ValueError( + "Failed to get auth token from France Travail (ex: Pole Emploi):" + f" {response.text}" + ) + return response.json()["access_token"] + + +def read( + adapter: LoggerAdapter, + auth_parameters: AuthParameters, + parameters: ReadJobsParameters, + incremental: bool, + incremental_token: t.Optional[str], +) -> t.Iterable[t.Dict]: + token = get_poleemploi_auth_token( + client_id=auth_parameters.client_id, + client_secret=auth_parameters.client_secret, + ) + params = msgspec_json.decode(msgspec_json.encode(parameters), type=dict) + + response = requests.get( + JOBS_SEARCH_URL, + headers={"Authorization": "Bearer {}".format(token)}, + params=params, + ) + if response.status_code // 100 != 2: + adapter.error( + "Failed to pull jobs from France Travail (ex: Pole Emploi) params={}" + " status_code={} response={}".format( + params, response.status_code, response.text + ) + ) + raise Exception("Failed to pull jobs from France Travail (ex: Pole Emploi)") + jobs = response.json()["resultats"] + for job in jobs: + yield job + + +JobsAisle = Aisle( + name=Entity.job, + schema=FranceTravailJobOffer, + read=ReadOperation( + criterias=Criterias( + create=ReadJobsParameters, + update=ReadJobsParameters, + archive=ReadJobsParameters, + ), + function=merge(create=read, update=read, archive=read), + endpoints=Endpoints( + create=SEARCH_JOBS_ENDPOINT, + update=SEARCH_JOBS_ENDPOINT, + archive=SEARCH_JOBS_ENDPOINT, + ), + ), +) diff --git a/src/hrflow_connectors/v2/connectors/francetravail/connector.py b/src/hrflow_connectors/v2/connectors/francetravail/connector.py new file mode 100644 index 000000000..4f9010df4 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/francetravail/connector.py @@ -0,0 +1,138 @@ +import typing as t + +from hrflow_connectors.v2.connectors.francetravail.warehouse import ( + FranceTravailWarehouse, +) +from hrflow_connectors.v2.core.common import Direction, Entity, Mode +from hrflow_connectors.v2.core.connector import Connector, ConnectorType, Flow + + +def get_job_location(pole_emploi_location: t.Optional[t.Dict]) -> t.Dict: + if pole_emploi_location is None: + return dict(lat=None, lng=None, text="") + + return dict( + lat=pole_emploi_location.get("latitude"), + lng=pole_emploi_location.get("longitude"), + text=" ".join( + [ + value + for field in ["libelle", "codePostal"] + if (value := pole_emploi_location.get(field)) is not None + ] + ), + ) + + +def get_sections(job: t.Dict) -> t.List[t.Dict]: + sections = [] + if "entreprise" in job and "description" in job["entreprise"]: + sections.append( + dict( + name="company_description", + title="Company Description", + description=job["entreprise"]["description"], + ) + ) + return sections + + +def get_requirements(pole_emploi_formations: t.List[t.Dict]) -> t.Optional[str]: + requirements = "\n".join( + [ + f"{formation['niveauLibelle']} en {formation['domaineLibelle']}" + for formation in pole_emploi_formations + if formation.get("niveauLibelle") and formation.get("domaineLibelle") + ] + ) + return requirements if requirements else None + + +def get_tags(job: t.Dict) -> t.List[t.Dict]: + contact = job.get("contact", {}) + salary = job.get("salaire", {}) + tags = [] + + # Helper function to create tag dictionaries + create_tag = lambda name, value: dict(name=name, value=value) + + tags = [ + create_tag("rome_code", job.get("romeCode")), + create_tag("rome_label", job.get("romeLibelle")), + create_tag("contract_nature", job.get("natureContrat")), + create_tag("contract_type", job.get("typeContratLibelle")), + create_tag("accessible_to_disabled", job.get("accessibleTH")), + create_tag("is_apprenticeship", job.get("alternance")), + create_tag("experience_required", job.get("experienceExige") == "E"), + create_tag("experience_description", job.get("experienceLibelle")), + create_tag("salary_description", salary.get("libelle")), + create_tag("working_hours_description", job.get("dureeTravailLibelle")), + create_tag("working_hours_type", job.get("dureeTravailLibelleConverti")), + create_tag("number_of_positions", job.get("nombrePostes")), + create_tag("qualification_label", job.get("qualificationLibelle")), + create_tag("sector_of_activity", job.get("secteurActiviteLibelle")), + create_tag("company_name", job.get("entreprise", {}).get("nom")), + create_tag("company_description", job.get("entreprise", {}).get("description")), + create_tag("company_website", job.get("entreprise", {}).get("url")), + create_tag("recruiter_name", contact.get("nom")), + create_tag("recruiter_email", contact.get("courriel")), + create_tag("recruiter_phone", contact.get("telephone")), + create_tag("recruiter_website", contact.get("urlRecruteur")), + create_tag("application_url", job.get("urlPostulation")), + ] + return tags + + +def format_job( + pole_emploi_job: t.Dict, +) -> t.Dict: + job = dict( + name=pole_emploi_job.get("intitule"), + reference=pole_emploi_job.get("id"), + created_at=pole_emploi_job.get("dateCreation"), + updated_at=pole_emploi_job.get("dateActualisation"), + location=get_job_location(pole_emploi_job.get("lieuTravail")), + url=pole_emploi_job.get("origineOffre", {}).get("urlOrigine"), + summary=pole_emploi_job.get("description"), + requirements=get_requirements(pole_emploi_job.get("formations", [])), + skills=[ + dict(name=skill["libelle"], value=None, type="hard") + for skill in pole_emploi_job.get("competences", []) + ], + languages=[ + dict(name=language["libelle"], value=None) + for language in pole_emploi_job.get("langues", []) + ], + sections=get_sections(pole_emploi_job), + tags=get_tags(pole_emploi_job), + ) + return job + + +DESCRIPTION = ( + "France Travail, formerly Pôle emploi until 31 December 2023, is a public" + " administrative body responsible for employment in France. It was created on 19" + " December 2008 from the merger of the Agence nationale pour l'emploi and the" + " Association pour l'emploi dans l'industrie et le commerce." +) + + +def format_archive( + pole_emploi_job: t.Dict, +) -> t.Dict: + return dict(reference=pole_emploi_job.get("id")) + + +FranceTravail = Connector( + name="France Travail (ex: Pole Emploi)", + type=ConnectorType.JobBoard, + subtype="francetravail", + description=DESCRIPTION, + url="https://www.francetravail.fr/", + warehouse=FranceTravailWarehouse, + flows=( + Flow(Mode.create, Entity.job, Direction.inbound, format=format_job), + Flow(Mode.update, Entity.job, Direction.inbound, format=format_job), + Flow(Mode.archive, Entity.job, Direction.inbound, format=format_archive), + ), +) diff --git a/src/hrflow_connectors/v2/connectors/francetravail/connector.pyi b/src/hrflow_connectors/v2/connectors/francetravail/connector.pyi new file mode 100644 index 000000000..3923755d1 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/francetravail/connector.pyi @@ -0,0 +1,9 @@ +# This file is generated automatically +from hrflow_connectors.v2.core.connector import Connector, PublicActionInterface + +class FranceTravailProto(Connector): + create_jobs_in_hrflow: PublicActionInterface + update_jobs_in_hrflow: PublicActionInterface + archive_jobs_in_hrflow: PublicActionInterface + +FranceTravail: FranceTravailProto \ No newline at end of file diff --git a/src/hrflow_connectors/v2/connectors/francetravail/docs/archive_jobs_in_hrflow.md b/src/hrflow_connectors/v2/connectors/francetravail/docs/archive_jobs_in_hrflow.md new file mode 100644 index 000000000..f23853658 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/francetravail/docs/archive_jobs_in_hrflow.md @@ -0,0 +1,245 @@ +# Archive jobs in hrflow +`France Travail (ex: Pole Emploi)` :arrow_right: `HrFlow` + +Send **archived** 'job(s)' _from_ France Travail (ex: Pole Emploi) _to_ HrFlow + + +**France Travail (ex: Pole Emploi) endpoint used :** +| Endpoint | Description | +| --------- | ----------- | +| [**Get all jobs**](https://api.francetravail.io/partenaire/offresdemploi/v2/offres/search) | Endpoint to search offers based on selection criteria. The list of returned offers is paginated.The range of results is limited to 150.The request method is `GET` | + + + +## France Travail (ex: Pole Emploi) Auth Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `client_id` :red_circle: | `string` | None | Client ID used to access France Travail (ex: Pole Emploi) API | +| `client_secret` :red_circle: | `string` | None | Client Secret used to access France Travail (ex: Pole Emploi) API | + +## HrFlow.ai Auth Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `api_secret` :red_circle: | `string` | None | API Key used to access HrFlow.ai API | +| `api_user` :red_circle: | `string` | None | User email used to access HrFlow.ai API | + +## Pull Parameters (France Travail (ex: Pole Emploi)) + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `range` | `string\|null` | None | Pagination of data. The range of results is limited to 150. Format: p-d, where : + +p is the index (starting at 0) of the first element requested, which must not exceed 3000 +d is the index of the last element requested, which must not exceed 3149 | +| `sort` | `integer\|null` | None | Sorting of data | +| `domaine` | `string\|null` | None | Professional field codeA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint :https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//domaines | +| `codeROME` | `string\|null` | None | ROME code of the professionA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//metiers | +| `theme` | `string\|null` | None | Theme of the professionA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//themes | +| `appellation` | `string\|null` | None | ROME designation code for the offer, see reference belowA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//appellations | +| `codeNAF` | `string\|null` | None | NAF code of the offer (format 99.99X)A GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//nafs | +| `secteurActivite` | `string\|null` | None | NAF codes for sectors of activity. It is possible to specify two NAF codes by separating them with a comma in the character string.Example : 01,02A GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//secteursActivites | +| `experience` | `Literal['1','2','3']\|null` | None | Level of experience required +Possible values: +1 -> Less than 1 year of experience +2 -> From 1 to 3 years of experience +3 -> More than 3 years of experience | +| `experienceExigence` | `Literal['D','E','S']\|null` | None | Filter offers by experience requirement (D beginner accepted, S experience desired, E experience required) | +| `typeContrat` | `string\|null` | None | Contract type codeExample : CDI,CDDA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//typesContrats | +| `natureContrat` | `string\|null` | None | Code of the nature of contractA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//naturesContrats | +| `origineOffre` | `Literal['1','2']\|null` | None | Origin of the offer +Possible values: +1 -> Job center +2 -> Partner | +| `qualification` | `Literal['0','9']\|null` | None | Qualification Code +Possible values: +0 -> Non-executive +9 -> Executive | +| `tempsPlein` | `boolean\|null` | None | Promote the use of the WeeklyDuration filter +Possible values: +false -> Part-time +true -> Full time +If the parameter is not filled, then all the offers are returned | +| `commune` | `string\|null` | None | INSEE code of the communeA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//communes | +| `distance` | `integer\|null` | None | Kilometric distance of the search radius +Default value: 10Note: to obtain only the offers of a specific commune, then you must fill in the parameter 'distance=0'. | +| `departement` | `string\|null` | None | Job departmentA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//departements | +| `inclureLimitrophes` | `boolean\|null` | None | Include bordering departments in the search | +| `region` | `string\|null` | None | Code of the region of the offerA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//regions | +| `paysContinent` | `string\|null` | None | Code of the country or continent of the offerA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//paysAND https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//continents | +| `niveauFormation` | `string\|null` | None | Level of education requiredA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//niveauxFormations | +| `permis` | `string\|null` | None | Code of the requested licenseA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//permis | +| `motsCles` | `string\|null` | None | Search by keyword + +Each keyword (or expression) is at least 2 characters long and must +be separated by a comma. +The search on several keywords is processed via the logical operator "AND". +The keyword search can be used to search on : + +- The title of the offer (title field in the search return) +- The ROME code (romeCode field in the search return) +- The ROME label (field romeLibelle in return for the search) +- The competences label (field competences.libelle in return of the search) +- The wording of the training fields (field formations.domaineLibelle in +return of the research) +- The wording of the permits (field permits.label in return of the search) +- The language label (field languages.label in return of the search) +- The offer description if found in the offer title and/or the ROME label +(description field in the search return) + +Allowed characters: [aA-zZ]+[0-9]+[space]+[@#$%^&+./-""] | +| `salaireMin` | `number\|null` | None | Minimum wage, expressed in Euro.If this data is filled in, the code of the type of minimum wage is mandatory. | +| `periodeSalaire` | `Literal['A','C','H','M']\|null` | None | Period for the calculation of the minimum wage. +If this data is filled in, the minimum wage is mandatory. +Possible values: +M -> Monthly +A -> Annual +H -> Hourly +C -> Fee | +| `accesTravailleurHandicape` | `boolean\|null` | None | Jobs for which the employer is disabled-friendly | +| `offresMRS` | `boolean\|null` | None | Allows you to search for jobs that offer the simulation recruitment method | +| `grandDomaine` | `Literal['A','B','C','C15','D','E','F','G','H','I','J','K','L','L14','M','M13','M14','M15','M16','M17','M18','N']\|null` | None | Code of the major area of the offer | +| `experienceExige` | `Literal['D','E','S']\|null` | None | Filter offers by experience level. | +| `publieeDepuis` | `Literal['1','3','7','14','31']\|null` | None | Maximum number of days since the publication of the offer +Possible values: 1, 3, 7, 14, 31 | +| `minCreationDate` | `string\|null` | None | Minimum offer creation date. +If this data is filled in, the maximum offer creation date is mandatory. +ISO-8601 standard (YYYY-MM-DDTHH:MM:SSZ) | +| `maxCreationDate` | `string\|null` | None | Maximum offer creation date. +If this data is filled in, the minimum offer creation date is mandatory. +ISO-8601 standard (YYYY-MM-DDTHH:MM:SSZ) | +| `partenaires` | `string\|null` | None | This filter allows you to enter your partner code in order to include or exclude your offers from the results according to the selectionmade in the PartnerSelection mode filter +It is possible to enter several codes (separator ','). | +| `modeSelectionPartenaires` | `Literal['EXCLU','INCLUS']\|null` | None | Selection mode of the partner offers. + +This filter works with the partner criterion and is dependent on the originOffer +criterion. Possible values with the results obtained according to the two other filters: + +- INCLUS(INCLUDED) +originOffer empty : Returns the PE offers and the Partners listed in the Partners +criterion +originOffer at 2 : Only the offers of the Partners listed in the Partners +criterion +- EXCLU(EXCLUDED) +originOffer empty : Return the offers of PE and Partners not listed in the Partners +criterion +originOffer at 2 : Only the offers of the Partners not listed in the Partners +criterion +Note: In all cases, if originOffer = 1, then only the France Travail (ex: Pole Emploi) +offers will be returned | +| `dureeHebdo` | `Literal['0','1','2']\|null` | None | Filtre les offres selon la durée hebdomadaire. +Valeurs possibles : +0 -> Non précisé +1 -> Temps plein +2 -> Temps partiel | +| `dureeHebdoMin` | `integer\|null` | None | Minimum weekly duration of the offer +The value must be in HHMM format, for example : 8h => 800 ; 24h30 => 2430 | +| `dureeHebdoMax` | `integer\|null` | None | Maximum weekly duration of the offer +The value must be in HHMM format, for example: 8h => 800; 24h30 => 2430 | +| `dureeContratMin` | `number\|null` | None | Minimum duration of the sought contract. +The search is done in months (ex: 0.5 for 15 days, 1.0 for 1 month,2.0 for 2 months). +Positive decimal (Decimal separator: '.') | +| `dureeContratMax` | `number\|null` | None | Maximum duration of the sought contract. +The search is made in months (ex: 0.5 for 15 days, 1.0 for 1 month,2.0 for 2 months). +Positive decimal (Decimal separator: '.') | +| `offresManqueCandidats` | `boolean\|null` | None | Filters offers older than 15 days, with less than 4 applications (of which Pôle emploi is informed) +false -> Offers not concerned +true -> Offers with few candidates | +| `entreprisesAdaptees` | `boolean\|null` | None | Filter the offers where the adapted company allows a disabled worker to exercise a professional activity in conditions adapted to his capacities +false -> Offers not concerned +true -> Offers from adapted companies | + +## Push Parameters (HrFlow) + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `board_key` :red_circle: | `string` | None | HrFlow.ai board key | + +## Other Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `workflow_id` :red_circle: | `string` | None | A stable identifier used for persisting in incremental mode | +| `logics` :red_circle: | `array\|null` | None | A list of functions called in sequence with each item pulled from the origin. Each function might either return it's argument or None to discard the item. Any item discarded is eventually not pushed to the target | +| `format` | `Callable\|null` | None | A formatting function to apply on items pulled before the push | +| `callback` | `Callable\|null` | None | Registers a callback function to be called at the of a successful execution | +| `persist` | `boolean` | True | When False has the effect of running in dry mode. Items are pulled but not pushed to the target | +| `incremental` | `boolean` | False | Controls the incremental reading execution mode | + +:red_circle: : *required* + +## Example + +```python +import logging +from hrflow_connectors.v2 import FranceTravail + + +logging.basicConfig(level=logging.INFO) + + +FranceTravail.archive_jobs_in_hrflow( + workflow_id=..., + logics=..., + connector_auth=dict( + client_id=..., + client_secret=..., + ), + hrflow_auth=dict( + api_secret=..., + api_user=..., + ), + pull_parameters=dict( + range=..., + sort=..., + domaine=..., + codeROME=..., + theme=..., + appellation=..., + codeNAF=..., + secteurActivite=..., + experience=..., + experienceExigence=..., + typeContrat=..., + natureContrat=..., + origineOffre=..., + qualification=..., + tempsPlein=..., + commune=..., + distance=..., + departement=..., + inclureLimitrophes=..., + region=..., + paysContinent=..., + niveauFormation=..., + permis=..., + motsCles=..., + salaireMin=..., + periodeSalaire=..., + accesTravailleurHandicape=..., + offresMRS=..., + grandDomaine=..., + experienceExige=..., + publieeDepuis=..., + minCreationDate=..., + maxCreationDate=..., + partenaires=..., + modeSelectionPartenaires=..., + dureeHebdo=..., + dureeHebdoMin=..., + dureeHebdoMax=..., + dureeContratMin=..., + dureeContratMax=..., + offresManqueCandidats=..., + entreprisesAdaptees=..., + ), + push_parameters=dict( + board_key=..., + ), + format=..., + callback=..., + persist=..., + incremental=... +) +``` \ No newline at end of file diff --git a/src/hrflow_connectors/v2/connectors/francetravail/docs/create_jobs_in_hrflow.md b/src/hrflow_connectors/v2/connectors/francetravail/docs/create_jobs_in_hrflow.md new file mode 100644 index 000000000..e7e502c37 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/francetravail/docs/create_jobs_in_hrflow.md @@ -0,0 +1,247 @@ +# Create jobs in hrflow +`France Travail (ex: Pole Emploi)` :arrow_right: `HrFlow` + +Send **created** 'job(s)' _from_ France Travail (ex: Pole Emploi) _to_ HrFlow + + +**France Travail (ex: Pole Emploi) endpoint used :** +| Endpoint | Description | +| --------- | ----------- | +| [**Get all jobs**](https://api.francetravail.io/partenaire/offresdemploi/v2/offres/search) | Endpoint to search offers based on selection criteria. The list of returned offers is paginated.The range of results is limited to 150.The request method is `GET` | + + + +## France Travail (ex: Pole Emploi) Auth Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `client_id` :red_circle: | `string` | None | Client ID used to access France Travail (ex: Pole Emploi) API | +| `client_secret` :red_circle: | `string` | None | Client Secret used to access France Travail (ex: Pole Emploi) API | + +## HrFlow.ai Auth Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `api_secret` :red_circle: | `string` | None | API Key used to access HrFlow.ai API | +| `api_user` :red_circle: | `string` | None | User email used to access HrFlow.ai API | + +## Pull Parameters (France Travail (ex: Pole Emploi)) + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `range` | `string\|null` | None | Pagination of data. The range of results is limited to 150. Format: p-d, where : + +p is the index (starting at 0) of the first element requested, which must not exceed 3000 +d is the index of the last element requested, which must not exceed 3149 | +| `sort` | `integer\|null` | None | Sorting of data | +| `domaine` | `string\|null` | None | Professional field codeA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint :https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//domaines | +| `codeROME` | `string\|null` | None | ROME code of the professionA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//metiers | +| `theme` | `string\|null` | None | Theme of the professionA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//themes | +| `appellation` | `string\|null` | None | ROME designation code for the offer, see reference belowA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//appellations | +| `codeNAF` | `string\|null` | None | NAF code of the offer (format 99.99X)A GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//nafs | +| `secteurActivite` | `string\|null` | None | NAF codes for sectors of activity. It is possible to specify two NAF codes by separating them with a comma in the character string.Example : 01,02A GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//secteursActivites | +| `experience` | `Literal['1','2','3']\|null` | None | Level of experience required +Possible values: +1 -> Less than 1 year of experience +2 -> From 1 to 3 years of experience +3 -> More than 3 years of experience | +| `experienceExigence` | `Literal['D','E','S']\|null` | None | Filter offers by experience requirement (D beginner accepted, S experience desired, E experience required) | +| `typeContrat` | `string\|null` | None | Contract type codeExample : CDI,CDDA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//typesContrats | +| `natureContrat` | `string\|null` | None | Code of the nature of contractA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//naturesContrats | +| `origineOffre` | `Literal['1','2']\|null` | None | Origin of the offer +Possible values: +1 -> Job center +2 -> Partner | +| `qualification` | `Literal['0','9']\|null` | None | Qualification Code +Possible values: +0 -> Non-executive +9 -> Executive | +| `tempsPlein` | `boolean\|null` | None | Promote the use of the WeeklyDuration filter +Possible values: +false -> Part-time +true -> Full time +If the parameter is not filled, then all the offers are returned | +| `commune` | `string\|null` | None | INSEE code of the communeA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//communes | +| `distance` | `integer\|null` | None | Kilometric distance of the search radius +Default value: 10Note: to obtain only the offers of a specific commune, then you must fill in the parameter 'distance=0'. | +| `departement` | `string\|null` | None | Job departmentA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//departements | +| `inclureLimitrophes` | `boolean\|null` | None | Include bordering departments in the search | +| `region` | `string\|null` | None | Code of the region of the offerA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//regions | +| `paysContinent` | `string\|null` | None | Code of the country or continent of the offerA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//paysAND https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//continents | +| `niveauFormation` | `string\|null` | None | Level of education requiredA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//niveauxFormations | +| `permis` | `string\|null` | None | Code of the requested licenseA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//permis | +| `motsCles` | `string\|null` | None | Search by keyword + +Each keyword (or expression) is at least 2 characters long and must +be separated by a comma. +The search on several keywords is processed via the logical operator "AND". +The keyword search can be used to search on : + +- The title of the offer (title field in the search return) +- The ROME code (romeCode field in the search return) +- The ROME label (field romeLibelle in return for the search) +- The competences label (field competences.libelle in return of the search) +- The wording of the training fields (field formations.domaineLibelle in +return of the research) +- The wording of the permits (field permits.label in return of the search) +- The language label (field languages.label in return of the search) +- The offer description if found in the offer title and/or the ROME label +(description field in the search return) + +Allowed characters: [aA-zZ]+[0-9]+[space]+[@#$%^&+./-""] | +| `salaireMin` | `number\|null` | None | Minimum wage, expressed in Euro.If this data is filled in, the code of the type of minimum wage is mandatory. | +| `periodeSalaire` | `Literal['A','C','H','M']\|null` | None | Period for the calculation of the minimum wage. +If this data is filled in, the minimum wage is mandatory. +Possible values: +M -> Monthly +A -> Annual +H -> Hourly +C -> Fee | +| `accesTravailleurHandicape` | `boolean\|null` | None | Jobs for which the employer is disabled-friendly | +| `offresMRS` | `boolean\|null` | None | Allows you to search for jobs that offer the simulation recruitment method | +| `grandDomaine` | `Literal['A','B','C','C15','D','E','F','G','H','I','J','K','L','L14','M','M13','M14','M15','M16','M17','M18','N']\|null` | None | Code of the major area of the offer | +| `experienceExige` | `Literal['D','E','S']\|null` | None | Filter offers by experience level. | +| `publieeDepuis` | `Literal['1','3','7','14','31']\|null` | None | Maximum number of days since the publication of the offer +Possible values: 1, 3, 7, 14, 31 | +| `minCreationDate` | `string\|null` | None | Minimum offer creation date. +If this data is filled in, the maximum offer creation date is mandatory. +ISO-8601 standard (YYYY-MM-DDTHH:MM:SSZ) | +| `maxCreationDate` | `string\|null` | None | Maximum offer creation date. +If this data is filled in, the minimum offer creation date is mandatory. +ISO-8601 standard (YYYY-MM-DDTHH:MM:SSZ) | +| `partenaires` | `string\|null` | None | This filter allows you to enter your partner code in order to include or exclude your offers from the results according to the selectionmade in the PartnerSelection mode filter +It is possible to enter several codes (separator ','). | +| `modeSelectionPartenaires` | `Literal['EXCLU','INCLUS']\|null` | None | Selection mode of the partner offers. + +This filter works with the partner criterion and is dependent on the originOffer +criterion. Possible values with the results obtained according to the two other filters: + +- INCLUS(INCLUDED) +originOffer empty : Returns the PE offers and the Partners listed in the Partners +criterion +originOffer at 2 : Only the offers of the Partners listed in the Partners +criterion +- EXCLU(EXCLUDED) +originOffer empty : Return the offers of PE and Partners not listed in the Partners +criterion +originOffer at 2 : Only the offers of the Partners not listed in the Partners +criterion +Note: In all cases, if originOffer = 1, then only the France Travail (ex: Pole Emploi) +offers will be returned | +| `dureeHebdo` | `Literal['0','1','2']\|null` | None | Filtre les offres selon la durée hebdomadaire. +Valeurs possibles : +0 -> Non précisé +1 -> Temps plein +2 -> Temps partiel | +| `dureeHebdoMin` | `integer\|null` | None | Minimum weekly duration of the offer +The value must be in HHMM format, for example : 8h => 800 ; 24h30 => 2430 | +| `dureeHebdoMax` | `integer\|null` | None | Maximum weekly duration of the offer +The value must be in HHMM format, for example: 8h => 800; 24h30 => 2430 | +| `dureeContratMin` | `number\|null` | None | Minimum duration of the sought contract. +The search is done in months (ex: 0.5 for 15 days, 1.0 for 1 month,2.0 for 2 months). +Positive decimal (Decimal separator: '.') | +| `dureeContratMax` | `number\|null` | None | Maximum duration of the sought contract. +The search is made in months (ex: 0.5 for 15 days, 1.0 for 1 month,2.0 for 2 months). +Positive decimal (Decimal separator: '.') | +| `offresManqueCandidats` | `boolean\|null` | None | Filters offers older than 15 days, with less than 4 applications (of which Pôle emploi is informed) +false -> Offers not concerned +true -> Offers with few candidates | +| `entreprisesAdaptees` | `boolean\|null` | None | Filter the offers where the adapted company allows a disabled worker to exercise a professional activity in conditions adapted to his capacities +false -> Offers not concerned +true -> Offers from adapted companies | + +## Push Parameters (HrFlow) + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `board_key` :red_circle: | `string` | None | HrFlow.ai board key | +| `enrich_with_parsing` | `boolean` | False | When enabled jobs are enriched with HrFlow.ai parsing | + +## Other Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `workflow_id` :red_circle: | `string` | None | A stable identifier used for persisting in incremental mode | +| `logics` :red_circle: | `array\|null` | None | A list of functions called in sequence with each item pulled from the origin. Each function might either return it's argument or None to discard the item. Any item discarded is eventually not pushed to the target | +| `format` | `Callable\|null` | None | A formatting function to apply on items pulled before the push | +| `callback` | `Callable\|null` | None | Registers a callback function to be called at the of a successful execution | +| `persist` | `boolean` | True | When False has the effect of running in dry mode. Items are pulled but not pushed to the target | +| `incremental` | `boolean` | False | Controls the incremental reading execution mode | + +:red_circle: : *required* + +## Example + +```python +import logging +from hrflow_connectors.v2 import FranceTravail + + +logging.basicConfig(level=logging.INFO) + + +FranceTravail.create_jobs_in_hrflow( + workflow_id=..., + logics=..., + connector_auth=dict( + client_id=..., + client_secret=..., + ), + hrflow_auth=dict( + api_secret=..., + api_user=..., + ), + pull_parameters=dict( + range=..., + sort=..., + domaine=..., + codeROME=..., + theme=..., + appellation=..., + codeNAF=..., + secteurActivite=..., + experience=..., + experienceExigence=..., + typeContrat=..., + natureContrat=..., + origineOffre=..., + qualification=..., + tempsPlein=..., + commune=..., + distance=..., + departement=..., + inclureLimitrophes=..., + region=..., + paysContinent=..., + niveauFormation=..., + permis=..., + motsCles=..., + salaireMin=..., + periodeSalaire=..., + accesTravailleurHandicape=..., + offresMRS=..., + grandDomaine=..., + experienceExige=..., + publieeDepuis=..., + minCreationDate=..., + maxCreationDate=..., + partenaires=..., + modeSelectionPartenaires=..., + dureeHebdo=..., + dureeHebdoMin=..., + dureeHebdoMax=..., + dureeContratMin=..., + dureeContratMax=..., + offresManqueCandidats=..., + entreprisesAdaptees=..., + ), + push_parameters=dict( + board_key=..., + enrich_with_parsing=..., + ), + format=..., + callback=..., + persist=..., + incremental=... +) +``` \ No newline at end of file diff --git a/src/hrflow_connectors/v2/connectors/francetravail/docs/update_jobs_in_hrflow.md b/src/hrflow_connectors/v2/connectors/francetravail/docs/update_jobs_in_hrflow.md new file mode 100644 index 000000000..d43ddec97 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/francetravail/docs/update_jobs_in_hrflow.md @@ -0,0 +1,245 @@ +# Update jobs in hrflow +`France Travail (ex: Pole Emploi)` :arrow_right: `HrFlow` + +Send **updated** 'job(s)' _from_ France Travail (ex: Pole Emploi) _to_ HrFlow + + +**France Travail (ex: Pole Emploi) endpoint used :** +| Endpoint | Description | +| --------- | ----------- | +| [**Get all jobs**](https://api.francetravail.io/partenaire/offresdemploi/v2/offres/search) | Endpoint to search offers based on selection criteria. The list of returned offers is paginated.The range of results is limited to 150.The request method is `GET` | + + + +## France Travail (ex: Pole Emploi) Auth Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `client_id` :red_circle: | `string` | None | Client ID used to access France Travail (ex: Pole Emploi) API | +| `client_secret` :red_circle: | `string` | None | Client Secret used to access France Travail (ex: Pole Emploi) API | + +## HrFlow.ai Auth Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `api_secret` :red_circle: | `string` | None | API Key used to access HrFlow.ai API | +| `api_user` :red_circle: | `string` | None | User email used to access HrFlow.ai API | + +## Pull Parameters (France Travail (ex: Pole Emploi)) + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `range` | `string\|null` | None | Pagination of data. The range of results is limited to 150. Format: p-d, where : + +p is the index (starting at 0) of the first element requested, which must not exceed 3000 +d is the index of the last element requested, which must not exceed 3149 | +| `sort` | `integer\|null` | None | Sorting of data | +| `domaine` | `string\|null` | None | Professional field codeA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint :https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//domaines | +| `codeROME` | `string\|null` | None | ROME code of the professionA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//metiers | +| `theme` | `string\|null` | None | Theme of the professionA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//themes | +| `appellation` | `string\|null` | None | ROME designation code for the offer, see reference belowA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//appellations | +| `codeNAF` | `string\|null` | None | NAF code of the offer (format 99.99X)A GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//nafs | +| `secteurActivite` | `string\|null` | None | NAF codes for sectors of activity. It is possible to specify two NAF codes by separating them with a comma in the character string.Example : 01,02A GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//secteursActivites | +| `experience` | `Literal['1','2','3']\|null` | None | Level of experience required +Possible values: +1 -> Less than 1 year of experience +2 -> From 1 to 3 years of experience +3 -> More than 3 years of experience | +| `experienceExigence` | `Literal['D','E','S']\|null` | None | Filter offers by experience requirement (D beginner accepted, S experience desired, E experience required) | +| `typeContrat` | `string\|null` | None | Contract type codeExample : CDI,CDDA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//typesContrats | +| `natureContrat` | `string\|null` | None | Code of the nature of contractA GET request for the list of accepted choices from the Offres d'emploi API to this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//naturesContrats | +| `origineOffre` | `Literal['1','2']\|null` | None | Origin of the offer +Possible values: +1 -> Job center +2 -> Partner | +| `qualification` | `Literal['0','9']\|null` | None | Qualification Code +Possible values: +0 -> Non-executive +9 -> Executive | +| `tempsPlein` | `boolean\|null` | None | Promote the use of the WeeklyDuration filter +Possible values: +false -> Part-time +true -> Full time +If the parameter is not filled, then all the offers are returned | +| `commune` | `string\|null` | None | INSEE code of the communeA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//communes | +| `distance` | `integer\|null` | None | Kilometric distance of the search radius +Default value: 10Note: to obtain only the offers of a specific commune, then you must fill in the parameter 'distance=0'. | +| `departement` | `string\|null` | None | Job departmentA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//departements | +| `inclureLimitrophes` | `boolean\|null` | None | Include bordering departments in the search | +| `region` | `string\|null` | None | Code of the region of the offerA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//regions | +| `paysContinent` | `string\|null` | None | Code of the country or continent of the offerA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//paysAND https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//continents | +| `niveauFormation` | `string\|null` | None | Level of education requiredA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//niveauxFormations | +| `permis` | `string\|null` | None | Code of the requested licenseA GET request for the list of accepted choices from the Offres d'emploi APIto this endpoint : https://api.francetravail.io/partenaire/offresdemploi/v2/referentiel//permis | +| `motsCles` | `string\|null` | None | Search by keyword + +Each keyword (or expression) is at least 2 characters long and must +be separated by a comma. +The search on several keywords is processed via the logical operator "AND". +The keyword search can be used to search on : + +- The title of the offer (title field in the search return) +- The ROME code (romeCode field in the search return) +- The ROME label (field romeLibelle in return for the search) +- The competences label (field competences.libelle in return of the search) +- The wording of the training fields (field formations.domaineLibelle in +return of the research) +- The wording of the permits (field permits.label in return of the search) +- The language label (field languages.label in return of the search) +- The offer description if found in the offer title and/or the ROME label +(description field in the search return) + +Allowed characters: [aA-zZ]+[0-9]+[space]+[@#$%^&+./-""] | +| `salaireMin` | `number\|null` | None | Minimum wage, expressed in Euro.If this data is filled in, the code of the type of minimum wage is mandatory. | +| `periodeSalaire` | `Literal['A','C','H','M']\|null` | None | Period for the calculation of the minimum wage. +If this data is filled in, the minimum wage is mandatory. +Possible values: +M -> Monthly +A -> Annual +H -> Hourly +C -> Fee | +| `accesTravailleurHandicape` | `boolean\|null` | None | Jobs for which the employer is disabled-friendly | +| `offresMRS` | `boolean\|null` | None | Allows you to search for jobs that offer the simulation recruitment method | +| `grandDomaine` | `Literal['A','B','C','C15','D','E','F','G','H','I','J','K','L','L14','M','M13','M14','M15','M16','M17','M18','N']\|null` | None | Code of the major area of the offer | +| `experienceExige` | `Literal['D','E','S']\|null` | None | Filter offers by experience level. | +| `publieeDepuis` | `Literal['1','3','7','14','31']\|null` | None | Maximum number of days since the publication of the offer +Possible values: 1, 3, 7, 14, 31 | +| `minCreationDate` | `string\|null` | None | Minimum offer creation date. +If this data is filled in, the maximum offer creation date is mandatory. +ISO-8601 standard (YYYY-MM-DDTHH:MM:SSZ) | +| `maxCreationDate` | `string\|null` | None | Maximum offer creation date. +If this data is filled in, the minimum offer creation date is mandatory. +ISO-8601 standard (YYYY-MM-DDTHH:MM:SSZ) | +| `partenaires` | `string\|null` | None | This filter allows you to enter your partner code in order to include or exclude your offers from the results according to the selectionmade in the PartnerSelection mode filter +It is possible to enter several codes (separator ','). | +| `modeSelectionPartenaires` | `Literal['EXCLU','INCLUS']\|null` | None | Selection mode of the partner offers. + +This filter works with the partner criterion and is dependent on the originOffer +criterion. Possible values with the results obtained according to the two other filters: + +- INCLUS(INCLUDED) +originOffer empty : Returns the PE offers and the Partners listed in the Partners +criterion +originOffer at 2 : Only the offers of the Partners listed in the Partners +criterion +- EXCLU(EXCLUDED) +originOffer empty : Return the offers of PE and Partners not listed in the Partners +criterion +originOffer at 2 : Only the offers of the Partners not listed in the Partners +criterion +Note: In all cases, if originOffer = 1, then only the France Travail (ex: Pole Emploi) +offers will be returned | +| `dureeHebdo` | `Literal['0','1','2']\|null` | None | Filtre les offres selon la durée hebdomadaire. +Valeurs possibles : +0 -> Non précisé +1 -> Temps plein +2 -> Temps partiel | +| `dureeHebdoMin` | `integer\|null` | None | Minimum weekly duration of the offer +The value must be in HHMM format, for example : 8h => 800 ; 24h30 => 2430 | +| `dureeHebdoMax` | `integer\|null` | None | Maximum weekly duration of the offer +The value must be in HHMM format, for example: 8h => 800; 24h30 => 2430 | +| `dureeContratMin` | `number\|null` | None | Minimum duration of the sought contract. +The search is done in months (ex: 0.5 for 15 days, 1.0 for 1 month,2.0 for 2 months). +Positive decimal (Decimal separator: '.') | +| `dureeContratMax` | `number\|null` | None | Maximum duration of the sought contract. +The search is made in months (ex: 0.5 for 15 days, 1.0 for 1 month,2.0 for 2 months). +Positive decimal (Decimal separator: '.') | +| `offresManqueCandidats` | `boolean\|null` | None | Filters offers older than 15 days, with less than 4 applications (of which Pôle emploi is informed) +false -> Offers not concerned +true -> Offers with few candidates | +| `entreprisesAdaptees` | `boolean\|null` | None | Filter the offers where the adapted company allows a disabled worker to exercise a professional activity in conditions adapted to his capacities +false -> Offers not concerned +true -> Offers from adapted companies | + +## Push Parameters (HrFlow) + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `board_key` :red_circle: | `string` | None | HrFlow.ai board key | + +## Other Parameters + +| Field | Type | Default | Description | +| ----- | ---- | ------- | ----------- | +| `workflow_id` :red_circle: | `string` | None | A stable identifier used for persisting in incremental mode | +| `logics` :red_circle: | `array\|null` | None | A list of functions called in sequence with each item pulled from the origin. Each function might either return it's argument or None to discard the item. Any item discarded is eventually not pushed to the target | +| `format` | `Callable\|null` | None | A formatting function to apply on items pulled before the push | +| `callback` | `Callable\|null` | None | Registers a callback function to be called at the of a successful execution | +| `persist` | `boolean` | True | When False has the effect of running in dry mode. Items are pulled but not pushed to the target | +| `incremental` | `boolean` | False | Controls the incremental reading execution mode | + +:red_circle: : *required* + +## Example + +```python +import logging +from hrflow_connectors.v2 import FranceTravail + + +logging.basicConfig(level=logging.INFO) + + +FranceTravail.update_jobs_in_hrflow( + workflow_id=..., + logics=..., + connector_auth=dict( + client_id=..., + client_secret=..., + ), + hrflow_auth=dict( + api_secret=..., + api_user=..., + ), + pull_parameters=dict( + range=..., + sort=..., + domaine=..., + codeROME=..., + theme=..., + appellation=..., + codeNAF=..., + secteurActivite=..., + experience=..., + experienceExigence=..., + typeContrat=..., + natureContrat=..., + origineOffre=..., + qualification=..., + tempsPlein=..., + commune=..., + distance=..., + departement=..., + inclureLimitrophes=..., + region=..., + paysContinent=..., + niveauFormation=..., + permis=..., + motsCles=..., + salaireMin=..., + periodeSalaire=..., + accesTravailleurHandicape=..., + offresMRS=..., + grandDomaine=..., + experienceExige=..., + publieeDepuis=..., + minCreationDate=..., + maxCreationDate=..., + partenaires=..., + modeSelectionPartenaires=..., + dureeHebdo=..., + dureeHebdoMin=..., + dureeHebdoMax=..., + dureeContratMin=..., + dureeContratMax=..., + offresManqueCandidats=..., + entreprisesAdaptees=..., + ), + push_parameters=dict( + board_key=..., + ), + format=..., + callback=..., + persist=..., + incremental=... +) +``` \ No newline at end of file diff --git a/src/hrflow_connectors/v2/connectors/francetravail/logo.png b/src/hrflow_connectors/v2/connectors/francetravail/logo.png new file mode 100644 index 000000000..4f1b1c917 Binary files /dev/null and b/src/hrflow_connectors/v2/connectors/francetravail/logo.png differ diff --git a/src/hrflow_connectors/v2/connectors/francetravail/mappings/format/archive_jobs_in_hrflow.json b/src/hrflow_connectors/v2/connectors/francetravail/mappings/format/archive_jobs_in_hrflow.json new file mode 100644 index 000000000..018c86b68 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/francetravail/mappings/format/archive_jobs_in_hrflow.json @@ -0,0 +1,3 @@ +{ + "reference": "?._id" +} diff --git a/src/hrflow_connectors/v2/connectors/francetravail/mappings/format/create_jobs_in_hrflow.json b/src/hrflow_connectors/v2/connectors/francetravail/mappings/format/create_jobs_in_hrflow.json new file mode 100644 index 000000000..9448d961e --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/francetravail/mappings/format/create_jobs_in_hrflow.json @@ -0,0 +1,102 @@ +{ + "name": "?.intitule", + "reference": "?.id", + "created_at": "?.dateCreation", + "updated_at": "?.dateActualisation", + "location": "?.lieuTravail ?? {lat: .lieuTravail?.latitude, lng: .lieuTravail?.longitude, text: $concat(.lieuTravail?.libelle >> '', ' ', .lieuTravail?.codePostal >> '') | $strip}: {lat: null, lng: null, text: ''}", + "url": "?.origineOffre?.urlOrigine", + "summary": "?.description", + "requirements": "?.formations ?? $map($concat(.niveauLibelle || '', ' en ', .domaineLibelle || '')) | $join('\n')", + "skills": "?.competences ?? $map({name: .libelle, value: null, type: hard}) : []", + "languages": "?.langues ?? $map({name: .libelle, value: null}) : []", + "sections": [ + { + "name": "company_description", + "title": "'Company Description'", + "description": "?.entreprise?.description" + } + ], + "tags": [ + { + "name": "rome_code", + "value": "?.romeCode" + }, + { + "name": "rome_label", + "value": "?.romeLibelle" + }, + { + "name": "contract_nature", + "value": "?.natureContrat" + }, + { + "name": "contract_type", + "value": "?.typeContratLibelle" + }, + { + "name": "accessible_to_disabled", + "value": "?.accessibleTH" + }, + { + "name": "is_apprenticeship", + "value": "?.alternance" + }, + { + "name": "experience_required", + "value": "?.experienceExige == 'E' ?? true : false" + }, + { + "name": "experience_description", + "value": "?.experienceLibelle" + }, + { + "name": "salary_description", + "value": "?.salaire?.libelle" + }, + { + "name": "working_hours_description", + "value": "?.dureeTravailLibelle" + }, + { "name": "working_hours_type", "value": "?.dureeTravailLibelleConverti" }, + { + "name": "qualification_label", + "value": "?.qualificationLibelle" + }, + { + "name": "sector_of_activity", + "value": "?.secteurActiviteLibelle" + }, + { + "name": "company_name", + "value": "?.entreprise?.nom" + }, + { + "name": "company_description", + "value": "?.entreprise?.description" + }, + { + "name": "company_website", + "value": "?.entreprise?.url" + }, + { + "name": "recruiter_name", + "value": "?.contact?.nom" + }, + { + "name": "recruiter_email", + "value": "?.contact?.courriel" + }, + { + "name": "recruiter_phone", + "value": "?.contact?.telephone" + }, + { + "name": "recruiter_website", + "value": "?.contact?.urlRecruteur" + }, + { + "name": "application_url", + "value": "?.contact?.urlPostulation" + } + ] +} diff --git a/src/hrflow_connectors/v2/connectors/francetravail/mappings/format/update_jobs_in_hrflow.json b/src/hrflow_connectors/v2/connectors/francetravail/mappings/format/update_jobs_in_hrflow.json new file mode 100644 index 000000000..9448d961e --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/francetravail/mappings/format/update_jobs_in_hrflow.json @@ -0,0 +1,102 @@ +{ + "name": "?.intitule", + "reference": "?.id", + "created_at": "?.dateCreation", + "updated_at": "?.dateActualisation", + "location": "?.lieuTravail ?? {lat: .lieuTravail?.latitude, lng: .lieuTravail?.longitude, text: $concat(.lieuTravail?.libelle >> '', ' ', .lieuTravail?.codePostal >> '') | $strip}: {lat: null, lng: null, text: ''}", + "url": "?.origineOffre?.urlOrigine", + "summary": "?.description", + "requirements": "?.formations ?? $map($concat(.niveauLibelle || '', ' en ', .domaineLibelle || '')) | $join('\n')", + "skills": "?.competences ?? $map({name: .libelle, value: null, type: hard}) : []", + "languages": "?.langues ?? $map({name: .libelle, value: null}) : []", + "sections": [ + { + "name": "company_description", + "title": "'Company Description'", + "description": "?.entreprise?.description" + } + ], + "tags": [ + { + "name": "rome_code", + "value": "?.romeCode" + }, + { + "name": "rome_label", + "value": "?.romeLibelle" + }, + { + "name": "contract_nature", + "value": "?.natureContrat" + }, + { + "name": "contract_type", + "value": "?.typeContratLibelle" + }, + { + "name": "accessible_to_disabled", + "value": "?.accessibleTH" + }, + { + "name": "is_apprenticeship", + "value": "?.alternance" + }, + { + "name": "experience_required", + "value": "?.experienceExige == 'E' ?? true : false" + }, + { + "name": "experience_description", + "value": "?.experienceLibelle" + }, + { + "name": "salary_description", + "value": "?.salaire?.libelle" + }, + { + "name": "working_hours_description", + "value": "?.dureeTravailLibelle" + }, + { "name": "working_hours_type", "value": "?.dureeTravailLibelleConverti" }, + { + "name": "qualification_label", + "value": "?.qualificationLibelle" + }, + { + "name": "sector_of_activity", + "value": "?.secteurActiviteLibelle" + }, + { + "name": "company_name", + "value": "?.entreprise?.nom" + }, + { + "name": "company_description", + "value": "?.entreprise?.description" + }, + { + "name": "company_website", + "value": "?.entreprise?.url" + }, + { + "name": "recruiter_name", + "value": "?.contact?.nom" + }, + { + "name": "recruiter_email", + "value": "?.contact?.courriel" + }, + { + "name": "recruiter_phone", + "value": "?.contact?.telephone" + }, + { + "name": "recruiter_website", + "value": "?.contact?.urlRecruteur" + }, + { + "name": "application_url", + "value": "?.contact?.urlPostulation" + } + ] +} diff --git a/src/hrflow_connectors/v2/connectors/francetravail/notebooks/.gitkeep b/src/hrflow_connectors/v2/connectors/francetravail/notebooks/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/src/hrflow_connectors/v2/connectors/francetravail/schemas.py b/src/hrflow_connectors/v2/connectors/francetravail/schemas.py new file mode 100644 index 000000000..a69a1fbbf --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/francetravail/schemas.py @@ -0,0 +1,311 @@ +import datetime +import typing as t +from enum import Enum, IntEnum + +from msgspec import Meta, Struct +from typing_extensions import Annotated + +POLE_EMPLOI_REFERENCES_ENDPOINT = ( + "https://api.emploi-store.fr/partenaire/offresdemploi/v2/referentiel/" +) + + +def validate_date(value: t.Optional[str], field_name: str) -> None: + if value is not None: + try: + datetime.date.fromisoformat(value) + except ValueError: + raise ValueError( + f"Invalid date format for '{field_name}': {value}. Expected ISO 8601" + " format (YYYY-MM-DD)." + ) + + +class JobLocation(Struct): + libelle: str + latitude: float + longitude: float + codepostal: str + commune: Annotated[ + str, + Meta( + description=( + "INSEE code of the commune" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + "to this endpoint :" + f" {POLE_EMPLOI_REFERENCES_ENDPOINT}communes" + ), + ), + ] + + +class Entreprise(Struct): + nom: t.Optional[str] + description: t.Optional[str] + logo: t.Optional[str] + url: t.Optional[str] + entrepriseAdaptee: bool + + +class Partner(Struct): + nom: str + url: str + logo: str + + +class OfferOriginTag(IntEnum): + POLE_EMPLOI = 1 + PARTNER = 2 + + +class OfferOrigin(Struct): + origine: OfferOriginTag + urlOrigine: t.Optional[str] + partenaires: t.List[Partner] + + +class ExperienceRequirement(str, Enum): + BEGINNER_ACCEPTED = "D" + EXPERIENCE_DESIRED = "S" + EXPERIENCE_REQUIRED = "E" + + +class Exigence(Enum): + REQUIRED = "E" + DESIRED = "S" + + +class Formation(Struct): + domaineLibelle: str + niveauLibelle: Annotated[ + str, + Meta( + description=( + "Label of the level of the education required" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + "to this endpoint :" + f" {POLE_EMPLOI_REFERENCES_ENDPOINT}referentiel/niveauxFormations" + ), + ), + ] + commentaire: str + exigence: Exigence + + +class Langue(Struct): + libelle: Annotated[ + str, + Meta( + description=( + "Language label" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + "to this endpoint :" + f" {POLE_EMPLOI_REFERENCES_ENDPOINT}referentiel/langues" + ), + ), + ] + exigence: t.Optional[Exigence] + + +class Permis(Struct): + libelle: Annotated[ + str, + Meta( + description=( + "requested license" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + "to this endpoint :" + f" {POLE_EMPLOI_REFERENCES_ENDPOINT}referentiel/permis" + ), + ), + ] + exigence: t.Optional[Exigence] + + +class Competence(Struct): + code: str + libelle: str + exigence: t.Optional[Exigence] + + +class Salaire(Struct): + libelle: t.Optional[str] + commentaire: t.Optional[str] + complement1: t.Optional[str] + complement2: t.Optional[str] + + +class Contact(Struct): + nom: t.Optional[str] + coordonnees1: t.Optional[str] + coordonnees2: t.Optional[str] + coordonnees3: t.Optional[str] + telephone: t.Optional[str] + courriel: t.Optional[str] + commentaire: t.Optional[str] + urlRecruteur: t.Optional[str] + urlPostulation: t.Optional[str] + + +class Agence(Struct): + telephone: t.Optional[str] + courriel: t.Optional[str] + + +class QualificationCode(str, Enum): + MANOEUVRE = "1" + SPECIALIZED_WORKER = "2" + QUALIFIED_WORKER_P1_P2 = "3" + QUALIFIED_WORKER_P3_P4_OHQ = "4" + UNQUALIFIED_EMPLOYEE = "5" + QUALIFIED_EMPLOYEE = "6" + TECHNICIAN = "7" + SUPERVISORY_AGENT = "8" + EXECUTIVE = "9" + + +class QualificationLibelle(str, Enum): + MANOEUVRE = "Manœuvre" + SPECIALIZED_WORKER = "Ouvrier spécialisé" + QUALIFIED_WORKER_P1_P2 = "Ouvrier qualifié (P1, P2)" + QUALIFIED_WORKER_P3_P4_OHQ = "Ouvrier qualifié (P3, P4, OHQ)" + UNQUALIFIED_EMPLOYEE = "Employé non qualifié" + QUALIFIED_EMPLOYEE = "Employé qualifié" + TECHNICIAN = "Technicien" + SUPERVISORY_AGENT = "Agent de maîtrise" + EXECUTIVE = "Cadre" + + +class QualitePro(Struct): + libelle: t.Optional[str] + description: t.Optional[str] + + +class FranceTravailJobOffer(Struct): + id: int + intitule: str + description: str + dateCreation: t.Optional[str] = None + dateActualisation: t.Optional[str] = None + lieuTravail: t.Optional[JobLocation] = None + romeCode: Annotated[ + t.Optional[str], + Meta( + description=( + "ROME code of the profession" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + "to this endpoint :" + f" {POLE_EMPLOI_REFERENCES_ENDPOINT}metiers" + ), + ), + ] = None + romeLibelle: t.Optional[str] = None + appellationLibelle: Annotated[ + t.Optional[str], + Meta( + description=( + "Code of the appellation" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + "to this endpoint :" + f" {POLE_EMPLOI_REFERENCES_ENDPOINT}appellations" + ), + ), + ] = None + entreprise: t.Optional[Entreprise] = None + typeContrat: Annotated[ + t.Optional[str], + Meta( + description=( + "Contract type code" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + "to this endpoint :" + f" {POLE_EMPLOI_REFERENCES_ENDPOINT}typesContrats" + ), + ), + ] = None + typeContratLibelle: Annotated[ + t.Optional[str], + Meta( + description=( + "Contract type label" + "Example : CDI,CDD" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + "to this endpoint :" + f" {POLE_EMPLOI_REFERENCES_ENDPOINT}typesContrats" + ), + ), + ] = None + natureContrat: Annotated[ + t.Optional[str], + Meta( + description=( + "Code of the nature of contract" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + "to this endpoint :" + f" {POLE_EMPLOI_REFERENCES_ENDPOINT}naturesContrats" + ), + ), + ] = None + origineOffre: t.Optional[OfferOrigin] = None + offresManqueCandidats: t.Optional[bool] = None + experienceExige: t.Optional[ExperienceRequirement] = None + experienceLibelle: t.Optional[str] = None + experienceCommentaire: t.Optional[str] = None + formations: t.Optional[t.List[Formation]] = None + langues: t.Optional[t.List[Langue]] = None + permis: t.Optional[t.List[Permis]] = None + outilsBureautiques: t.Optional[str] = None + competences: t.Optional[t.List[Competence]] = None + salaire: t.Optional[Salaire] = None + dureeTravailLibelle: t.Optional[str] = None + dureeTravailLibelleConverti: t.Optional[str] = None + complementExercice: t.Optional[str] = None + conditionExercice: t.Optional[str] = None + alternance: t.Optional[bool] = None + contact: t.Optional[Contact] = None + agence: t.Optional[Agence] = None + nombrePostes: t.Optional[int] = None + accessibleTH: t.Optional[bool] = None + deplacementCode: t.Optional[str] = None + deplacementLibelle: t.Optional[str] = None + qualificationCode: t.Optional[QualificationCode] = None + qualificationLibelle: t.Optional[QualificationLibelle] = None + secteurActivite: Annotated[ + t.Optional[str], + Meta( + description=( + "NAF codes for sectors of activity. It is possible to specify two NAF" + " codes by separating them with a comma in the character" + " string.Example : 01,02A GET request for the list of accepted choices" + " from the Offres d'emploi APIto this endpoint :" + f" {POLE_EMPLOI_REFERENCES_ENDPOINT}secteursActivites" + ), + ), + ] = None + secteurActiviteLibelle: Annotated[ + t.Optional[str], + Meta( + description=( + "Sector of activitylabel" + "A GET request for the list of accepted choices from the Offres" + " d'emploi API" + "to this endpoint :" + f" {POLE_EMPLOI_REFERENCES_ENDPOINT}secteursActivites" + ), + ), + ] = None + qualitesProfessionnelles: t.Optional[t.List[QualitePro]] = None + + def __post_init__(self): + # Validate date fields + validate_date(self.dateCreation, "dateCreation") + validate_date(self.dateActualisation, "dateActualisation") diff --git a/src/hrflow_connectors/v2/connectors/francetravail/test-config.yaml b/src/hrflow_connectors/v2/connectors/francetravail/test-config.yaml new file mode 100644 index 000000000..702ddf331 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/francetravail/test-config.yaml @@ -0,0 +1,67 @@ +actions: + create_jobs_in_hrflow: + - id: valid_parameters + connector_auth: + client_id: $__CLIENT_ID + client_secret: $__CLIENT_SECRET + hrflow_auth: + api_secret: $__API_SECRET + api_user: $__API_USER + pull_parameters: + secteurActivite: "72" + typeContrat: "CDI" + natureContrat: "E1" + range: "0-1" + push_parameters: + board_key: $__BOARD_KEY + status: success + - id: no_client_credentials + connector_auth: {} + hrflow_auth: + api_secret: $__API_SECRET + api_user: $__API_USER + pull_parameters: + motsCles: INFORMATIQUE + push_parameters: + board_key: $__BOARD_KEY + status: fatal + reason: bad_origin_parameters + - id: no_hrflow_board_key + connector_auth: + client_id: $__CLIENT_ID + client_secret: $__CLIENT_SECRET + hrflow_auth: + api_secret: $__API_SECRET + api_user: $__API_USER + pull_parameters: + motsCles: Software + push_parameters: {} + status: fatal + reason: bad_target_parameters + - id: invalid_client_credentials + connector_auth: + client_id: bad_client_id + client_secret: bad_client_secret + hrflow_auth: + api_secret: $__API_SECRET + api_user: $__API_USER + pull_parameters: + motsCles: Software + push_parameters: + board_key: $__BOARD_KEY + status: fatal + reason: read_failure + - id: invalid_hrflow_api_secret + connector_auth: + client_id: $__CLIENT_ID + client_secret: $__CLIENT_SECRET + hrflow_auth: + api_secret: bad_api_secret + api_user: $__API_USER + pull_parameters: + motsCles: Software + range: "0-1" + push_parameters: + board_key: $__BOARD_KEY + status: fatal + reason: write_failure diff --git a/src/hrflow_connectors/v2/connectors/francetravail/warehouse.py b/src/hrflow_connectors/v2/connectors/francetravail/warehouse.py new file mode 100644 index 000000000..cb08def34 --- /dev/null +++ b/src/hrflow_connectors/v2/connectors/francetravail/warehouse.py @@ -0,0 +1,7 @@ +from hrflow_connectors.v2.connectors.francetravail.aisles import ( + AuthParameters, + JobsAisle, +) +from hrflow_connectors.v2.core.warehouse import Warehouse + +FranceTravailWarehouse = Warehouse(auth=AuthParameters, aisles=(JobsAisle,)) diff --git a/src/hrflow_connectors/v2/connectors/hubspot/README.md b/src/hrflow_connectors/v2/connectors/hubspot/README.md index cd5e23b79..8ce4e6652 100644 --- a/src/hrflow_connectors/v2/connectors/hubspot/README.md +++ b/src/hrflow_connectors/v2/connectors/hubspot/README.md @@ -1,31 +1,42 @@ # 📖 Summary -- [📖 Summary](#-summary) -- [📝 About Hubspot](#-about-hubspot) -- [📊 Data Flow](#-data-flow) -- [🔌 Connector Actions](#-connector-actions) -- [🐍 Quick Start Example](#-quick-start-example) -- [🔗 Useful Links](#-useful-links) -- [👏 Special Thanks](#-special-thanks) +- [📖 Summary](#📖-summary) +- [💼 About Hubspot](#💼-about-hubspot) + - [😍 Why is it a big deal for Hubspot customers & partners?](#😍-why-is-it-a-big-deal-for-hubspot-customers--partners) +- [🔧 How does it work?](#🔧-how-does-it-work) + - [📊 Data integration capabilities:](#📊-data-integration-capabilities) + - [🧠 Artificial Intelligence capabilities:](#🧠-artificial-intelligence-capabilities) +- [🔌 Connector Actions](#🔌-connector-actions) +- [💍 Quick Start Examples](#💍-quick-start-examples) +- [🔗 Useful Links](#🔗-useful-links) +- [👏 Special Thanks](#👏-special-thanks) -# 📝 About Hubspot +# 💼 About Hubspot -HubSpot is a CRM platform with all the software, integrations, and resources you need to connect marketing, sales, content management, and customer service. +> HubSpot is a CRM platform with all the software, integrations, and resources you need to connect marketing, sales, content management, and customer service. -

- -

+## 😍 Why is it a big deal for Hubspot customers & partners? +This new connector will enable: +- ⚡ A Fastlane Talent & Workforce data integration for Hubspot customers & partners +- 🤖 Cutting-edge AI-powered Talent Experiences & Recruiter Experiences for Hubspot customers -# 📊 Data Flow -In this section, we outline the data flow between different components of the connector. The following schema provides a graphical representation of the data exchange process +# 🔧 How does it work? +## 📊 Data integration capabilities: +- ⬅️ Send Profiles data from Hubspot to a Destination of your choice. +- ➡️ Send Profiles data from a Source of your choice to Hubspot. +- ⬅️ Send Jobs data from Hubspot to a Destination of your choice. +- ➡️ Send Jobs data from a Source of your choice to Hubspot.

+## 🧠 Artificial Intelligence capabilities: +- Extract, Structure, and Categorize Talent & Workforce data +- Search, Score, and Match Profiles & Jobs with our APIs and AI Widgets (**Matching Custom Tab in Hubspot**) # 🔌 Connector Actions @@ -46,8 +57,9 @@ In this section, we outline the data flow between different components of the co # 💍 Quick Start Examples - To make sure you can successfully run the latest versions of the example scripts, you have to **install the package from PyPi**. + + To browse the examples of actions corresponding to released versions of 🤗 this connector, you just need to import the module like this : @@ -57,14 +69,14 @@ To browse the examples of actions corresponding to released versions of 🤗 thi Once the connector module is imported, you can leverage all the different actions that it offers. -For more code details checkout connector code +For more code details checkout connector code. # 🔗 Useful Links - 📄Visit [Hubspot](https://www.hubspot.com) to learn more. - ⚙️ API documentation : (https://developers.hubspot.com/docs/api/overview) -- 💻 [Connector code](https://github.com/Riminder/hrflow-connectors/tree/master/src/hrflow_connectors/connectors/hubspot) on our Github. +- 💻 [Connector code](https://github.com/Riminder/hrflow-connectors/tree/master/src/hrflow_connectors/v2/connectors/hubspot) on our Github. # 👏 Special Thanks diff --git a/src/hrflow_connectors/v2/connectors/hubspot/connector.py b/src/hrflow_connectors/v2/connectors/hubspot/connector.py index 89a4edced..ae300991c 100644 --- a/src/hrflow_connectors/v2/connectors/hubspot/connector.py +++ b/src/hrflow_connectors/v2/connectors/hubspot/connector.py @@ -74,7 +74,11 @@ def format_hubspot_contact_for_archive(hubspot_contact: t.Dict) -> t.Dict: name="Hubspot", type=ConnectorType.CRM, subtype="hubspot", - description="", + description=( + "HubSpot is a CRM platform with all the software, integrations, and resources" + " you need to connect marketing, sales, content management, and customer" + " service." + ), url="https://www.hubspot.com/", warehouse=HubspotWarehouse, flows=( diff --git a/src/hrflow_connectors/v2/connectors/recruitee/README.md b/src/hrflow_connectors/v2/connectors/recruitee/README.md index 4da48b078..a691bcbda 100644 --- a/src/hrflow_connectors/v2/connectors/recruitee/README.md +++ b/src/hrflow_connectors/v2/connectors/recruitee/README.md @@ -29,6 +29,9 @@ This new connector will enable: - ⬅️ Send Jobs data from Recruitee to a Destination of your choice. - ➡️ Send Jobs data from a Source of your choice to Recruitee. +

+ +

## 🧠 Artificial Intelligence capabilities: - Extract, Structure, and Categorize Talent & Workforce data @@ -53,13 +56,12 @@ This new connector will enable:

-

- -

# 💍 Quick Start Examples To make sure you can successfully run the latest versions of the example scripts, you have to **install the package from PyPi**. + + To browse the examples of actions corresponding to released versions of 🤗 this connector, you just need to import the module like this : @@ -71,11 +73,13 @@ Once the connector module is imported, you can leverage all the different action For more code details checkout connector code. + # 🔗 Useful Links -- 📄Visit [Recruitee](https://recruitee.com/) to learn more. +- 📄 Visit [Recruitee](https://recruitee.com/) to learn more. - ⚙️ API documentation : [Recruitee API](https://api.recruitee.com/docs/index.html) -- 💻 [Connector code](https://github.com/Riminder/hrflow-connectors/tree/master/src/hrflow_connectors/connectors/recruitee) on our Github. +- 💻 [Connector code](https://github.com/Riminder/hrflow-connectors/tree/master/src/hrflow_connectors/v2/connectors/recruitee) on our Github. + # 👏 Special Thanks diff --git a/src/hrflow_connectors/v2/connectors/smartrecruiters/README.md b/src/hrflow_connectors/v2/connectors/smartrecruiters/README.md index e9d02e6bf..113bb39e9 100644 --- a/src/hrflow_connectors/v2/connectors/smartrecruiters/README.md +++ b/src/hrflow_connectors/v2/connectors/smartrecruiters/README.md @@ -15,13 +15,6 @@ > Move beyond applicant tracking systems (ATS) with an enterprise-grade recruiting platform designed for the modern workforce. SmartRecruiters' Talent Acquisition Suite provides everything needed to attract, select, and hire great talent. -

- -

- -

- -

## 😍 Why is it a big deal for Smartrecruiters customers & partners? @@ -36,6 +29,9 @@ This new connector will enable: - ⬅️ Send Jobs data from Smartrecruiters to a Destination of your choice. - ➡️ Send Jobs data from a Source of your choice to Smartrecruiters. +

+ +

## 🧠 Artificial Intelligence capabilities: - Extract, Structure, and Categorize Talent & Workforce data @@ -60,10 +56,6 @@ This new connector will enable:

-

- -

- # 💍 Quick Start Examples @@ -79,14 +71,15 @@ To browse the examples of actions corresponding to released versions of 🤗 thi Once the connector module is imported, you can leverage all the different actions that it offers. + For more code details checkout connector code. # 🔗 Useful Links -- 📄Visit [SmartRecruiters](https://www.smartrecruiters.com/) to learn more. +- 📄 Visit [Smartrecruiters](https://www.smartrecruiters.com/) to learn more. - ⚙️ API documentation : (https://developers.smartrecruiters.com/doc) -- 💻 [Connector code](https://github.com/Riminder/hrflow-connectors/tree/master/src/hrflow_connectors/connectors/smartrecruiters) on our Github. +- 💻 [Connector code](https://github.com/Riminder/hrflow-connectors/tree/master/src/hrflow_connectors/v2/connectors/smartrecruiters) on our Github. # 👏 Special Thanks diff --git a/src/hrflow_connectors/v2/connectors/zohorecruit/README.md b/src/hrflow_connectors/v2/connectors/zohorecruit/README.md index 6b13759f1..1e7b51fcf 100644 --- a/src/hrflow_connectors/v2/connectors/zohorecruit/README.md +++ b/src/hrflow_connectors/v2/connectors/zohorecruit/README.md @@ -1,7 +1,7 @@ # 📖 Summary - [📖 Summary](#📖-summary) -- [💼 About Zohorecruit](#💼-about-zohorecruit) - - [😍 Why is it a big deal for Zohorecruit customers & partners?](#😍-why-is-it-a-big-deal-for-zohorecruit-customers--partners) +- [💼 About Zoho recruit](#💼-about-zoho-recruit) + - [😍 Why is it a big deal for Zoho recruit customers & partners?](#😍-why-is-it-a-big-deal-for-zoho-recruit-customers--partners) - [🔧 How does it work?](#🔧-how-does-it-work) - [📊 Data integration capabilities:](#📊-data-integration-capabilities) - [🧠 Artificial Intelligence capabilities:](#🧠-artificial-intelligence-capabilities) @@ -11,28 +11,28 @@ - [👏 Special Thanks](#👏-special-thanks) -# 💼 About Zohorecruit +# 💼 About Zoho recruit > Zoho Recruit offers a powerful ATS and CRM in a single recruitment platform. With scalability, customization, and remote hiring tools, Recruit has everything your staffing agency or internal HR team needs to match the right candidate to the right role. -## 😍 Why is it a big deal for Zohorecruit customers & partners? +## 😍 Why is it a big deal for Zoho recruit customers & partners? This new connector will enable: -- ⚡ A Fastlane Talent & Workforce data integration for Zohorecruit customers & partners -- 🤖 Cutting-edge AI-powered Talent Experiences & Recruiter Experiences for Zohorecruit customers +- ⚡ A Fastlane Talent & Workforce data integration for Zoho recruit customers & partners +- 🤖 Cutting-edge AI-powered Talent Experiences & Recruiter Experiences for Zoho recruit customers # 🔧 How does it work? ## 📊 Data integration capabilities: -- ⬅️ Send Profiles data from Zohorecruit to a Destination of your choice. -- ➡️ Send Profiles data from a Source of your choice to Zohorecruit. -- ⬅️ Send Jobs data from Zohorecruit to a Destination of your choice. -- ➡️ Send Jobs data from a Source of your choice to Zohorecruit. +- ⬅️ Send Profiles data from Zoho recruit to a Destination of your choice. +- ➡️ Send Profiles data from a Source of your choice to Zoho recruit. +- ⬅️ Send Jobs data from Zoho recruit to a Destination of your choice. +- ➡️ Send Jobs data from a Source of your choice to Zoho recruit. ## 🧠 Artificial Intelligence capabilities: - Extract, Structure, and Categorize Talent & Workforce data -- Search, Score, and Match Profiles & Jobs with our APIs and AI Widgets (**Matching Custom Tab in Zohorecruit**) +- Search, Score, and Match Profiles & Jobs with our APIs and AI Widgets (**Matching Custom Tab in Zoho recruit**) # 🔌 Connector Actions @@ -53,11 +53,6 @@ This new connector will enable:

-

- -

- # 💍 Quick Start Examples @@ -66,10 +61,6 @@ To make sure you can successfully run the latest versions of the example scripts To browse the examples of actions corresponding to released versions of 🤗 this connector, you just need to import the module like this : -

- -

Once the connector module is imported, you can leverage all the different actions that it offers. @@ -78,9 +69,9 @@ For more code details checkout connector code. # 🔗 Useful Links -- 📄Visit [Zohorecruit](https://zoho.com/recruit/) to learn more. +- 📄 Visit [Zoho recruit](https://zoho.com/recruit/) to learn more. - ⚙️ API documentation : (https://www.zoho.com/recruit/developer-guide/apiv2/) -- 💻 [Connector code](https://github.com/Riminder/hrflow-connectors/tree/master/src/hrflow_connectors/connectors/zohorecruit) on our Github. +- 💻 [Connector code](https://github.com/Riminder/hrflow-connectors/tree/master/src/hrflow_connectors/v2/connectors/zohorecruit) on our Github. # 👏 Special Thanks