From af42ff66ec38d53643d676f2c9d885f00325e170 Mon Sep 17 00:00:00 2001 From: Nedhir Ebnou Date: Wed, 4 Dec 2024 16:21:32 +0100 Subject: [PATCH 1/4] fix: unify connector documentations --- README.md | 2 +- src/hrflow_connectors/v2/__init__.py | 11 ++++- .../v2/connectors/admen/README.md | 38 +++++++-------- .../v2/connectors/hubspot/README.md | 46 ++++++++++++------- .../v2/connectors/hubspot/connector.py | 6 ++- .../v2/connectors/recruitee/README.md | 14 ++++-- .../v2/connectors/smartrecruiters/README.md | 19 +++----- .../v2/connectors/zohorecruit/README.md | 35 ++++++-------- 8 files changed, 92 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index 8012558f..da568489 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ 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* | | [**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* | diff --git a/src/hrflow_connectors/v2/__init__.py b/src/hrflow_connectors/v2/__init__.py index 6e3ebf6c..76b15555 100644 --- a/src/hrflow_connectors/v2/__init__.py +++ b/src/hrflow_connectors/v2/__init__.py @@ -1,4 +1,5 @@ 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.hubspot import Hubspot from hrflow_connectors.v2.connectors.recruitee import Recruitee @@ -11,4 +12,12 @@ hrflow_connectors_docs as hrflow_connectors_docs, ) -__CONNECTORS__ = [Bullhorn, ZohoRecruit, Admen, SmartRecruiters, Hubspot, Recruitee] +__CONNECTORS__ = [ + Bullhorn, + ZohoRecruit, + Admen, + SmartRecruiters, + Hubspot, + Recruitee, + Adzuna, +] diff --git a/src/hrflow_connectors/v2/connectors/admen/README.md b/src/hrflow_connectors/v2/connectors/admen/README.md index 549bf572..097b934a 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/hubspot/README.md b/src/hrflow_connectors/v2/connectors/hubspot/README.md index cd5e23b7..8ce4e665 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 89a4edce..ae300991 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 4da48b07..a691bcbd 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 e9d02e6b..113bb39e 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 6b13759f..1e7b51fc 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 From d4852a8b8fc694c5f10114b878db6030539c60be Mon Sep 17 00:00:00 2001 From: Nedhir Ebnou Date: Wed, 4 Dec 2024 16:26:17 +0100 Subject: [PATCH 2/4] feature: Add Adzuna Connector in CRUD v2 --- manifest.json | 3603 +++++++++++++++++ .../v2/connectors/adzuna/README.md | 87 + .../v2/connectors/adzuna/__init__.py | 1 + .../v2/connectors/adzuna/aisles.py | 323 ++ .../v2/connectors/adzuna/connector.py | 76 + .../v2/connectors/adzuna/connector.pyi | 9 + .../adzuna/docs/archive_jobs_in_hrflow.md | 143 + .../adzuna/docs/create_jobs_in_hrflow.md | 145 + .../adzuna/docs/update_jobs_in_hrflow.md | 143 + .../v2/connectors/adzuna/logo.png | Bin 0 -> 6520 bytes .../format/archive_jobs_in_hrflow.json | 3 + .../format/create_jobs_in_hrflow.json | 43 + .../format/update_jobs_in_hrflow.json | 43 + .../v2/connectors/adzuna/notebooks/.gitkeep | 0 .../v2/connectors/adzuna/schemas.py | 68 + .../v2/connectors/adzuna/test-config.yaml | 79 + .../v2/connectors/adzuna/warehouse.py | 4 + 17 files changed, 4770 insertions(+) create mode 100644 src/hrflow_connectors/v2/connectors/adzuna/README.md create mode 100644 src/hrflow_connectors/v2/connectors/adzuna/__init__.py create mode 100644 src/hrflow_connectors/v2/connectors/adzuna/aisles.py create mode 100644 src/hrflow_connectors/v2/connectors/adzuna/connector.py create mode 100644 src/hrflow_connectors/v2/connectors/adzuna/connector.pyi create mode 100644 src/hrflow_connectors/v2/connectors/adzuna/docs/archive_jobs_in_hrflow.md create mode 100644 src/hrflow_connectors/v2/connectors/adzuna/docs/create_jobs_in_hrflow.md create mode 100644 src/hrflow_connectors/v2/connectors/adzuna/docs/update_jobs_in_hrflow.md create mode 100644 src/hrflow_connectors/v2/connectors/adzuna/logo.png create mode 100644 src/hrflow_connectors/v2/connectors/adzuna/mappings/format/archive_jobs_in_hrflow.json create mode 100644 src/hrflow_connectors/v2/connectors/adzuna/mappings/format/create_jobs_in_hrflow.json create mode 100644 src/hrflow_connectors/v2/connectors/adzuna/mappings/format/update_jobs_in_hrflow.json create mode 100644 src/hrflow_connectors/v2/connectors/adzuna/notebooks/.gitkeep create mode 100644 src/hrflow_connectors/v2/connectors/adzuna/schemas.py create mode 100644 src/hrflow_connectors/v2/connectors/adzuna/test-config.yaml create mode 100644 src/hrflow_connectors/v2/connectors/adzuna/warehouse.py diff --git a/manifest.json b/manifest.json index 827d2c69..46599a5f 100644 --- a/manifest.json +++ b/manifest.json @@ -64402,6 +64402,3609 @@ } } ] + }, + { + "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": { + "title": "Id", + "type": "string" + }, + "created": { + "title": "Created", + "type": "string" + }, + "title": { + "title": "Title", + "type": "string" + }, + "description": { + "title": "Description", + "type": "string" + }, + "full_description": { + "title": "Full Description", + "type": "string" + }, + "redirect_url": { + "title": "Redirect Url", + "type": "string" + }, + "latitude": { + "title": "Latitude", + "type": "number" + }, + "longitude": { + "title": "Longitude", + "type": "number" + }, + "category": { + "$ref": "#/definitions/Category" + }, + "location": { + "$ref": "#/definitions/Location" + }, + "salary_min": { + "title": "Salary Min", + "type": "integer" + }, + "salary_max": { + "title": "Salary Max", + "type": "integer" + }, + "salary_is_predicted": { + "$ref": "#/definitions/Flag" + }, + "company": { + "$ref": "#/definitions/Company" + }, + "contract_type": { + "$ref": "#/definitions/ContractType" + }, + "contract_time": { + "$ref": "#/definitions/ContractTime" + } + }, + "required": [ + "id", + "created", + "title", + "description", + "redirect_url", + "category", + "location", + "salary_min", + "salary_max", + "salary_is_predicted", + "company" + ], + "definitions": { + "Category": { + "title": "Category", + "type": "object", + "properties": { + "tag": { + "title": "Tag", + "type": "string" + }, + "label": { + "title": "Label", + "type": "string" + } + }, + "required": [ + "tag", + "label" + ] + }, + "Location": { + "title": "Location", + "type": "object", + "properties": { + "area": { + "title": "Area", + "type": "array", + "items": { + "type": "string" + } + }, + "display_name": { + "title": "Display Name", + "type": "string" + } + }, + "required": [ + "area", + "display_name" + ] + }, + "Flag": { + "title": "Flag", + "description": "An enumeration.", + "enum": [ + "1", + "0" + ], + "type": "string" + }, + "Company": { + "title": "Company", + "type": "object", + "properties": { + "display_name": { + "title": "Display Name", + "type": "string" + }, + "canonical_name": { + "title": "Canonical Name", + "type": "string" + }, + "count": { + "title": "Count", + "type": "integer" + } + }, + "required": [ + "display_name" + ] + }, + "ContractType": { + "title": "ContractType", + "description": "An enumeration.", + "enum": [ + "permanent", + "contract" + ], + "type": "string" + }, + "ContractTime": { + "title": "ContractTime", + "description": "An enumeration.", + "enum": [ + "full_time", + "part_time" + ], + "type": "string" + } + } + }, + "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": { + "title": "Id", + "type": "string" + }, + "created": { + "title": "Created", + "type": "string" + }, + "title": { + "title": "Title", + "type": "string" + }, + "description": { + "title": "Description", + "type": "string" + }, + "full_description": { + "title": "Full Description", + "type": "string" + }, + "redirect_url": { + "title": "Redirect Url", + "type": "string" + }, + "latitude": { + "title": "Latitude", + "type": "number" + }, + "longitude": { + "title": "Longitude", + "type": "number" + }, + "category": { + "$ref": "#/definitions/Category" + }, + "location": { + "$ref": "#/definitions/Location" + }, + "salary_min": { + "title": "Salary Min", + "type": "integer" + }, + "salary_max": { + "title": "Salary Max", + "type": "integer" + }, + "salary_is_predicted": { + "$ref": "#/definitions/Flag" + }, + "company": { + "$ref": "#/definitions/Company" + }, + "contract_type": { + "$ref": "#/definitions/ContractType" + }, + "contract_time": { + "$ref": "#/definitions/ContractTime" + } + }, + "required": [ + "id", + "created", + "title", + "description", + "redirect_url", + "category", + "location", + "salary_min", + "salary_max", + "salary_is_predicted", + "company" + ], + "definitions": { + "Category": { + "title": "Category", + "type": "object", + "properties": { + "tag": { + "title": "Tag", + "type": "string" + }, + "label": { + "title": "Label", + "type": "string" + } + }, + "required": [ + "tag", + "label" + ] + }, + "Location": { + "title": "Location", + "type": "object", + "properties": { + "area": { + "title": "Area", + "type": "array", + "items": { + "type": "string" + } + }, + "display_name": { + "title": "Display Name", + "type": "string" + } + }, + "required": [ + "area", + "display_name" + ] + }, + "Flag": { + "title": "Flag", + "description": "An enumeration.", + "enum": [ + "1", + "0" + ], + "type": "string" + }, + "Company": { + "title": "Company", + "type": "object", + "properties": { + "display_name": { + "title": "Display Name", + "type": "string" + }, + "canonical_name": { + "title": "Canonical Name", + "type": "string" + }, + "count": { + "title": "Count", + "type": "integer" + } + }, + "required": [ + "display_name" + ] + }, + "ContractType": { + "title": "ContractType", + "description": "An enumeration.", + "enum": [ + "permanent", + "contract" + ], + "type": "string" + }, + "ContractTime": { + "title": "ContractTime", + "description": "An enumeration.", + "enum": [ + "full_time", + "part_time" + ], + "type": "string" + } + } + }, + "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": { + "title": "Id", + "type": "string" + }, + "created": { + "title": "Created", + "type": "string" + }, + "title": { + "title": "Title", + "type": "string" + }, + "description": { + "title": "Description", + "type": "string" + }, + "full_description": { + "title": "Full Description", + "type": "string" + }, + "redirect_url": { + "title": "Redirect Url", + "type": "string" + }, + "latitude": { + "title": "Latitude", + "type": "number" + }, + "longitude": { + "title": "Longitude", + "type": "number" + }, + "category": { + "$ref": "#/definitions/Category" + }, + "location": { + "$ref": "#/definitions/Location" + }, + "salary_min": { + "title": "Salary Min", + "type": "integer" + }, + "salary_max": { + "title": "Salary Max", + "type": "integer" + }, + "salary_is_predicted": { + "$ref": "#/definitions/Flag" + }, + "company": { + "$ref": "#/definitions/Company" + }, + "contract_type": { + "$ref": "#/definitions/ContractType" + }, + "contract_time": { + "$ref": "#/definitions/ContractTime" + } + }, + "required": [ + "id", + "created", + "title", + "description", + "redirect_url", + "category", + "location", + "salary_min", + "salary_max", + "salary_is_predicted", + "company" + ], + "definitions": { + "Category": { + "title": "Category", + "type": "object", + "properties": { + "tag": { + "title": "Tag", + "type": "string" + }, + "label": { + "title": "Label", + "type": "string" + } + }, + "required": [ + "tag", + "label" + ] + }, + "Location": { + "title": "Location", + "type": "object", + "properties": { + "area": { + "title": "Area", + "type": "array", + "items": { + "type": "string" + } + }, + "display_name": { + "title": "Display Name", + "type": "string" + } + }, + "required": [ + "area", + "display_name" + ] + }, + "Flag": { + "title": "Flag", + "description": "An enumeration.", + "enum": [ + "1", + "0" + ], + "type": "string" + }, + "Company": { + "title": "Company", + "type": "object", + "properties": { + "display_name": { + "title": "Display Name", + "type": "string" + }, + "canonical_name": { + "title": "Canonical Name", + "type": "string" + }, + "count": { + "title": "Count", + "type": "integer" + } + }, + "required": [ + "display_name" + ] + }, + "ContractType": { + "title": "ContractType", + "description": "An enumeration.", + "enum": [ + "permanent", + "contract" + ], + "type": "string" + }, + "ContractTime": { + "title": "ContractTime", + "description": "An enumeration.", + "enum": [ + "full_time", + "part_time" + ], + "type": "string" + } + } + }, + "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" + } + } + } + ] } ] } \ No newline at end of file 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 00000000..f9fbce03 --- /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 00000000..e4cb6ed1 --- /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 00000000..ec6e7b91 --- /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 00000000..5f6f09aa --- /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 00000000..39b7d36c --- /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 00000000..91d84199 --- /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 00000000..09410f22 --- /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 00000000..5fe33e65 --- /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 0000000000000000000000000000000000000000..24b37ca82ae03c1a94e92e90f66df392beaf6cd0 GIT binary patch literal 6520 zcmc(k)mIb_u*d1{?(Qx{LXZXl*-szA z{tfp&%*?}_dHK%F!{>Zs0PoZY@#yeSP*4ap)RjU1YWjbHgZ3{sTJC;FL7|n`P*%|M z&N+Z+k9Qmbv%5WC3g4B+nNn zx`=6|Vt}tL#arTd#r;Ac&ua<1k|@=}zyD{=WMW>ecbdCF#jCc?kmu^t9Xl3g(9OW^ zhMMy;<@&+i26AI>Q+K#g**gFHg@4r-LBO5i+7h{f+&2+v-m6b0wu<(OM(w;~U((a_ zY#@+R3m3iv&pxo#vf|NY|J2JxtEKmbO+rB_=1NFo=J(4)klxX+tiF8 z*-LlKQ@6*;&MVdLt38QuKz(*aP;tUad&r#*NUZsIXs+SR6$y@ zOnW*6p{_)-w$y*!1L=?hUoO?LE=#)g?%*OC}p)gd@yW+yeFrje|_%Iz#fZEZ!<` z6eWx8Q9>{3PK--Dhjwc;B_JOPnZUDMe@ahA*4EC>dc{ZTw~)u4j%sTf>e~L!_lru8 z&BMLSNok5x{W8u+mOfrLSFrwB<>K)kpmVsCpG%rifI&i|9lN*i&o-a+XH z=^w}ajpo&8^f4Df=@jAfjsw zj-+F7KTOl_>h^K9f3AG}E4tJAgXn3AGo64PeLh{{x;3PqS2Nj%n>x|q&r@n3+t)XA zc=}ICvBgjwi^bcHn^;%&;B752&a!VMA6IO=paVq%G%qZQM41P>(GpCn(V~uN_8dJ< zfQ7{tP3Fa^3z>I)h?A@%D;F|9xAQdW1y)Ts(S+2uLV(1{w0o86Q8r+5=qrrv#?r5W zms6V82vR4!3v6wI;F?i0+q5FTWquXySztpyMMSkpwZd+64MO%4O0T{A^+xLWPPnJU zu@;cmD=`sXTS^gF_!%KUh5OKFThr>Z#()F05C)3a$N?IxAT1zY5DOb`O1`h&kwk%g zo%GWSmWlH>9D9{<^aThv%4k3rbx_dX6P*DV`XRC_$C`b87w1UT$~Z_{A)ujj6 z4e_r%ZNc&qnCROD16+OfF3dA-MycR2g)_wkl@#y!z(2l0&c06dger1P(F1!(W0FU| z=o}b@bF@+~KFN(pv{Y05|bkue( zEZg-o(a0)u+>O0Hp#{QnUMT;eK3-J)E7o_L6uS26N4a!?`uWT5zcAbYtxv=6dwIiS zb;uDMh|f;ark@iL4dE{Ymt3yL)-W}yPiT`vfRg%n=*thUnC+`vNXotn*6OU=ITGOV zeAbSUVe};u)brPVt9|8lNe?J75PGNI-<8x}BxyW*lzBXB_L^aNL%;tcj^Ec!>A(|K z)CdFiT5&q?L`+?HX<^uU+ZeneyyQ0;an~*JeWgB%b~Y}5&jk@KPbV#TX#dC`@l4Ap z7p$Fgy{VpkD3?Bq_-rS`>p3%6n*75{H9uKhpVqT73|t-#3{@vX_l`rnw!6I(y^c>O zh>j|0{=d>nc6DS2b;|ihWYvw0K~Hl)7SxDc@M^aL`Q9g&`Xodd&nz(5cxs{Tqjf&s z0TFdyoyfc(&b+wS?$eKaDvp9lS^THhDjOWV!q2VTZH#_iHwlRV2f`~XbB1W`ghN1S zjWj$o^?Ll(0V5o8M>uc-%7b6{Uh6QC0iyK@R7CsAo#tuKi=B7J#YW|L}E~+|KS;q4eg22*J@3AYWI`g zQ(7ckvD(Pm@#Z61la6F(8mSy+#)&6B1j33-jGB%f4z`;pbP%7hHe6);baq4jTTj2o zkRplX>+Lg29TGBP;m&$P2sT* zdVyUE4pRr37}R~SyXem!qe==^H0o{+@*GG_azl!JE~KQMC#rgUpP=@O+T$uxQSp~R z%a*6x3+X!K4SFe1Wi|V9q9W=k4yH}{HTyD*8a9YSltQ zbM|g5L^ZeQtCgjtu7F6o>GiiJtD?eTYM#cUIiH=b5i4~QnGSSTHL5(*VRgz5*WT9c z8_CK`pWX>8@j-axgJyaaiqCsf_9#u0PkfNeV~ z_U!<#%BBo-9!cGarFbw-=X@P{_De=XX^QPWVG%ANWQ^7Pq}$1vlBGy{XLHaCmWuQuqgiYouAZh9s~K2XIqphB-|bdR*7=0}t3Xx@ z_e8h19*^w#-XVO$5_bA=Fn_VZP&d|*CUCQ9G#f*%1}V{dF5wmZ0KYDn%^UcTD}@JV)>yys3>mJfy0)aWA~*+>Wh+&u&T=B zSnlMKRFd1%T z3Igmbd`_Ah%51@f82`6#HF33D&H7pnbQpg`c)lFwRK&C@BEg|Dw0v0d+1Lwu@Ed@& ziG=@t?}=b%y2N_jt~I{bGs;+j5&XN`?Ebi7j0?;wIB=em81t&~7_ zNtEeG<0J)9DCl7`auuJ#HOjDkc@{yeLIC?5rW4^$ftIG?Sk~=n1`~84zIrK3wjI^5 z`crtq5kh1ohA8}1Qd~&_R6oFs!f3r~I8tilBrwU*wtou#LV-4->TKMA86;U0=C!hj zi0-6tr8I_u?8$iF4J(&RHjF|TLGUtAY7yb2AsAre#YfA^ACVPeoDAa}oe?-!KT}b& z2DH!x>#v(<`pWW?DNPy%7?REh`iO3s7 zkusV<6p9G$G=ahGF$GQbvVzzWaZ@F1D2h&S>8h0qT zkR<+e%KKGv+d&feB;INwlzcRo`b=j;%+$?=fOu2Z;ehco<^{7~pWTBe!q0(p#54v_BWwyy$7KP9{iyQuHWygLP6WgSx( z-W)HzBzWynEc`V{kucQ|5r`wkjV#b|HHx+RTRy1)Be$NT-tYNRvc%LHC4v$v^(q|1 zfL?WZ@S%b}M|)8+?ZQRsNLe|28+PWTROpSy=7H_R6v%ll%}T1=oZ8)c45D`GeX5|Z z{q)$@w>-80W$3)*p1rD=)drNy$$$FIx%Ym0(%Xa*0%%Xk>3Z!ViA6muyai!N%4;+< z{lXB#-jY}$MV4L=G8wEoACNJjOdaUAsV0s3I_$vbJw>RzVge{8KBSlEvGOko1yhHg zMbExB%+B0P}z!D%twp<}ltzYqsk+?_ATn^WyHk0Os`{{*S( zDVNKL+sDhTG|~Cp8iNuc=Op`S|5o1|m(+C#27etZD@=hl0LXapXlETx@H`Vr^JOD? zo9v-#+Z*~p1_dPQu|WU|`-B-(_q2o^CHN%o%O60#qZ>^PwPeuc2`T+YL<1!pVACmo zWEflbu9kwpO7FGudiHr9-UZV#il;r2%H<7e_Ndp%?s_j#|2hxjj=~suQ8%s<+)pKN z^p4+{B+n|!eQ%j^m+6O_vwXhs5K(wQIVH+X(9kcl$WP3DgyLb7sYykD5Ktz<1)4H8 zg#_`77mB=kIT1KMCX11ZzP{b@Z!`9GdAQWQYIlue_(WPk71r-mOhF4-8(-YCUXe4U zM-@Z0mwYVcAAvcDk)b%0IJQryJ)$i`agxqJoBq*8R@4iLE)nl@{zw4E&$Q^n;Wsex zWD3+=3mr})?Kb=7;p&?ne@kL13e*7%EHe)`fjU)NaO*q3XpOc(3xX3dMbBb4l|>om z@K^YHoseeMj0WZ|%UZ#MDuK2=hhMHgS4P&KPuv~Onn%@26F8@Fs&1OI^Zgv{H{jLn zPmgaw=GQ177g|*JC9P9KSlk`I72tuq5WDBSR!&<`;LtBh@5S3uT2rBw?1ON7Jt4}R zfs@=&5+&-v>K7s^hE9b7xHVk8U2C;dX3D^A(m`~buk(&i9Zo4o|_vy39KreGcMj1=Wuo&6;&5CYV%V!outWSp9hEKO7Dm_4b9WB)a6(Z~} z4I4VsBJPJ8od9OLCjYUV=}pCJv3|ZD-;I51Tgg~GjnCh#kUEUJMo$MDNV%5dg~35H zVW;4y9OtmjH{7SWm+qGeVYYg$wMK<9i3Rk)alIX4Jt45U-ip^hblEKMQZ~uQ@8D?` zAB?UkV&H0grF&XAjvsCIU6!&I_TmFoi^*!%P;caI-^+p|5h^!8Ia?^w_I-8oy0Clr zWhPc1mNV^s%2U!`wGM?vF%RU_jImZTXa){ZrMKpr6mf6Gwim1G=*;>&p7{;TRmr(q zo8+a&lC5d)%SU142{!9N#qd}-fBPidOKq^{{piKx^V+{OX8 zsK4UtiM%@^*8A{Dc$#GxVDU_oKseO8n*Fr#XBCy8kC1@o0byNtE@U+ zX9~boBY@T+g`MQ=9TBnxYDL$(E>nmILLQE49b1p($CVquU&jNEQ9GDJ#h*y0gk+^S zl|(VOU2sdn_$gJMBKbJ7&`7r=XicDe3xOV8h4XB)MYg=DfZbGGt$D3aS8S3q!fz#_ z++w1BilIyIBY66d*px>NB;SHlvUX#(3cs{<{=}k4LBbE>i5JCQn*6$h#-sX=%Mv?v z|4>8P9Z=n|J18{JO->4ho0axM!xTLQh)KD7#=>8YkiE4sz>iK1s&|*IBQ@uwOD2hd zTlI`IikoFiJ^?xuee`lsv&GlsOVrX@D;)EP?wD(>QUt+9IK0C+#_o2yP+)~ba+_G| zSP_on8*`^;Ivi;WMr0&dS|o+ALTWNrKGg7soOIM}-!Ri+gSW1u^e$)Tr=vU_uWKVn zn-Z3e%mDW{uEKp>ytykAe;asWSrC!SCB(5!nq;H{g-dM0DK7y>h+UkD@mX<^lg&Y0 zR4=IHFbDVbbD~0AVrVIx4o0@42*wSRYpGPqg4$=PPMK5>HXf}tmk)Kgedz7$o5{fssAf!B&iVHCMVkLGJF8tOzIg`aefoIxxrG!pniWgB z*5`7SmAIQ$Z*gVy8-9ZV0%w#EH!A_f(Y`5d(eJXEvZGTGP!IP}91>#Ga>dT_;5atK z?D*JNC#ZdFbl&W|&0we25~>50Y!{UiS!*(yYRlHKZbys6R3F2!ZG_inE_;v0jdXm( zQC^*dfn}x}NBlB&DtOBjYTH`V32)Jx3rU7Vx*tbt9q#e{XlOHH>|*-S6@wL=3(}<; zSx|#*C2Z8DmE7^SC@ZOQKh$=%&-E~FjejqH<7PH_m*i}<*Gn=|pk=tTTOgZ4;DApyNp17+0%Gu zadAlkr-SB)m1E{!?4mS7)RpX*kZ~G^*hAemdJTc*DrtcMxCymL3B0@ z_X)$~vfRtaOQa|7b&8^)t|KEH2!`M zlKtGdk2um{)(=>!?5;45FfdMYj68N(7+Z6OFWcaT9RCP>Q=>3<5Ax2Ww@k1K8W+gs zOsr4q7AfYm&XKr~MI%&`>(+k6*bXEkk0?J2q)^3h~G?xkW%iLcBLIh!iA!haIb zo~T}P2lpCF?aXO@q}@o=WZ#=>p$Sd)i~{H7Jc|~dWt2F7;Gik?gqVJ-JP!VY7#m{l z%ij3(i^v0i#EpL#m$>y5(NKA(T&wso^nU=w CN_h7G literal 0 HcmV?d00001 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 00000000..88224dab --- /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 00000000..42d354e0 --- /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 00000000..42d354e0 --- /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 00000000..e69de29b 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 00000000..4acdd0fd --- /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 00000000..a73b9cce --- /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 00000000..a1040f4e --- /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,)) From 839d6b03c41f5b6771e42f3f4f3f8298b78bf433 Mon Sep 17 00:00:00 2001 From: Nedhir Ebnou Date: Thu, 5 Dec 2024 12:27:50 +0100 Subject: [PATCH 3/4] feature: Add France Travail(ex: Pole Emploi) Connector in CRUD v2 --- README.md | 2 +- manifest.json | 7027 ++++++++++++++++- src/hrflow_connectors/v1/data/connectors.json | 4 +- src/hrflow_connectors/v2/__init__.py | 2 + .../v2/connectors/francetravail/README.md | 83 + .../v2/connectors/francetravail/__init__.py | 3 + .../v2/connectors/francetravail/aisles.py | 662 ++ .../v2/connectors/francetravail/connector.py | 138 + .../v2/connectors/francetravail/connector.pyi | 9 + .../docs/archive_jobs_in_hrflow.md | 245 + .../docs/create_jobs_in_hrflow.md | 247 + .../docs/update_jobs_in_hrflow.md | 245 + .../v2/connectors/francetravail/logo.png | Bin 0 -> 11665 bytes .../format/archive_jobs_in_hrflow.json | 3 + .../format/create_jobs_in_hrflow.json | 102 + .../format/update_jobs_in_hrflow.json | 102 + .../francetravail/notebooks/.gitkeep | 0 .../v2/connectors/francetravail/schemas.py | 311 + .../connectors/francetravail/test-config.yaml | 67 + .../v2/connectors/francetravail/warehouse.py | 7 + 20 files changed, 9124 insertions(+), 135 deletions(-) create mode 100644 src/hrflow_connectors/v2/connectors/francetravail/README.md create mode 100644 src/hrflow_connectors/v2/connectors/francetravail/__init__.py create mode 100644 src/hrflow_connectors/v2/connectors/francetravail/aisles.py create mode 100644 src/hrflow_connectors/v2/connectors/francetravail/connector.py create mode 100644 src/hrflow_connectors/v2/connectors/francetravail/connector.pyi create mode 100644 src/hrflow_connectors/v2/connectors/francetravail/docs/archive_jobs_in_hrflow.md create mode 100644 src/hrflow_connectors/v2/connectors/francetravail/docs/create_jobs_in_hrflow.md create mode 100644 src/hrflow_connectors/v2/connectors/francetravail/docs/update_jobs_in_hrflow.md create mode 100644 src/hrflow_connectors/v2/connectors/francetravail/logo.png create mode 100644 src/hrflow_connectors/v2/connectors/francetravail/mappings/format/archive_jobs_in_hrflow.json create mode 100644 src/hrflow_connectors/v2/connectors/francetravail/mappings/format/create_jobs_in_hrflow.json create mode 100644 src/hrflow_connectors/v2/connectors/francetravail/mappings/format/update_jobs_in_hrflow.json create mode 100644 src/hrflow_connectors/v2/connectors/francetravail/notebooks/.gitkeep create mode 100644 src/hrflow_connectors/v2/connectors/francetravail/schemas.py create mode 100644 src/hrflow_connectors/v2/connectors/francetravail/test-config.yaml create mode 100644 src/hrflow_connectors/v2/connectors/francetravail/warehouse.py diff --git a/README.md b/README.md index da568489..13b38dba 100644 --- a/README.md +++ b/README.md @@ -74,9 +74,9 @@ We invite developers to join us in our mission to bring AI and data integration |-------------------------------------------------------------------------------------------------------------------------------------------|----------------------|--------------------|----------------|-----------------| | [**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 46599a5f..c7288ab3 100644 --- a/manifest.json +++ b/manifest.json @@ -64472,62 +64472,87 @@ "type": "object", "properties": { "id": { - "title": "Id", "type": "string" }, "created": { - "title": "Created", "type": "string" }, "title": { - "title": "Title", "type": "string" }, "description": { - "title": "Description", "type": "string" }, "full_description": { - "title": "Full Description", - "type": "string" + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] }, "redirect_url": { - "title": "Redirect Url", "type": "string" }, "latitude": { - "title": "Latitude", - "type": "number" + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] }, "longitude": { - "title": "Longitude", - "type": "number" + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] }, "category": { - "$ref": "#/definitions/Category" + "$ref": "#/$defs/Category" }, "location": { - "$ref": "#/definitions/Location" + "$ref": "#/$defs/Location" }, "salary_min": { - "title": "Salary Min", "type": "integer" }, "salary_max": { - "title": "Salary Max", "type": "integer" }, "salary_is_predicted": { - "$ref": "#/definitions/Flag" + "$ref": "#/$defs/Flag" }, "company": { - "$ref": "#/definitions/Company" + "$ref": "#/$defs/Company" }, "contract_type": { - "$ref": "#/definitions/ContractType" + "anyOf": [ + { + "$ref": "#/$defs/ContractType" + }, + { + "type": "null" + } + ] }, "contract_time": { - "$ref": "#/definitions/ContractTime" + "anyOf": [ + { + "$ref": "#/$defs/ContractTime" + }, + { + "type": "null" + } + ] } }, "required": [ @@ -64535,25 +64560,28 @@ "created", "title", "description", + "full_description", "redirect_url", + "latitude", + "longitude", "category", "location", "salary_min", "salary_max", "salary_is_predicted", - "company" + "company", + "contract_type", + "contract_time" ], - "definitions": { + "$defs": { "Category": { "title": "Category", "type": "object", "properties": { "tag": { - "title": "Tag", "type": "string" }, "label": { - "title": "Label", "type": "string" } }, @@ -64567,14 +64595,12 @@ "type": "object", "properties": { "area": { - "title": "Area", "type": "array", "items": { "type": "string" } }, "display_name": { - "title": "Display Name", "type": "string" } }, @@ -64585,51 +64611,58 @@ }, "Flag": { "title": "Flag", - "description": "An enumeration.", "enum": [ - "1", - "0" - ], - "type": "string" + "0", + "1" + ] }, "Company": { "title": "Company", "type": "object", "properties": { "display_name": { - "title": "Display Name", "type": "string" }, "canonical_name": { - "title": "Canonical Name", - "type": "string" + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] }, "count": { - "title": "Count", - "type": "integer" + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ] } }, "required": [ - "display_name" + "display_name", + "canonical_name", + "count" ] }, "ContractType": { "title": "ContractType", - "description": "An enumeration.", "enum": [ - "permanent", - "contract" - ], - "type": "string" + "contract", + "permanent" + ] }, "ContractTime": { "title": "ContractTime", - "description": "An enumeration.", "enum": [ "full_time", "part_time" - ], - "type": "string" + ] } } }, @@ -65687,62 +65720,87 @@ "type": "object", "properties": { "id": { - "title": "Id", "type": "string" }, "created": { - "title": "Created", "type": "string" }, "title": { - "title": "Title", "type": "string" }, "description": { - "title": "Description", "type": "string" }, "full_description": { - "title": "Full Description", - "type": "string" + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] }, "redirect_url": { - "title": "Redirect Url", "type": "string" }, "latitude": { - "title": "Latitude", - "type": "number" + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] }, "longitude": { - "title": "Longitude", - "type": "number" + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] }, "category": { - "$ref": "#/definitions/Category" + "$ref": "#/$defs/Category" }, "location": { - "$ref": "#/definitions/Location" + "$ref": "#/$defs/Location" }, "salary_min": { - "title": "Salary Min", "type": "integer" }, "salary_max": { - "title": "Salary Max", "type": "integer" }, "salary_is_predicted": { - "$ref": "#/definitions/Flag" + "$ref": "#/$defs/Flag" }, "company": { - "$ref": "#/definitions/Company" + "$ref": "#/$defs/Company" }, "contract_type": { - "$ref": "#/definitions/ContractType" + "anyOf": [ + { + "$ref": "#/$defs/ContractType" + }, + { + "type": "null" + } + ] }, "contract_time": { - "$ref": "#/definitions/ContractTime" + "anyOf": [ + { + "$ref": "#/$defs/ContractTime" + }, + { + "type": "null" + } + ] } }, "required": [ @@ -65750,25 +65808,28 @@ "created", "title", "description", + "full_description", "redirect_url", + "latitude", + "longitude", "category", "location", "salary_min", "salary_max", "salary_is_predicted", - "company" + "company", + "contract_type", + "contract_time" ], - "definitions": { + "$defs": { "Category": { "title": "Category", "type": "object", "properties": { "tag": { - "title": "Tag", "type": "string" }, "label": { - "title": "Label", "type": "string" } }, @@ -65782,14 +65843,12 @@ "type": "object", "properties": { "area": { - "title": "Area", "type": "array", "items": { "type": "string" } }, "display_name": { - "title": "Display Name", "type": "string" } }, @@ -65800,51 +65859,58 @@ }, "Flag": { "title": "Flag", - "description": "An enumeration.", "enum": [ - "1", - "0" - ], - "type": "string" + "0", + "1" + ] }, "Company": { "title": "Company", "type": "object", "properties": { "display_name": { - "title": "Display Name", "type": "string" }, "canonical_name": { - "title": "Canonical Name", - "type": "string" + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] }, "count": { - "title": "Count", - "type": "integer" + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ] } }, "required": [ - "display_name" + "display_name", + "canonical_name", + "count" ] }, "ContractType": { "title": "ContractType", - "description": "An enumeration.", "enum": [ - "permanent", - "contract" - ], - "type": "string" + "contract", + "permanent" + ] }, "ContractTime": { "title": "ContractTime", - "description": "An enumeration.", "enum": [ "full_time", "part_time" - ], - "type": "string" + ] } } }, @@ -66897,62 +66963,87 @@ "type": "object", "properties": { "id": { - "title": "Id", "type": "string" }, "created": { - "title": "Created", "type": "string" }, "title": { - "title": "Title", "type": "string" }, "description": { - "title": "Description", "type": "string" }, "full_description": { - "title": "Full Description", - "type": "string" + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] }, "redirect_url": { - "title": "Redirect Url", "type": "string" }, "latitude": { - "title": "Latitude", - "type": "number" + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] }, "longitude": { - "title": "Longitude", - "type": "number" + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ] }, "category": { - "$ref": "#/definitions/Category" + "$ref": "#/$defs/Category" }, "location": { - "$ref": "#/definitions/Location" + "$ref": "#/$defs/Location" }, "salary_min": { - "title": "Salary Min", "type": "integer" }, "salary_max": { - "title": "Salary Max", "type": "integer" }, "salary_is_predicted": { - "$ref": "#/definitions/Flag" + "$ref": "#/$defs/Flag" }, "company": { - "$ref": "#/definitions/Company" + "$ref": "#/$defs/Company" }, "contract_type": { - "$ref": "#/definitions/ContractType" + "anyOf": [ + { + "$ref": "#/$defs/ContractType" + }, + { + "type": "null" + } + ] }, "contract_time": { - "$ref": "#/definitions/ContractTime" + "anyOf": [ + { + "$ref": "#/$defs/ContractTime" + }, + { + "type": "null" + } + ] } }, "required": [ @@ -66960,25 +67051,28 @@ "created", "title", "description", + "full_description", "redirect_url", + "latitude", + "longitude", "category", "location", "salary_min", "salary_max", "salary_is_predicted", - "company" + "company", + "contract_type", + "contract_time" ], - "definitions": { + "$defs": { "Category": { "title": "Category", "type": "object", "properties": { "tag": { - "title": "Tag", "type": "string" }, "label": { - "title": "Label", "type": "string" } }, @@ -66992,14 +67086,12 @@ "type": "object", "properties": { "area": { - "title": "Area", "type": "array", "items": { "type": "string" } }, "display_name": { - "title": "Display Name", "type": "string" } }, @@ -67010,51 +67102,58 @@ }, "Flag": { "title": "Flag", - "description": "An enumeration.", "enum": [ - "1", - "0" - ], - "type": "string" + "0", + "1" + ] }, "Company": { "title": "Company", "type": "object", "properties": { "display_name": { - "title": "Display Name", "type": "string" }, "canonical_name": { - "title": "Canonical Name", - "type": "string" + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ] }, "count": { - "title": "Count", - "type": "integer" + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ] } }, "required": [ - "display_name" + "display_name", + "canonical_name", + "count" ] }, "ContractType": { "title": "ContractType", - "description": "An enumeration.", "enum": [ - "permanent", - "contract" - ], - "type": "string" + "contract", + "permanent" + ] }, "ContractTime": { "title": "ContractTime", - "description": "An enumeration.", "enum": [ "full_time", "part_time" - ], - "type": "string" + ] } } }, @@ -68005,6 +68104,6670 @@ } } ] + }, + { + "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(' ')", + "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(' ')", + "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/v1/data/connectors.json b/src/hrflow_connectors/v1/data/connectors.json index 90cf558c..f498ea46 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 76b15555..7eddc5ee 100644 --- a/src/hrflow_connectors/v2/__init__.py +++ b/src/hrflow_connectors/v2/__init__.py @@ -1,6 +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 @@ -20,4 +21,5 @@ Hubspot, Recruitee, Adzuna, + FranceTravail, ] 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 00000000..f5891815 --- /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 00000000..fdbcd4d9 --- /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 00000000..584d7aec --- /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 00000000..4f9010df --- /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 00000000..3923755d --- /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 00000000..f2385365 --- /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 00000000..e7e502c3 --- /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 00000000..d43ddec9 --- /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 0000000000000000000000000000000000000000..4f1b1c917b8c7c451e121fc86af49ab97ee3f95a GIT binary patch literal 11665 zcmeIY<98k07cJbhF&pc|$q7zu_X$pHv$1U_O&YVYZQHhOH@0!&-2UFr?_Y4o{jl~L zW3T;bjxm?^3{#L3M?oY&{PN`sill_7(m$W{KZA$;ck)9y?EZ5I_7a*-U%nt={Li4~ zHhtgzT|zl2i3@+JngX1B`9k_dQdCIA{pUp{oV&{6QunrUQNbT!(u5hl(76J5axfSj zsul?v9SjB!1~`IYR7BGxVj0PG{}U3ep!tdzKq?!qR3M4=M+V4N{J!~08KCp<;@8FJ zee8xhErJj)V7BBtt!4GOw8j^{$Bnvmp!v7k8fx&{S+}*K9k&G(8a-NIibl^j5YY4i z_Mzt%FEk8>zsAr|%}xQ0KF0t5`q2COFI9U$XCBQ~#XAc9b@LbL|6DGoc@$J1?DV%j z+ne2c15Cb^eZ%1lx502wi4M9|z)rkx`O;=;0PA7pz=kHuvy28 z9*xm#Mb>T2T>NpAQ^u>FAX#j-hfFt2l~W1~KOIJj#YI)wm1ESXsp(bA1MphR+;rMK z0l9wV4v_iY#>DWaVXLOj7NL&%&ZuO=Ed>oO1|cO;mBfhQJuIT#Z=v_q?FoHw)52)G zTx+*>EOk)2C4&MmNd}IB`j8MSk(P{BSN6exwW-%MlU!)PdS6m&0%B8m*@})fUG(a5 z5{2Bp)=$*A? z((qT@q~W++xe7QKQPfrR7Q-b1PH|-g_`RIHkw0enw44vhU+G&*>B7pw4^OmlQB`r( zZZGv$qa||fL-W>no3L}o;nGvRR+u_deg`vrQLy1i{AhE#$Z;${wmC ze$>yoK~1e*w`{u|-VQ8&^6B$%Hd&yL{*?ZCY_#h=I6JpyC>noKZ;6Z9Oeo5MGFT_s zQ((5a%m4F7rZE6{F-9I*68r^-+2GWJp$EFwI{MhwV{zzBfvFaNZ2Or+eri|q$P-H^ z7*9QYkEP}be|nGnY0C$U9YGatC#GKfNyh;S?+i_H#HF6m>;NU3w8uzXEtEMTRMBCR z&N|GXzzsJj?tR7MeZqEAIjO!q+I|;tulzbqwOi?#q|CS6-g>=iNM*@a68`;%GhlEE z@*A}&Kc5CQtxPv%;OzyF`Tk#Kx3&P9ei)kRm}Jwez441p9!(pFh?})EPMLU2>(^C} z?o%RsxZxkd7DT<))STy8hM*FHo}ONL;^@8M(XoT;whMEz-+{MOl9h@$U;C^Mev{v_ zrk?R#W=mlyQuZN)yTO8=nw=tqcIBpiH5$C5q5=fNN<&$6YOut~aIvQ&NEqT40ci_~#>xnn39Zl+kRZ10bx>INd6A=c) zQL|Ho{vNfP#3~E|3Dj}@PSETVu&j4DREQ?k901Y_Ufge!5a>q}OmDyX&bq20TM4 zYi3or!C9I(WF#{*N&(u-imUf`us==Cr`PBS1Q)CObL~gkUch%h9QvdG9;^!fG(W~b zjRP$;WjxQmZDrIZ%%j7oI!Hu?Y<2R^wVCL?waK@90Spg?R#4VKgaQs->9xgaADIg} zD4`k_YIM-cpnGrp(GQM?x8t0ZBudE}gmv=AO0XkxBq`{)n|@oQ%VfXe8v#4zSCA#_ z@I!x7leDC!SKCDbg&hSqj^wfrL_JJroVPUVep{-BE7Fr?g)YnklrWuP`4@v02I_OL zb{hZ2K}dyFm|G1(E1a3jKzuKVx)e_1+Fs zJm?JoMJXH|Ze?!79t87p;hn*1u%&+;V^zREc@sSS4) za-c&O@chG|yd^5&8cvsaMOvjsbTTXF-4)g%;vtHKon00;)4?k>>dtPU2p+7Z=d}Cu zw-p$UwE`NBd5;L!Vk1)Hb+Ej!lqG=zZsE#0znney)~7%|OoO`?f~*MD-KfwOBz5~(H3KndR0Qz=;9sozIoXFl%u_He2v{h+3~-F z25j!H?+iH>bM+;=rA>j!@bgEpsLpM*v1crRZ{s&cJUC^Z1e1t=ir2Zte!0lslR3;` zVNd{z3E2O}1v!P{$OijpiY{IDhHE{sBF4L0n84Fq1|sFJqgKm#r;oCAe;Yiq)W0Pj zxI*`IZBO%J)0XQ0{7KW`+gfZEGNFIDd*yKv#Hi!t;ewTV-(JaU_@>+bSnKsEWcgDi zv9ldg@9_$y#ZfLE7Afi|0?cMw?`bB4Nc}2PV;tmA=b~hwCEW=VqhGS#2-aJqiOU-D zBJm!r#q_{piW7T%OjaZpK-ZnEg+X>D-l6eszY*`!=z?XFC+oETQ=Z0=Yj|LIJSSU@ zr0Nzj1_(Kq82qugB>G(mrrLF^1ecbqg;dBPkHB`{A_BL@atk^i}vO^ z+)TIPt6gUk@I9-INL+C?G%xf`(p!xqVE2gy`*+7Vph;&gpw7$9piHr^%Xm&uOVn{s zY&SRXPZ-gZh&1B&C^zX@-y5JMbic~U%|3M3%Vo{T{K1%tu^k34ht%1)C5v;<#c?++ zTxKlBgm=xBZbvFQlkr@cB=#yAP)fQ_zND%D*x`!RWXp`*N-a4N#D$5Nj(oPA8H_?V z`sq!tXhN4IH+KM-dP{nZN7hf2pe-seE-Ub=2`8@zf^mxG&bTTmRsJa;ue)|GK zi&v58S5c`j4|Ry&HaZP(3A|Nt7Vja$Z(9j(InNpiA0va z7iR;qa#pe7C=rYin;V9m36Gw1YH!m|5b0h^v6lU7(QXE?^{$U8&+pFhV3jDW2(3a_ zC|&diaAo$?5|hI1MnnKx7(u1brKD+V=R`Xyi3kzk%)+1=n>~p(oy+g|I3!0U9x+|H zb8}R!Com3jve2K0#^Tzgpl^MLD zauPWcQ=!#MGAZvidFJ9XSI9>;3f`WUe?@bGh=|<0BF)ziN2!d`^u1>LPM!yiw^sb5 z5<@%p-}dv}k4^EUpJ(@Q{mZ`fY)svR1IGNqLmu<}IY1;kWIcZMLutaupw9JT81*QR z@=3B>34wzORaMnKk5k+82l%ZeY(NvpgF>j_+Dk71l2S02B~NCtkuwob<@;0?{Pd(K ztFpH#e`)A0f-&0G=t+3CGM*yeC?sFYz-GqI%+gJ}wqLeVY^=YFW+NUSDwzI@PyeKk zCMcK34cjEsBP)jN{R;=B{AR5nC^D-vWBgRb?5SQ?LMEI#G-xlyyYm!oOoc{P3;|_v z?%DVOjsK;ZtF=;BBD9Q zW|a8$Y`nfU1|I(TGoY=7I^3p1s2IaxM|%KJ_Ef3X`Iov__xQpyA>O^WdX<%yViA$z z{C?K3c)iaR0*>4?S2FO(7lJk;(uINq(e%}7NKrzS zz2yUEKx>)IxebRDB~Nt1c$rc0kTl0f2oayApgCZv*IH`Zi%qr4QuJUS>rD$wTs2G- z@Pg|38q{*>j4EsH3&y_mv!)9k*|t_R!um%leg2N;HHw9*l;B&q9ie^j zG;-Ed`_)x}j3UX618>oB)l47%!-@@iiDp(T=C;ZCy-OtiLJ){hRb+N>w*1%a~W!^?%dUr2=G!gy&%H}Cg9 z&~Li`v8etb(QnyzHYDgDgRk*?X4;3Iu0A|%_Lx^4hR2&`f*uLEIrgz>ZIm^t>)Mid z>jkJIB%je_>kvIl0qr|}S`0C5PgDr-WGEo*umusu{5g+^)6A!VaMFnzaQGkSRpu?% zv#~s2aqWlwi4e*#W!qVV(`Y*NDw=!=C`qNECY`OGVW_8abLq&)nHE+I=ze`$>y{w> zhg*LDgp0MsPh9KgPX<4#q8)YYRRb39Hyz;QTHk(wk$v9W7 z>n3W`#nyChg>_v&LW7-Ry3q8du&Z1s;iYF#LZI_u$IW-Bom`^y_*Js1Y42DJs&Q7M zeIM^`Biu|9&rF=jQ?`byN@(X<7LYQX8<@^>xzD4a>wy+EIQ+Xk`Rz`fYV4FYD@g<$ z@4T3R%w~ktN2fs2+ko&5&d#{=li?z#;FBYYWS4tYdmXxqRq}sG>4Ac){~5yPwVj4% zf2E_2>F*_t5qH!8NRgMp&H|96m9I7Fk}$~h#an18ddeBBZf0frge5c0roOB(T z59B2&7_NM1sa|ia&}od9Pp$$(cyt!?Xl2imhMD*S&57TB&*<|dL7#2@gX*?WrmCxh zE}X7`Hap=SJOdE4#lbYQF}%IDWiM4%teOZc=5xP?@67g$kmW;DE-=P87&le`=F`|s z>q(v^J>V}~0fkq|PHL4f=2Q7vizoUADvdJ{XN&HT5=Ll-Cln!dChKx-{OrMplcy|i z&wSSr848SIw}YsIvHH4hXKaBB7#-L53{ULeL>8|#5!)CXrAkyAv4Y}%cUMji(@+kr z7$Hy_kE^CwfJ9}HKzz6hfUlC0c;fk@KVGxAsejRa4K74q%x7)&-6OHF?s%dMik5W}G~PTEsmm%};Vs((9!2NPlqrIPQI09Im3I79azUkS zI=ka9+1jhmo6;qZ!nP^h?x5<`RO(lh8wzfh{IS6wnpyvB5=}^!xfAV2qy-jE^yFg8oN!+94 zf*yF_xZ)akrF3IK9{CaFRH0`kwFDJ(gy>}cpl^4Rj?J-IHM=cn zQUwT|SPg%x$=q+W3M+GXTGSCWiYgRC5cB5umd9i@jV5>LkHI3@NLR{i%R@@tU4De) zl75Da54q;?^SN_6C0QRd;_}TGjSkK!zrR?H8?FSprEpsj#RqT6#_KhJZv2v9D5xil zb|b6Jm)pp=^xV+Xn=Z`W?jbx$%Au|dXV+tF&2h<2;Z2)j7|C%x0SGbQXLLKyo<^|`6j3%z(xb5#LQz2+% zT=In?XT1ODoVYiP#^Umr4B#U+*eyp>KHIJH^NXS4PjrTl4sdWMS!cA6dkM>5ks~(n zLYL#036gmExfg=60h0%k4r-_v31HE<; zrMVGBWoNrxidc`Ds<^}9y?C*GE$ohycbF~r0dj$WgbwKN;#a(xS58YTh(pV&Y60;J zzFy2F7O^0f?gH%Rj8SHx(JFA=_1tWGR>x9xG)H4rn6zD07h7)u%I*9kwG*zsR5>32 zogZI`D1wshxB$Jg&IGzjjNSC# zJYs3em#%tAuAM9@ca;(rE8v4oZXVj+>3_B**=K=o@@N~nn$U4o>7(^97ZC~jXI8t8 z@Q?(x`olzu;a~pV7ByO|weW_KA1ya_cMoIeXbSUxw`?|X(%(4S7vTDujb5aXEE5;Z zA42|;Dmr<8Z4r46hz8Ngc5O@=?6PpwzTp@sB^XRSsxxZ9*I1L3dUBq%FHk^cES9{R zgWP5FZ956D(11kykVYm@*GcP7Wc?dT032s=r(MKh_AEG18#-O_t8S4=B+L?ZG-?jiO&ks(MN0>^QjuJE6w|81mdwDLauiWcRpv|>Sf_Y% z#ZD%4X3ccX5K#jk1KxEY#-`AH@y^OQX|00Q{XH?B7C97{r~K>=(gxbhqT-rq+0B1y zM!H=URJNsXYgaQ)_Say{^2)9Y>Lrr*ZRaZ@mDqT#?o#yqY(4Fcd|>Q;-fS{sg@S5n zXHRsa`LGSM4SlP&fQ>FRp!LA;+*x#KUHU$Fr2!}8_ICFj@s7l{bsxI`K}e|qHn{`V#ssOe5OE}D=dcf?Hz3|oK1WVyxTF%|sKXGL@AM$Og>?5*GVWa|99LU!8f zp_53QKGlzt?=Y9;ap4`f+ze5C;2uk4nz++@8(GN)7nj&y15} z=n=~=Gxi!K7u4+z_gB1~m^n}8C=ZdAt$-8~b*$Gzls)mf5@ZyR-U|;mLM^Ue0$Vc# zO-BEK1Okt(#?&9dICkZ9s&t9_O^*!MqZ&`*NC8gte!!^LtBHyRBVwdvdb8bu!uu;f zw12sk3V`aQd_*=tov8ovbV(^8w4zHo@WRWapLr5GVdpzOEgvY?;Q221lbAK}8=MGh za>>tnEZHk_`EA)B@s$JPK+f2K_F54{)wy@1S&r|j*VKVeExI;>+TF3U>vB#i@`Gkt zkyUJI69cQq(PCNK!b}4A3_EIA4!=T0&(I=4^^QT-{dqn|eh$ZGxgKHs;_#8e4k0;) z2CX*P4VGF#WbaqK)tT*s6N8`2&h(#5eunH;YRNTi+p*I6OhQU> zOBTw~b!3n7E( zsG`9n6;y2XFjPu$BVl;XBi{Z`fl3pp3sKN|e>)ZsjIxXnK8<;!Ws1OtAVLeG9VP(1 zBfh|i$k3!tkW>bLxlmD46RKtCWv8vdqh$J3A1zHcd}7i_1Uu$zPdT9=vTU&suZ)Fi z6oOub!G715rkP@TE|S}I#Zwx++y6Foc$ZFoRjU7oZ4?TSVPqN9n^NPO_J{^&DpM-5 zI&z<{xdlGz!Yc6!L(7Mf zDJv4y3M;dKLxL-FKzW@S9m!!fR@|;C#JtpM{=TZA!{IuLX|c>=1Ehi}p@+DV9eTFk z6&Wzc=S+BH_G@^BUoCtkw^X&qtMaH|Wx|ta9kb5KSMTpE{v5OD0 z1KNHF1Tb~;`A^RtKv^2rfl-YN9bX?BEnL*$f_=LZnWDM(j}6m1*MkV;i6=n?HyZ~g zEfUKuADt-l0*tQ0grsS2fy0XL-$NapYPpMaRbj!9QB(ffU*F+E;r&$~2giLvyPdF) zYso#}TrUKq+8KY-Bxa4};lt>M4N3$~cdrcuUxc)Llo5D;3<5cA1qOUlD@!yx@!BD# zY!?^Pn)N0T=bj~Mh4c{D_Gqa=B+SXilumbqrlOfzAFBZ0Sp#54OmB>rui;7Eq)O!< zp>dF<6ZN z%T?2hRPk20;&lj<0Ao856qBt*E@`@i$^n5{;r0dLTe z%uTlTMyup9=9&SG+ZXzSb=3-?dt>E6CNd;_N|Xe3J*}l#@L3NTOs6!*?>cRdPOU6w-TsOSYCg01 z>hY)9Vva^Bu?zNCiCh(_J;Y&D%*G$Fxt=CRdOo0QaaM@h(g?p!sE5i+y_$K@=jI0H z<4`13nrt-DN1qMu58#qT95Gh+q@74>w3(u%y(Ly7jq01(Lnf1F@4D1V$n^x#5B7^P z_cJ+-U&Rfz0JI!qdBB13kCLr%F1A}QY;9atVGUQS@Fg7Sha2a2W7ef=!@0-dk|}q_RZ41H#Hurl+!~uhQr5YM+mA@WXZ^58vxpCoB9^;; z8^>aWGt|?JH7g+dPw8|1FG#>gat>@y2$6hM<`9K|EhPs>bTh8+P$d4i#e5qo zlb}brw}e>NGw0rx&U8sG#L*;QD$w!H_(@KJ{$(0!Jh38=e%mL2k>st%zeR;znsSF6 zKUxVqdWhOR)i8<#zXBz*V=ii&yYi$G;n07X>w7V0j-L4q#HDyFArUO2+<+YsC5RtH zvz9}E-aY#At<_nhA#BgmfR>4SU>vNM_9GpaiE(0}I5^&@X!Ma#8{LDTU?9lDXn$UX zAv^qqkEo!Eem7VWYW32)Mhb_a@0IN{NY9hrfdc0}q-*qkQ2WHy%Zd2Hl?X}~UcWC) zq znNGcWup!qi_Y6mq`i|K~LLQxXX?Ny?rg=*sa+fNC#b#dwnmv71`H;o*lvfPxWJ(nU z6rYJ(ByyA-DlhZ-`rD-`(jrAM>q#F46GDYC3-+aaY-^n>+76xRwnbNy^@y=qhr||B zjx?DxFxzOe=Y1-3p)au4xe@ojxuPK`s{7;ksO@5OiuLOC6?Pkw2}e%`Ho|#0Z2CGT zLepwff{NXnG*$aZ{3aIMmI5%Gr74By62^igr>kIoJhT2&5zzfl3!v`cXX>O98}mL& zMT$vWu6qbdpx5Fisd&RAr%(6oFJg9@MLm@9PKg*$qo+*^uP5%q%gZR_78Su6jyAp< zRNrQOdO$m|??1Trs{0m8v*CI5Uo;@{`f`DqHa=@0!Gna&{Y}YpYd-7M)-Hg&jU^+L z9$hnO=w^?4<#x|Di=-=M_XK|eFrS%Y$!0p{6`9qRHY;+OsDH2@)S5g0-!9VoH~ytn z{ZwIac6(f+CROddwZ~QfGDFi!*xpQK-Xt3b9kX?x4yW}~QlBRvnWHt(cGH%+Q~__2 zaiG@Dw_qklvyPqY%qUNE2fq41yfQ;nc+=6b+d(C$`Y|NM?;5X+;P0U$xI~+BBt8c9 zXk1o&Uo=8BMJG0Vi4m@0bw)73w1r@2J)7pyWSZur|_Qj(+Rau6Ww|F8%%~8vtLCfi{7M6f03x`B;Sf77f=jDltb$ z^I`Q-p_yIoJ2vj@MJ>8_{X6^J@MDqGAZ4o*zwe@ks?-Wy zKeQpQP>X+exT>$}*n9fMdh;2mpz$Rsfj}nS>af}vtOgtHxF&F_7(k|Ggt}Q?$b5L~ zJh9Oa*!m#9`KVUdE05DT#m>;j_Yf0ay1k&h6b#F4Uq22)WWurZ9S0Um(e;XP%nYDf zPEzItFzy!YelI3?+m&%|IKoQu?N&cE-}Ql6sWY3IHD4?NRChWr`|)=-e5r8Nz3ok7 zbgX#$7Ed1p^$(AwS8aDMC3#B~+Jj&rxUTKG_$>LTo|^d*KMN{LmFizi`mF9NhPKw* zzo6t@dyZDT8(j%Ez2pyXL6)~VF-;9uoPQebk#XeQ0eU?^&>0rmJ#l|kCi(9)C;O#)+@uDN~ zZB`4tui+)a<7?S85uvaG@#<+wdE%3O`$WXD*XBP0TvI}sLUqqQ-b&HNF@M&npOdy6 zC7in@6Jk@QpoSOjs*L_unbdb_LXsbHJJND1CBYP(m>Go4At52R_fUJq@}ZlX*c#rh zFi%g$#Y2GRY9Tajt3I;V@u^I+(FuXKY3~poz3-#X+NnZ3Fl)qyMa~>szp^u&DhMf6 zENr+BKV;J0c|}X>+mLU%bL{qNtrCK9)=k#_V7v0ry>z~WEZ7`}PGX|lw$%S1;~UA> zO}jZy0Xw(uNPRr~N2s!S*iQv=w?5|Q-Et<1acz&|&KCJe(gCT4+PUgsU71tII&qDrV&LloP+(}bYEy~lsC$hC5 zh(V6CTK?}S?(q)`#$4+txn|wLLEPm0;e2Iygq)xbQf*ylj9q$Q%;_ivj4xVlQGDa-Nyv2l>3_p_S?_Y{tBwIRK62*OBL7NI_r4qtkeOsa#t1~LncOA z?Ua&IHqQfqH^r~N z@LSDw4uqjD{^0&{(5-tIW+5rQ59SG;{G-~A-}nGc#z6y~+t+j5?O14_Oife{bHgGZ z7Vn?!f;I^t_!TF=i*>>P*;^$G*A)0hINdS)fV*-{0&aI<~7ViD#AfrdZ{23kh**>_tqE_R??$=}Z%8aw}+sqE;v zk0~fDCap*`QvvD!_UDyQVy^rCu1J0eprSZaqw+jM0s`twYtDJa*La7eIVPt2_udLw|gew-)q2@>;MGV7alhj^v@p)?vWjb*{Fh^<5x+|HA8PZUfFSiHi zhH6QK=>`y7%_%qzq>Ek?OcS|m6QH5)x4o$_$LM`ISb?mX1@dl+j2_cEHsl~Xe3tnV zZ5OKbE(K;`8;{LI>o_|6Z?%$b0^%G+fmLTO73tJE2!llUfbx7FkNg#Aw0>Oh$rKYa zDHPb#IRQ~f8Gj689PuF&vm|;%aIsmP$E#FoD5>FE^Y!KK84&xtpm1KSFcD%z6agK4 z){7>xAe>w}>w(2yoBkUq-vB&mvajuWeXMT{mP*MVK5MyU9(Bf;h}s?8=R`@~9jT$I z;-s^?L!9b24{K2c)WdAHPZUqy9x}d0P?%=_#;KfFlTRO8Zkb`*-(k{p0|kmPv43$@ zEBty^Q7+X=;LBFhY+*;|!I)VqPq@G-ME$c}eNH!|r0EUBAw_tceg#lIl0^@?2`RQn z1C2OQ#(5~H05~)XclB3YFLv<}bxwGgWg+Lh`OHg_P^~y2Ue?xulG$wIw@Ot?czz4{ zFaAV%01GW^Re(T%pHvbkQ7e`vL>|2F`gXt1-AX3XAeP?Lf06;8%O7G$>i`W+>&RAm zT@G6;;!&~L5@Rk}{0PRUEH23qgbM5Bj*DYg@%RYjb|Oy}DHeULm9w0Yuj6(Dbz}Fj zqV(;S`0I+Vc7HN2mM0VnkLG2J@I(d6X-Rb?u=llkWT2K8P?g?pu+)lBpB4O3!%~WS z3pFAfu)V)?7-Yw4>y+*rEfH0vl^^RE{a((s`u^{igrC8>MbprztOU{; z<)3B~haFaPRs8#jBWlis?fUf_-VXiawlmsCVRkF13lV!|&5Lxpt35*^OESbN{Z?h# z3IQ5gEQz01Y$Ku)uVhyM9Hare{9_xHD&5E0L88!{!0nY@)J2O}C$1Y0onhei3)O0= zg1u5Fxq8j6rsMPi21s(Yi~$EdkCbss4`}tQi=0XHCmplHg!O%r`iWlI zcD~tJH*4^Kv$5sfJMZY#`~2g9l+VZ?iGY5bHHGs`1UBXqOByBbD0_sOkJrZiVRcGp zzJtKhA2o5Co|@~w5fsFuVwB}?r`rtwlO@KXI^-Qu_zd4ZtHT-Fk~aGvBnQE;U#uK` zdV8PfJ^3Fo_=K@!qx!Acjd8$N=>y@)Ug)<8H;z0%R~Qut(k?DJCStWo-oTAXeiuCM ze!EkCgH*c14{*MbPr1H(z-KhC5$&|u+FiW&atYH3jwo!ic5=0Lh8gN!h#Duvfn!jl zFPcuC?0`HY{eP%&6|Wd)hC5ziQmnr1q0)?EW^iQu~Nuenui$ z@fv-u?Fm9jO6ah0B_1< z^%_c)kt%$(=)nF>G&+!mfdQ&J%kOV6HSODCt6+6?``=!=nqck%d lHTVzqY)?gpPc%OBv?+gN?1SO{{YtOn3@0p literal 0 HcmV?d00001 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 00000000..018c86b6 --- /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 00000000..3bdb01c5 --- /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(' ')", + "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 00000000..3bdb01c5 --- /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(' ')", + "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 00000000..e69de29b 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 00000000..a69a1fbb --- /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 00000000..702ddf33 --- /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 00000000..cb08def3 --- /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,)) From c3464850a012eb85a3c905b2522dabd6e4136e66 Mon Sep 17 00:00:00 2001 From: Nedhir Ebnou Date: Mon, 9 Dec 2024 10:01:13 +0100 Subject: [PATCH 4/4] fix: remove Pole Emploi from V1_CONNECTORS to resolve test_root_readme_uses_v2_connectors_when_available failure caused by name mismatch in main README --- manifest.json | 4 ++-- src/hrflow_connectors/__init__.py | 2 -- .../francetravail/mappings/format/create_jobs_in_hrflow.json | 2 +- .../francetravail/mappings/format/update_jobs_in_hrflow.json | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/manifest.json b/manifest.json index c7288ab3..f2585f2e 100644 --- a/manifest.json +++ b/manifest.json @@ -70244,7 +70244,7 @@ "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(' ')", + "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": [ @@ -72495,7 +72495,7 @@ "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(' ')", + "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": [ diff --git a/src/hrflow_connectors/__init__.py b/src/hrflow_connectors/__init__.py index ffcef030..a39fbb69 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/v2/connectors/francetravail/mappings/format/create_jobs_in_hrflow.json b/src/hrflow_connectors/v2/connectors/francetravail/mappings/format/create_jobs_in_hrflow.json index 3bdb01c5..9448d961 100644 --- 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 @@ -6,7 +6,7 @@ "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(' ')", + "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": [ 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 index 3bdb01c5..9448d961 100644 --- 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 @@ -6,7 +6,7 @@ "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(' ')", + "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": [