-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Base class for importing employees between fyle and bamboohr (#110)
* base import class between fyle and bamboohr * minor changes * comment resolved * Class implementing employee import from bamboo hr (#111) * Implementaion of sync method for fyle and bamboohr (#112) * Implementaion of sync method for fyle and bamboohr * sync employees method added to platform connector * implementation of sync fyle and bamboo hr * removing api_token * indent correction * comment resolved * minor bug fix * better code * Import sync department (#115) * Syncing Department from Bamboohr to Fyle * resolved commented code * better optimized code * comment resolved * Employee and Approver Import (#116) * Employee and Approver Import * bug fix and comment resolved
- Loading branch information
1 parent
7e636a8
commit 263c4e0
Showing
8 changed files
with
270 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
apps/fyle_hrms_mappings/migrations/0003_auto_20231221_1815.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Generated by Django 3.1.14 on 2023-12-21 18:15 | ||
|
||
from django.db import migrations | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
('orgs', '0004_auto_20230627_1133'), | ||
('fyle_hrms_mappings', '0002_auto_20231221_1515'), | ||
] | ||
|
||
operations = [ | ||
migrations.AlterUniqueTogether( | ||
name='destinationattribute', | ||
unique_together={('destination_id', 'attribute_type', 'org')}, | ||
), | ||
migrations.AlterUniqueTogether( | ||
name='expenseattribute', | ||
unique_together={('value', 'attribute_type', 'org')}, | ||
), | ||
migrations.AlterModelTable( | ||
name='destinationattribute', | ||
table='destination_attributes', | ||
), | ||
migrations.AlterModelTable( | ||
name='expenseattribute', | ||
table='expense_attributes', | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
from typing import Dict | ||
from apps.users.models import User | ||
from apps.fyle_hrms_mappings.models import DestinationAttribute | ||
from .base import FyleEmployeeImport | ||
from bamboosdk.bamboohrsdk import BambooHrSDK | ||
from apps.bamboohr.models import BambooHr | ||
|
||
|
||
class BambooHrEmployeeImport(FyleEmployeeImport): | ||
|
||
def __init__(self, org_id: int, user: User): | ||
super().__init__(org_id, user) | ||
bamboo_hr = BambooHr.objects.get(org_id__in=org_id) | ||
self.bamboohr_sdk = BambooHrSDK(api_token=bamboo_hr.api_token, sub_domain=bamboo_hr.sub_domain) | ||
|
||
def sync_hrms_employees(self): | ||
employees = self.bamboohr_sdk.employees.get_all() | ||
self.upsert_employees(employees) | ||
|
||
def upsert_employees(self, employees: Dict): | ||
attributes = [] | ||
for employee in employees['employees']: | ||
supervisor = [employee['supervisorEmail']] | ||
active_status = True if employee['status'] == 'Active' else False | ||
detail = { | ||
'email': employee['workEmail'] if employee['workEmail'] else None, | ||
'department_name': employee['department'] if employee['department'] else None, | ||
'full_name': employee['displayName'] if employee['displayName'] else None, | ||
'approver_emails': supervisor, | ||
} | ||
|
||
attributes.append({ | ||
'attribute_type': 'EMPLOYEE', | ||
'value': employee['displayName'], | ||
'destination_id': employee['id'], | ||
'detail': detail, | ||
'active': active_status | ||
}) | ||
|
||
DestinationAttribute.bulk_create_or_update_destination_attributes( | ||
attributes=attributes, attribute_type='EMPLOYEE', org_id=self.org_id, update=True) | ||
|
||
return [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
from typing import Dict, List | ||
from apps.fyle_hrms_mappings.models import DestinationAttribute, ExpenseAttribute | ||
from apps.orgs.models import Org | ||
from apps.users.helpers import PlatformConnector | ||
from fyle_rest_auth.models import AuthToken | ||
|
||
class FyleEmployeeImport(): | ||
|
||
def __init__(self, org_id: int, user): | ||
self.org_id = org_id | ||
self.user = user | ||
refresh_token = AuthToken.objects.get(user__user_id=self.user).refresh_token | ||
cluster_domain = Org.objects.get(user__user_id=self.user).cluster_domain | ||
self.platform_connection = PlatformConnector(refresh_token, cluster_domain) | ||
|
||
def sync_fyle_employees(self): | ||
self.platform_connection.sync_employees(org_id=self.org_id) | ||
|
||
def get_existing_departments_from_fyle(self): | ||
existing_departments: Dict = {} | ||
query_params={ | ||
'order': 'id.desc' | ||
} | ||
departments_generator = self.platform_connection.get_department_generator(query_params=query_params) | ||
for response in departments_generator: | ||
for department in response['data']: | ||
existing_departments[department['display_name']] = { | ||
'id': department['id'], | ||
'is_enabled': department['is_enabled'] | ||
} | ||
return existing_departments | ||
|
||
def create_fyle_department_payload(self, existing_departments, new_departments): | ||
departments_payload = [] | ||
|
||
for department in new_departments: | ||
if department in existing_departments.keys(): | ||
if not existing_departments[department]['is_enabled']: | ||
departments_payload.append({ | ||
'name': department, | ||
'id': existing_departments[department]['id'], | ||
'is_enabled': True, | ||
'display_name': department | ||
}) | ||
else: | ||
departments_payload.append({ | ||
'name': department, | ||
'display_name': department | ||
}) | ||
|
||
return departments_payload | ||
|
||
def departments_to_be_imported(self, hrms_employees): | ||
new_departments = [] | ||
|
||
for employee in hrms_employees: | ||
if employee.detail['department_name']: | ||
new_departments.append(employee.detail['department_name']) | ||
|
||
return list(set(new_departments)) | ||
|
||
def post_department(self, departments_payload): | ||
for department in departments_payload: | ||
self.platform_connection.post_department(department) | ||
|
||
def import_departments(self, hrms_employees): | ||
existing_departments = self.get_existing_departments_from_fyle() | ||
new_departments = self.departments_to_be_imported(hrms_employees) | ||
departments_payload = self.create_fyle_department_payload(existing_departments, new_departments) | ||
self.post_department(departments_payload) | ||
|
||
def get_employee_and_approver_payload(self, hrms_employees): | ||
employee_payload: List[Dict] = [] | ||
employee_emails: List[str] = [] | ||
approver_emails: List[str] = [] | ||
employee_approver_payload: List[Dict] = [] | ||
|
||
for employee in hrms_employees: | ||
if employee.detail['email']: | ||
update_create_employee_payload = { | ||
'user_email': employee.detail['email'], | ||
'user_full_name': employee.detail['full_name'], | ||
'code': employee.destination_id, | ||
'department_name': employee.detail['department_name'] if employee.detail['department_name'] else '', | ||
'is_enabled': employee.active | ||
} | ||
employee_payload.append(update_create_employee_payload) | ||
employee_emails.append(employee.detail['email']) | ||
|
||
if employee.detail['approver_emails']: | ||
employee_approver_payload.append({ | ||
'user_email': employee.detail['email'], | ||
'approver_emails': employee.detail['approver_emails'] | ||
}) | ||
approver_emails.extend(employee.detail['approver_emails']) | ||
|
||
existing_approver_emails = ExpenseAttribute.objects.filter( | ||
org_id=self.org_id, attribute_type='EMPLOYEE', value__in=approver_emails | ||
).values_list('value', flat=True) | ||
|
||
employee_approver_payload = list(filter( | ||
lambda employee_approver: set( | ||
employee_approver['approver_emails'] | ||
).issubset(employee_emails) or set( | ||
employee_approver['approver_emails'] | ||
).issubset(existing_approver_emails), | ||
employee_approver_payload | ||
)) | ||
|
||
return employee_payload, employee_approver_payload | ||
|
||
def fyle_employee_import(self, hrms_employees): | ||
fyle_employee_payload, employee_approver_payload = self.get_employee_and_approver_payload(hrms_employees) | ||
|
||
if fyle_employee_payload: | ||
self.platform_connection.bulk_post_employees(employees_payload=fyle_employee_payload) | ||
|
||
if employee_approver_payload: | ||
self.platform_connection.bulk_post_employees(employees_payload=employee_approver_payload) | ||
|
||
self.platform_connection.sync_employees(org_id=self.org_id) | ||
|
||
def sync_hrms_employees(self): | ||
raise NotImplementedError('Implement sync_hrms_employees() in the child class') | ||
|
||
def sync_employees(self): | ||
self.sync_fyle_employees() | ||
self.sync_hrms_employees() | ||
|
||
hrms_employees = DestinationAttribute.objects.filter( | ||
attribute_type='EMPLOYEE', | ||
org_id=self.org_id | ||
).order_by('value', 'id') | ||
|
||
self.import_departments(hrms_employees) | ||
self.fyle_employee_import(hrms_employees) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters