Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/update connector flatchr #125

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
661 changes: 661 additions & 0 deletions manifest.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/hrflow_connectors/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from hrflow_connectors.connectors.flatchr import Flatchr
from hrflow_connectors.connectors.smartrecruiters import SmartRecruiters
from hrflow_connectors.connectors.talentsoft import TalentSoft
from hrflow_connectors.core import backend
from hrflow_connectors.core.connector import hrflow_connectors_manifest # noqa
from hrflow_connectors.core.documentation import generate_docs # noqa

__version__ = "2.0.0"
__CONNECTORS__ = [SmartRecruiters, TalentSoft]
__CONNECTORS__ = [SmartRecruiters, TalentSoft, Flatchr]

# This makes sure that connector are in module namespace
# and that the automatic workflow code generation should work
Expand Down
73 changes: 73 additions & 0 deletions src/hrflow_connectors/connectors/flatchr/DOCUMENTATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# 📖 Summary
- [📖 Summary](#-summary)
- [📝 About flatchr](#-about-flatchr)
- [📊 Data Flow](#-data-flow)
- [🔌 Connector Actions](#-connector-actions)
- [🐍 Quick Start Examples](#-quick-start-examples)
- [🔗 Useful Links](#-useful-links)
- [🙏 Special Thanks](#-special-thanks)


# 📝 About Flatchr

Flatchr is a web-based Applicant Tracking System (ATS) and recruitment software. It is designed to help businesses and recruiters manage the recruitment process, from job posting and applicant tracking, to scheduling interviews and managing offers. It has features like candidate management, resume parser, job postings, sourcing, and more.



<p align="center">
<image src=https://user-images.githubusercontent.com/113343504/215117691-36605f2d-ddcf-48be-9d82-b4c660b1cc20.png
width=90% height=100% >
</p>

# 📊 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
![image](https://user-images.githubusercontent.com/113343504/215127248-6dc5dff3-f64e-4d50-a8ff-093077b45c32.png)


# 🔌 Connector Actions
<p align="center">


| Action | Description |
| ------- | -------- |
| [**Push profiles**](docs/push_profiles.md) | Retrieves profiles from a [HrFlow.ai](http://HrFlow.ai) Source and sends them to Flatchr ATS|

</p>


# 🐍 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 do this, execute the following steps in a new virtual environment:
```bash
pip hrflow-connectors
```


To browse the examples of actions corresponding to released versions of 🤗 this connector, you just need to import the module like this :

<p align="center">

```python
import logging
from hrflow_connectors import Flatchr
```

</p>

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 [Bullhorn](https://www.flatchr.io/) to learn more.
- ⚙️ API documentation : (https://developers.flatchr.io/docs/getting_started)
- 💻 [Connector code](https://github.com/Riminder/hrflow-connectors/tree/master/src/hrflow_connectors/connectors/flatchr) on our Github.


# 🙏 Special Thanks
- 💻 HrFlow.ai: [Arthur STIEVENARD](https://github.com/arhturstiev) - Software Engineer
- 💻 HrFlow.ai: [Limam VADHEL](https://github.com/limamvadhel) - Software Engineer
- 💻 HrFlow.ai: [Clement NEGRE](https://github.com/ClemNeg0) - Software Engineer
- 🤝 Flatchr: [Flatchr for the partnership and accessible documentation](https://flatchr.com/)
73 changes: 73 additions & 0 deletions src/hrflow_connectors/connectors/flatchr/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# 📖 Summary
- [📖 Summary](#-summary)
- [📝 About flatchr](#-about-flatchr)
- [📊 Data Flow](#-data-flow)
- [🔌 Connector Actions](#-connector-actions)
- [🐍 Quick Start Examples](#-quick-start-examples)
- [🔗 Useful Links](#-useful-links)
- [🙏 Special Thanks](#-special-thanks)


# 📝 About Flatchr

Flatchr is a web-based Applicant Tracking System (ATS) and recruitment software. It is designed to help businesses and recruiters manage the recruitment process, from job posting and applicant tracking, to scheduling interviews and managing offers. It has features like candidate management, resume parser, job postings, sourcing, and more.



<p align="center">
<image src=https://user-images.githubusercontent.com/113343504/215117691-36605f2d-ddcf-48be-9d82-b4c660b1cc20.png
width=90% height=100% >
</p>

# 📊 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
![image](https://user-images.githubusercontent.com/113343504/215127248-6dc5dff3-f64e-4d50-a8ff-093077b45c32.png)


# 🔌 Connector Actions
<p align="center">


| Action | Description |
| ------- | -------- |
| [**Push profiles**](docs/push_profiles.md) | Retrieves profiles from a [HrFlow.ai](http://HrFlow.ai) Source and sends them to Flatchr ATS|

</p>


# 🐍 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 do this, execute the following steps in a new virtual environment:
```bash
pip hrflow-connectors
```


To browse the examples of actions corresponding to released versions of 🤗 this connector, you just need to import the module like this :

<p align="center">

```python
import logging
from hrflow_connectors import Flatchr
```

</p>

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 [Bullhorn](https://www.flatchr.io/) to learn more.
- ⚙️ API documentation : (https://developers.flatchr.io/docs/getting_started)
- 💻 [Connector code](https://github.com/Riminder/hrflow-connectors/tree/master/src/hrflow_connectors/connectors/flatchr) on our Github.


# 🙏 Special Thanks
- 💻 HrFlow.ai: [Arthur STIEVENARD](https://github.com/arhturstiev) - Software Engineer
- 💻 HrFlow.ai: [Limam VADHEL](https://github.com/limamvadhel) - Software Engineer
- 💻 HrFlow.ai: [Clement NEGRE](https://github.com/ClemNeg0) - Software Engineer
- 🤝 Flatchr: [Flatchr for the partnership and accessible documentation](https://flatchr.com/)
1 change: 1 addition & 0 deletions src/hrflow_connectors/connectors/flatchr/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from hrflow_connectors.connectors.flatchr.connector import Flatchr # noqa
233 changes: 233 additions & 0 deletions src/hrflow_connectors/connectors/flatchr/connector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
import base64
import typing as t

import requests

from hrflow_connectors.connectors.flatchr.warehouse import FlatchrProfileWarehouse
from hrflow_connectors.connectors.hrflow.warehouse import HrFlowProfileWarehouse
from hrflow_connectors.core import (
BaseActionParameters,
Connector,
ConnectorAction,
WorkflowType,
)


def get_candidate_attachments(hrflow_profile: t.Dict) -> t.Dict:
attachments_list = hrflow_profile.get("attachments")
# We try to find 'resume' (which is 'original' after traitments).
# If we don't find it, we search 'original'.
fall_backs = ["resume", "original"]

for file_name in fall_backs:
for attachment in attachments_list:
if attachment["file_name"] == file_name:
# Get the base64's resume from its AWS url.
url = attachment["public_url"]
response = requests.get(url)
b64 = base64.b64encode(response.content)
return b64.decode()
return None


def get_education_list(hrflow_profile: t.Dict) -> t.Dict:
hrflow_education_list = hrflow_profile["educations"]
flatchr_education_list = []

for education in hrflow_education_list:
location = education.get("location")
flatchr_education = {
"institution": {
"communication": {
"address": [
{"formattedAddress": location.get("text") if location else None}
]
},
"name": education.get("school"),
},
"educationLevelCodes": [{"name": education.get("title")}],
"educationDegrees": [
{
"name": education.get("title"),
"date": education.get("date_start"),
"specializations": [],
}
],
"end": education.get("date_end"),
"descriptions": [education.get("description")],
}
flatchr_education_list.append(flatchr_education)
return flatchr_education_list


def get_experiences_list(hrflow_profile: t.Dict) -> t.Dict:
hrflow_experiences_list = hrflow_profile["experiences"]
flatchr_experiences_list = []

for experience in hrflow_experiences_list:
location = experience.get("location")
flatchr_education = {
"title": experience.get("title"),
"positionHistories": [
{
"organization": {
"communication": {
"address": [
{
"countryCode": None,
"city": None,
"postalCode": None,
"geoLocation": {
"latitude": location.get("lat"),
"longitude": location.get("lng"),
},
"formattedAddress": location.get("text")
if location
else None,
}
]
},
"name": experience.get("company"),
},
"jobCategories": [],
"jobLevels": [],
"start": experience.get("date_start"),
"current": None,
}
],
"start": experience.get("date_start"),
"current": None,
"descriptions": [experience.get("description")],
}
flatchr_experiences_list.append(flatchr_education)
return flatchr_experiences_list


def get_name() -> t.Dict:
name = {
"formattedName": "Undefined",
"given": "Undefined",
"family": "Undefined",
}
return name


def get_phone(hrflow_profile: t.Dict) -> t.Dict:
info = hrflow_profile.get("info")
phone = [{"dialNumber": info.get("phone") if info else "XXXXX", "useCode": None}]
return phone


def get_email(hrflow_profile: t.Dict) -> t.Dict:
info = hrflow_profile.get("info")

email = [{"address": info.get("email") if info else None}]
return email


def get_position(hrflow_profile: t.Dict) -> t.Dict:
hrflow_experiences_list = hrflow_profile["experiences"]
position = []

for experience in hrflow_experiences_list:
if experience.get("title") is not None and experience.get("title") != "":
position.append(experience.get("title"))

return position


def get_employment_positions(hrflow_profile: t.Dict) -> t.Dict:
hrflow_experiences_list = hrflow_profile["experiences"]
employment_positions = []

for experience in hrflow_experiences_list:
if experience.get("company") is not None and experience.get("company") != "":
employment_positions.append(experience.get("company"))

return employment_positions


def format_profile(hrflow_profile: t.Dict) -> t.Dict:

# CREATE PROFILE
data = hrflow_profile

info = data.get("info")
email = info.get("email") if info else None
if email is None:
reference = data.get("reference")
raise Exception(f"No email for hrflow_profile {reference} but one is mandatory")

create_profile_body = {
"vacancy": None,
"firstname": info.get("first_name")
if info.get("first_name") is not None
else "N/A",
"lastname": info.get("last_name")
if info.get("last_name") is not None
else "N/A",
"type": "document",
"email": email,
"resume": {
"fileName": "resume.pdf",
"contentType": "application/octet-stream",
"data": get_candidate_attachments(data),
},
}

# ENRICH PROFILE

value = {
"address": {
"administrative_area_level_1": data["info"]["location"].get("text"),
"location_lat": data["info"]["location"].get("lat"),
"location_lng": data["info"]["location"].get("lng"),
},
"education": get_education_list(data),
"employment": get_experiences_list(data),
"name": get_name(),
"phone": get_phone(data),
"email": get_email(data),
"position": get_position(data),
"employment_positions": get_employment_positions(data),
"experience": int(data.get("experiences_duration")),
}

enrich_profile_body = {
"app_name": "HRMatch",
"reference": data["info"].get("email"),
"name": "parsing",
"type": "applicants",
"value": value,
}
# When the action needs to send several requests to push a profile
# We group the formats of the different requests in a `profile_body_dict`.
profile_body_dict = dict(
create_profile_body=create_profile_body,
enrich_profile_body=enrich_profile_body,
)
return profile_body_dict


DESCRIPTION = (
"Avec le digital, recruter est devenu beaucoup plus compliqué qu'avant."
" Flatchr centralise et simplifie vos processus de recrutement pour le rendre aussi"
" simple que télécharger un film sur Netflix."
)
Flatchr = Connector(
name="Flatchr",
description=DESCRIPTION,
url="https://www.flatchr.io/",
actions=[
ConnectorAction(
name="push_profile",
trigger_type=WorkflowType.catch,
description="Writes profile from Hrflow.ai Source to Flatchr",
parameters=BaseActionParameters.with_defaults(
"WriteProfileActionParameters", format=format_profile
),
origin=HrFlowProfileWarehouse,
target=FlatchrProfileWarehouse,
),
],
)
Loading