brynq-sdk-bob 1.1.2__tar.gz → 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/PKG-INFO +1 -1
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/brynq_sdk_bob/__init__.py +10 -17
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/brynq_sdk_bob/bank.py +3 -3
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/brynq_sdk_bob/company.py +1 -1
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/brynq_sdk_bob/custom_tables.py +7 -7
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/brynq_sdk_bob/employment.py +3 -3
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/brynq_sdk_bob/named_lists.py +5 -5
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/brynq_sdk_bob/payments.py +2 -2
- brynq_sdk_bob-2.2.0/brynq_sdk_bob/people.py +82 -0
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/brynq_sdk_bob/salaries.py +2 -2
- brynq_sdk_bob-2.2.0/brynq_sdk_bob/schemas/bank.py +24 -0
- brynq_sdk_bob-2.2.0/brynq_sdk_bob/schemas/custom_tables.py +11 -0
- brynq_sdk_bob-2.2.0/brynq_sdk_bob/schemas/employment.py +31 -0
- brynq_sdk_bob-2.2.0/brynq_sdk_bob/schemas/named_lists.py +14 -0
- brynq_sdk_bob-2.2.0/brynq_sdk_bob/schemas/payments.py +31 -0
- brynq_sdk_bob-2.2.0/brynq_sdk_bob/schemas/people.py +99 -0
- brynq_sdk_bob-2.2.0/brynq_sdk_bob/schemas/salary.py +25 -0
- brynq_sdk_bob-2.2.0/brynq_sdk_bob/schemas/timeoff.py +29 -0
- brynq_sdk_bob-2.2.0/brynq_sdk_bob/schemas/work.py +33 -0
- brynq_sdk_bob-2.2.0/brynq_sdk_bob/timeoff.py +51 -0
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/brynq_sdk_bob/work.py +3 -4
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/brynq_sdk_bob.egg-info/PKG-INFO +1 -1
- brynq_sdk_bob-2.2.0/brynq_sdk_bob.egg-info/requires.txt +2 -0
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/setup.py +2 -2
- brynq_sdk_bob-1.1.2/brynq_sdk_bob/people.py +0 -62
- brynq_sdk_bob-1.1.2/brynq_sdk_bob/schemas/bank.py +0 -20
- brynq_sdk_bob-1.1.2/brynq_sdk_bob/schemas/custom_tables.py +0 -10
- brynq_sdk_bob-1.1.2/brynq_sdk_bob/schemas/employment.py +0 -28
- brynq_sdk_bob-1.1.2/brynq_sdk_bob/schemas/named_lists.py +0 -13
- brynq_sdk_bob-1.1.2/brynq_sdk_bob/schemas/payments.py +0 -30
- brynq_sdk_bob-1.1.2/brynq_sdk_bob/schemas/people.py +0 -87
- brynq_sdk_bob-1.1.2/brynq_sdk_bob/schemas/salary.py +0 -21
- brynq_sdk_bob-1.1.2/brynq_sdk_bob/schemas/timeoff.py +0 -28
- brynq_sdk_bob-1.1.2/brynq_sdk_bob/schemas/work.py +0 -29
- brynq_sdk_bob-1.1.2/brynq_sdk_bob/timeoff.py +0 -26
- brynq_sdk_bob-1.1.2/brynq_sdk_bob.egg-info/requires.txt +0 -2
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/brynq_sdk_bob/documents.py +0 -0
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/brynq_sdk_bob/schemas/__init__.py +0 -0
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/brynq_sdk_bob.egg-info/SOURCES.txt +0 -0
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/brynq_sdk_bob.egg-info/dependency_links.txt +0 -0
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/brynq_sdk_bob.egg-info/not-zip-safe +0 -0
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/brynq_sdk_bob.egg-info/top_level.txt +0 -0
- {brynq_sdk_bob-1.1.2 → brynq_sdk_bob-2.2.0}/setup.cfg +0 -0
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import base64
|
|
2
2
|
import re
|
|
3
|
-
from typing import Union, List
|
|
3
|
+
from typing import Union, List, Optional, Literal
|
|
4
4
|
import pandas as pd
|
|
5
5
|
import requests
|
|
6
|
+
import os
|
|
6
7
|
from brynq_sdk_brynq import BrynQ
|
|
8
|
+
from brynq_sdk_functions import Functions
|
|
7
9
|
from .bank import Bank
|
|
8
10
|
from .company import Company
|
|
9
11
|
from .documents import CustomDocuments
|
|
@@ -16,10 +18,10 @@ from .timeoff import TimeOff
|
|
|
16
18
|
from .work import Work
|
|
17
19
|
|
|
18
20
|
class Bob(BrynQ):
|
|
19
|
-
def __init__(self,
|
|
21
|
+
def __init__(self, system_type: Optional[Literal['source', 'target']] = None, test_environment: bool = True, debug: bool = False, target_system: str = None):
|
|
20
22
|
super().__init__()
|
|
21
23
|
self.timeout = 3600
|
|
22
|
-
self.headers = self._get_request_headers(
|
|
24
|
+
self.headers = self._get_request_headers(system_type)
|
|
23
25
|
if test_environment:
|
|
24
26
|
self.base_url = "https://api.sandbox.hibob.com/v1/"
|
|
25
27
|
else:
|
|
@@ -36,10 +38,12 @@ class Bob(BrynQ):
|
|
|
36
38
|
self.documents = CustomDocuments(self)
|
|
37
39
|
self.companies = Company(self)
|
|
38
40
|
self.named_lists = NamedLists(self)
|
|
41
|
+
self.data_interface_id = os.getenv("DATA_INTERFACE_ID")
|
|
42
|
+
self.debug = debug
|
|
39
43
|
|
|
40
|
-
def _get_request_headers(self,
|
|
41
|
-
credentials = self.
|
|
42
|
-
auth_token = base64.b64encode(f"{credentials
|
|
44
|
+
def _get_request_headers(self, system_type):
|
|
45
|
+
credentials = self.interfaces.credentials.get(system='bob', system_type=system_type)
|
|
46
|
+
auth_token = base64.b64encode(f"{credentials.get('data').get('User ID')}:{credentials.get('data').get('API Token')}".encode()).decode('utf-8')
|
|
43
47
|
headers = {
|
|
44
48
|
"accept": "application/json",
|
|
45
49
|
"Authorization": f"Basic {auth_token}",
|
|
@@ -65,14 +69,3 @@ class Bob(BrynQ):
|
|
|
65
69
|
request.params.update({"cursor": next_cursor})
|
|
66
70
|
|
|
67
71
|
return result_data
|
|
68
|
-
|
|
69
|
-
def rename_camel_columns_to_snake_case(self, df: pd.DataFrame) -> pd.DataFrame:
|
|
70
|
-
def camel_to_snake_case(column):
|
|
71
|
-
# Replace periods with underscores
|
|
72
|
-
column = column.replace('.', '_')
|
|
73
|
-
# Insert underscores before capital letters and convert to lowercase
|
|
74
|
-
return re.sub(r'(?<!^)(?=[A-Z])', '_', column).lower()
|
|
75
|
-
|
|
76
|
-
df.columns = map(camel_to_snake_case, df.columns)
|
|
77
|
-
|
|
78
|
-
return df
|
|
@@ -6,8 +6,9 @@ from .schemas.bank import BankSchema
|
|
|
6
6
|
class Bank:
|
|
7
7
|
def __init__(self, bob):
|
|
8
8
|
self.bob = bob
|
|
9
|
+
self.schema = BankSchema
|
|
9
10
|
|
|
10
|
-
def get(self, person_ids: pd.Series) -> (pd.DataFrame, pd.DataFrame):
|
|
11
|
+
def get(self, person_ids: pd.Series, field_selection: list[str] = []) -> (pd.DataFrame, pd.DataFrame):
|
|
11
12
|
data = []
|
|
12
13
|
for person_id in person_ids:
|
|
13
14
|
resp = self.bob.session.get(url=f"{self.bob.base_url}people/{person_id}/bank-accounts", timeout=self.bob.timeout)
|
|
@@ -19,8 +20,7 @@ class Bank:
|
|
|
19
20
|
data += temp_data
|
|
20
21
|
|
|
21
22
|
df = pd.DataFrame(data)
|
|
22
|
-
df = self.bob.rename_camel_columns_to_snake_case(df)
|
|
23
23
|
|
|
24
24
|
valid_banks, invalid_banks = Functions.validate_data(df=df, schema=BankSchema, debug=True)
|
|
25
25
|
|
|
26
|
-
return valid_banks, invalid_banks
|
|
26
|
+
return valid_banks, invalid_banks
|
|
@@ -7,30 +7,30 @@ from .schemas.custom_tables import CustomTableSchema
|
|
|
7
7
|
class CustomTables:
|
|
8
8
|
def __init__(self, bob):
|
|
9
9
|
self.bob = bob
|
|
10
|
+
self.schema = CustomTableSchema
|
|
10
11
|
|
|
11
12
|
def get(self, employee_id: str, custom_table_id: str) -> (pd.DataFrame, pd.DataFrame):
|
|
12
13
|
"""
|
|
13
14
|
Get custom table data for an employee
|
|
14
|
-
|
|
15
|
+
|
|
15
16
|
Args:
|
|
16
17
|
employee_id: The employee ID
|
|
17
18
|
custom_table_id: The custom table ID
|
|
18
|
-
|
|
19
|
+
|
|
19
20
|
Returns:
|
|
20
21
|
A tuple of (valid_data, invalid_data) as pandas DataFrames
|
|
21
22
|
"""
|
|
22
23
|
resp = self.bob.session.get(url=f"{self.bob.base_url}people/custom-tables/{employee_id}/{custom_table_id}")
|
|
23
24
|
resp.raise_for_status()
|
|
24
25
|
data = resp.json()
|
|
25
|
-
|
|
26
|
+
|
|
26
27
|
# Normalize the nested JSON response
|
|
27
28
|
df = pd.json_normalize(
|
|
28
29
|
data,
|
|
29
30
|
record_path=['values']
|
|
30
31
|
)
|
|
31
|
-
|
|
32
|
+
|
|
32
33
|
df['employee_id'] = employee_id
|
|
33
|
-
|
|
34
|
-
valid_data, invalid_data = Functions.validate_data(df=df, schema=CustomTableSchema, debug=True)
|
|
34
|
+
valid_data, invalid_data = Functions.validate_data(df=df, schema=self.schema, debug=True)
|
|
35
35
|
|
|
36
|
-
return valid_data, invalid_data
|
|
36
|
+
return valid_data, invalid_data
|
|
@@ -7,6 +7,7 @@ from brynq_sdk_functions import Functions
|
|
|
7
7
|
class Employment:
|
|
8
8
|
def __init__(self, bob):
|
|
9
9
|
self.bob = bob
|
|
10
|
+
self.schema = EmploymentSchema
|
|
10
11
|
|
|
11
12
|
def get(self) -> (pd.DataFrame, pd.DataFrame):
|
|
12
13
|
request = requests.Request(method='GET',
|
|
@@ -17,7 +18,6 @@ class Employment:
|
|
|
17
18
|
record_path='values',
|
|
18
19
|
meta=['employeeId']
|
|
19
20
|
)
|
|
20
|
-
|
|
21
|
-
valid_contracts, invalid_contracts = Functions.validate_data(df=df, schema=EmploymentSchema, debug=True)
|
|
21
|
+
valid_contracts, invalid_contracts = Functions.validate_data(df=df, schema=self.schema, debug=True)
|
|
22
22
|
|
|
23
|
-
return valid_contracts, invalid_contracts
|
|
23
|
+
return valid_contracts, invalid_contracts
|
|
@@ -7,14 +7,15 @@ from .schemas.named_lists import NamedListSchema
|
|
|
7
7
|
class NamedLists:
|
|
8
8
|
def __init__(self, bob):
|
|
9
9
|
self.bob = bob
|
|
10
|
+
self.schema = NamedListSchema
|
|
10
11
|
|
|
11
12
|
def get(self) -> (pd.DataFrame, pd.DataFrame):
|
|
12
13
|
"""
|
|
13
14
|
Get custom table data for an employee
|
|
14
|
-
|
|
15
|
+
|
|
15
16
|
Args:
|
|
16
17
|
list_name: The list name
|
|
17
|
-
|
|
18
|
+
|
|
18
19
|
Returns:
|
|
19
20
|
A tuple of (valid_data, invalid_data) as pandas DataFrames
|
|
20
21
|
"""
|
|
@@ -28,10 +29,9 @@ class NamedLists:
|
|
|
28
29
|
for key, group in data.items()
|
|
29
30
|
for item in group["values"]
|
|
30
31
|
])
|
|
31
|
-
|
|
32
|
+
|
|
32
33
|
# Normalize the nested JSON response
|
|
33
34
|
# df = pd.DataFrame(data.get('values'))
|
|
34
|
-
df = self.bob.rename_camel_columns_to_snake_case(df)
|
|
35
35
|
valid_data, invalid_data = Functions.validate_data(df=df, schema=NamedListSchema, debug=True)
|
|
36
36
|
|
|
37
|
-
return valid_data, invalid_data
|
|
37
|
+
return valid_data, invalid_data
|
|
@@ -7,6 +7,7 @@ from .schemas.payments import VariablePaymentSchema
|
|
|
7
7
|
class Payments:
|
|
8
8
|
def __init__(self, bob):
|
|
9
9
|
self.bob = bob
|
|
10
|
+
self.schema = VariablePaymentSchema
|
|
10
11
|
|
|
11
12
|
def get(self, person_id: str) -> (pd.DataFrame, pd.DataFrame):
|
|
12
13
|
resp = self.bob.session.get(url=f"{self.bob.base_url}people/{person_id}/variable", timeout=self.bob.timeout)
|
|
@@ -17,7 +18,6 @@ class Payments:
|
|
|
17
18
|
record_path='values'
|
|
18
19
|
)
|
|
19
20
|
df['employee_id'] = person_id
|
|
20
|
-
|
|
21
|
-
valid_payments, invalid_payments = Functions.validate_data(df=df, schema=VariablePaymentSchema, debug=True)
|
|
21
|
+
valid_payments, invalid_payments = Functions.validate_data(df=df, schema=self.schema, debug=True)
|
|
22
22
|
|
|
23
23
|
return valid_payments, invalid_payments
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
from brynq_sdk_functions import Functions
|
|
3
|
+
from .bank import Bank
|
|
4
|
+
from .employment import Employment
|
|
5
|
+
from .salaries import Salaries
|
|
6
|
+
from .schemas.people import PeopleSchema
|
|
7
|
+
from .work import Work
|
|
8
|
+
from .custom_tables import CustomTables
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class People:
|
|
12
|
+
def __init__(self, bob):
|
|
13
|
+
self.bob = bob
|
|
14
|
+
self.salaries = Salaries(bob)
|
|
15
|
+
self.employment = Employment(bob)
|
|
16
|
+
self.bank = Bank(bob)
|
|
17
|
+
self.work = Work(bob)
|
|
18
|
+
self.custom_tables = CustomTables(bob)
|
|
19
|
+
self.schema = PeopleSchema
|
|
20
|
+
self.field_name_in_body, self.field_name_in_response, self.endpoint_to_response = self._init_fields()
|
|
21
|
+
|
|
22
|
+
def get(self, additional_fields: list[str] = [], field_selection: list[str] = []) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
23
|
+
"""
|
|
24
|
+
Get people from Bob
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
additional_fields (list[str]): Additional fields to get (not defined in the schema)
|
|
28
|
+
field_selection (list[str]): Fields to get (defined in the schema), if not provided, all fields are returned
|
|
29
|
+
"""
|
|
30
|
+
#resp = self.bob.session.get(url=f"{self.bob.base_url}profiles", timeout=self.bob.timeout)
|
|
31
|
+
body_fields = list(set(self.field_name_in_body + additional_fields))
|
|
32
|
+
response_fields = list(set(self.field_name_in_response + additional_fields))
|
|
33
|
+
|
|
34
|
+
if field_selection:
|
|
35
|
+
body_fields = [field for field in body_fields if field in field_selection]
|
|
36
|
+
response_fields = [self.endpoint_to_response.get(field) for field in field_selection if field in self.endpoint_to_response]
|
|
37
|
+
|
|
38
|
+
# Bob sucks with default fields so you need to do a search call to retrieve additional fields.
|
|
39
|
+
resp_additional_fields = self.bob.session.post(url=f"{self.bob.base_url}people/search",
|
|
40
|
+
json={
|
|
41
|
+
"fields": body_fields,
|
|
42
|
+
"filters": []
|
|
43
|
+
},
|
|
44
|
+
timeout=self.bob.timeout)
|
|
45
|
+
json_response = resp_additional_fields.json()
|
|
46
|
+
df = pd.json_normalize(resp_additional_fields.json()['employees'])
|
|
47
|
+
df = df[[col for col in response_fields if col in df.columns]]
|
|
48
|
+
# Get the valid column names from PeopleSchema
|
|
49
|
+
valid_people, invalid_people = Functions.validate_data(df=df, schema=PeopleSchema, debug=True)
|
|
50
|
+
return valid_people, invalid_people
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _init_fields(self) -> tuple[list[str], list[str], dict[str, str]]:
|
|
54
|
+
resp_fields = self.bob.session.get(
|
|
55
|
+
url=f"{self.bob.base_url}company/people/fields",
|
|
56
|
+
timeout=self.bob.timeout,
|
|
57
|
+
headers=self.bob.headers
|
|
58
|
+
)
|
|
59
|
+
fields = resp_fields.json()
|
|
60
|
+
field_name_in_body = [field.get('id') for field in fields]
|
|
61
|
+
field_name_in_response = [field['jsonPath'] for field in fields]
|
|
62
|
+
endpoint_to_response = {field['id']: field['jsonPath'] for field in fields}
|
|
63
|
+
return field_name_in_body, field_name_in_response, endpoint_to_response
|
|
64
|
+
|
|
65
|
+
def _get_employee_id_to_person_id_mapping(self) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
66
|
+
employee_id_in_company = "work.employeeIdInCompany"
|
|
67
|
+
person_id = "root.id"
|
|
68
|
+
|
|
69
|
+
body_fields = [employee_id_in_company, person_id]
|
|
70
|
+
response_fields = [self.endpoint_to_response.get(field) for field in body_fields if field in self.endpoint_to_response]
|
|
71
|
+
|
|
72
|
+
resp_additional_fields = self.bob.session.post(url=f"{self.bob.base_url}people/search",
|
|
73
|
+
json={
|
|
74
|
+
"fields": body_fields,
|
|
75
|
+
"filters": []
|
|
76
|
+
},
|
|
77
|
+
timeout=self.bob.timeout)
|
|
78
|
+
df = pd.json_normalize(resp_additional_fields.json()['employees'])
|
|
79
|
+
df = df[[col for col in response_fields if col in df.columns]]
|
|
80
|
+
# Get the valid column names from PeopleSchema
|
|
81
|
+
valid_people, invalid_people = Functions.validate_data(df=df, schema=PeopleSchema, debug=True)
|
|
82
|
+
return valid_people, invalid_people
|
|
@@ -7,6 +7,7 @@ from .schemas.salary import SalarySchema
|
|
|
7
7
|
class Salaries:
|
|
8
8
|
def __init__(self, bob):
|
|
9
9
|
self.bob = bob
|
|
10
|
+
self.schema = SalarySchema
|
|
10
11
|
|
|
11
12
|
def get(self) -> (pd.DataFrame, pd.DataFrame):
|
|
12
13
|
request = requests.Request(method='GET',
|
|
@@ -18,7 +19,6 @@ class Salaries:
|
|
|
18
19
|
record_path='values',
|
|
19
20
|
meta=['employeeId']
|
|
20
21
|
)
|
|
21
|
-
df = self.bob.rename_camel_columns_to_snake_case(df)
|
|
22
22
|
valid_salaries, invalid_salaries = Functions.validate_data(df=df, schema=SalarySchema, debug=True)
|
|
23
23
|
|
|
24
|
-
return valid_salaries, invalid_salaries
|
|
24
|
+
return valid_salaries, invalid_salaries
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import pandera as pa
|
|
2
|
+
from pandera.typing import Series, String
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BankSchema(BrynQPanderaDataFrameModel):
|
|
8
|
+
id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Bank ID", alias="id")
|
|
9
|
+
employee_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
10
|
+
amount: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Amount", alias="amount")
|
|
11
|
+
allocation: Series[String] = pa.Field(coerce=True, nullable=True, description="Allocation", alias="allocation")
|
|
12
|
+
branch_address: Series[String] = pa.Field(coerce=True, nullable=True, description="Branch Address", alias="branchAddress")
|
|
13
|
+
bank_name: Series[String] = pa.Field(coerce=True, nullable=True, description="Bank Name", alias="bankName")
|
|
14
|
+
account_number: Series[String] = pa.Field(coerce=True, nullable=True, description="Account Number", alias="accountNumber")
|
|
15
|
+
routing_number: Series[String] = pa.Field(coerce=True, nullable=True, description="Routing Number", alias="routingNumber")
|
|
16
|
+
bank_account_type: Series[String] = pa.Field(coerce=True, nullable=True, description="Bank Account Type", alias="bankAccountType")
|
|
17
|
+
bic_or_swift: Series[String] = pa.Field(coerce=True, nullable=True, description="BIC or SWIFT", alias="bicOrSwift")
|
|
18
|
+
changed_by: Series[String] = pa.Field(coerce=True, nullable=True, description="Changed By", alias="changedBy")
|
|
19
|
+
iban: Series[String] = pa.Field(coerce=True, description="IBAN", alias="iban")
|
|
20
|
+
account_nickname: Series[String] = pa.Field(coerce=True, nullable=True, description="Account Nickname", alias="accountNickname")
|
|
21
|
+
use_for_bonus: Series[pd.BooleanDtype] = pa.Field(coerce=True, nullable=True, description="Use for Bonus", alias="useForBonus")
|
|
22
|
+
|
|
23
|
+
class Config:
|
|
24
|
+
coerce = True
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import pandera as pa
|
|
2
|
+
from pandera.typing import Series
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
5
|
+
|
|
6
|
+
class CustomTableSchema(BrynQPanderaDataFrameModel):
|
|
7
|
+
id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Custom Table ID", alias="id")
|
|
8
|
+
employee_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
9
|
+
|
|
10
|
+
class Config:
|
|
11
|
+
coerce = True
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import pandera as pa
|
|
3
|
+
from pandera import Bool
|
|
4
|
+
from pandera.typing import Series, String, Float, DateTime
|
|
5
|
+
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
6
|
+
|
|
7
|
+
class EmploymentSchema(BrynQPanderaDataFrameModel):
|
|
8
|
+
id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Employment ID", alias="id")
|
|
9
|
+
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
10
|
+
active_effective_date: Series[DateTime] = pa.Field(coerce=True, description="Active Effective Date", alias="activeEffectiveDate")
|
|
11
|
+
contract: Series[String] = pa.Field(coerce=True, nullable=True, description="Contract", alias="contract") # has a list of possible values
|
|
12
|
+
creation_date: Series[DateTime] = pa.Field(coerce=True, nullable=True, description="Creation Date", alias="creationDate")
|
|
13
|
+
effective_date: Series[DateTime] = pa.Field(coerce=True, description="Effective Date", alias="effectiveDate")
|
|
14
|
+
end_effective_date: Series[DateTime] = pa.Field(coerce=True, nullable=True, description="End Effective Date", alias="endEffectiveDate")
|
|
15
|
+
fte: Series[Float] = pa.Field(coerce=True, description="FTE", alias="fte")
|
|
16
|
+
is_current: Series[Bool] = pa.Field(coerce=True, description="Is Current", alias="isCurrent")
|
|
17
|
+
modification_date: Series[DateTime] = pa.Field(coerce=True, nullable=True, description="Modification Date", alias="modificationDate")
|
|
18
|
+
salary_pay_type: Series[String] = pa.Field(coerce=True, nullable=True, description="Salary Pay Type", alias="salaryPayType")
|
|
19
|
+
weekly_hours: Series[Float] = pa.Field(coerce=True, nullable=True, description="Weekly Hours", alias="weeklyHours")
|
|
20
|
+
# weekly_hours_sort_factor: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=False)
|
|
21
|
+
actual_working_pattern_working_pattern_type: Series[pa.String] = pa.Field(nullable=True, description="Actual Working Pattern Working Pattern Type", alias="actualWorkingPattern.workingPatternType")
|
|
22
|
+
actual_working_pattern_days_sunday: Series[Float] = pa.Field(nullable=True, description="Actual Working Pattern Days Sunday", alias="actualWorkingPattern.days.sunday")
|
|
23
|
+
actual_working_pattern_days_tuesday: Series[Float] = pa.Field(nullable=True, description="Actual Working Pattern Days Tuesday", alias="actualWorkingPattern.days.tuesday")
|
|
24
|
+
actual_working_pattern_days_wednesday: Series[Float] = pa.Field(nullable=True, description="Actual Working Pattern Days Wednesday", alias="actualWorkingPattern.days.wednesday")
|
|
25
|
+
actual_working_pattern_days_monday: Series[Float] = pa.Field(nullable=True, description="Actual Working Pattern Days Monday", alias="actualWorkingPattern.days.monday")
|
|
26
|
+
actual_working_pattern_days_friday: Series[Float] = pa.Field(nullable=True, description="Actual Working Pattern Days Friday", alias="actualWorkingPattern.days.friday")
|
|
27
|
+
actual_working_pattern_days_thursday: Series[Float] = pa.Field(nullable=True, description="Actual Working Pattern Days Thursday", alias="actualWorkingPattern.days.thursday")
|
|
28
|
+
actual_working_pattern_days_saturday: Series[Float] = pa.Field(nullable=True, description="Actual Working Pattern Days Saturday", alias="actualWorkingPattern.days.saturday")
|
|
29
|
+
|
|
30
|
+
class Config:
|
|
31
|
+
coerce = True
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import pandera as pa
|
|
2
|
+
from pandera.typing import Series
|
|
3
|
+
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
4
|
+
|
|
5
|
+
class NamedListSchema(BrynQPanderaDataFrameModel):
|
|
6
|
+
id: Series[str] = pa.Field(coerce=True, description="Named List ID", alias="id")
|
|
7
|
+
value: Series[str] = pa.Field(coerce=True, description="Named List Value", alias="value")
|
|
8
|
+
name: Series[str] = pa.Field(coerce=True, description="Named List Name", alias="name")
|
|
9
|
+
archived: Series[bool] = pa.Field(coerce=True, description="Named List Archived", alias="archived")
|
|
10
|
+
# children: Series[list] = pa.Field(coerce=True)
|
|
11
|
+
type: Series[str] = pa.Field(coerce=True, description="Named List Type", alias="type")
|
|
12
|
+
|
|
13
|
+
class Config:
|
|
14
|
+
coerce = True
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import pandera as pa
|
|
2
|
+
from pandera.typing import Series, String, Float, DateTime
|
|
3
|
+
from typing import Optional
|
|
4
|
+
import pandas as pd
|
|
5
|
+
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
6
|
+
|
|
7
|
+
class VariablePaymentSchema(BrynQPanderaDataFrameModel):
|
|
8
|
+
can_be_deleted: Series[bool] = pa.Field(nullable=True, coerce=True, description="Can Be Deleted", alias="canBeDeleted")
|
|
9
|
+
department_percent: Series[Float] = pa.Field(nullable=True, coerce=True, description="Department Percent", alias="departmentPercent")
|
|
10
|
+
payout_type: Series[String] = pa.Field(coerce=True, description="Payout Type", alias="payoutType")
|
|
11
|
+
num_of_salaries: Optional[Series[pd.Int64Dtype]] = pa.Field(nullable=True, coerce=True, description="Number of Salaries", alias="numOfSalaries")
|
|
12
|
+
end_date: Series[DateTime] = pa.Field(nullable=True, coerce=True, description="End Date", alias="endDate")
|
|
13
|
+
creation_date: Series[DateTime] = pa.Field(coerce=True, description="Creation Date", alias="creationDate")
|
|
14
|
+
percentage_of_annual_salary: Series[Float] = pa.Field(nullable=True, coerce=True, description="Percentage of Annual Salary", alias="percentageOfAnnualSalary")
|
|
15
|
+
individual_percent: Series[Float] = pa.Field(nullable=True, coerce=True, description="Individual Percent", alias="individualPercent")
|
|
16
|
+
variable_type: Series[String] = pa.Field(nullable=True, coerce=True, description="Variable Type", alias="variableType")
|
|
17
|
+
is_current: Series[bool] = pa.Field(nullable=True, coerce=True, description="Is Current", alias="isCurrent")
|
|
18
|
+
modification_date: Series[DateTime] = pa.Field(nullable=True, coerce=True, description="Modification Date", alias="modificationDate")
|
|
19
|
+
company_percent: Series[Float] = pa.Field(nullable=True, coerce=True, description="Company Percent", alias="companyPercent")
|
|
20
|
+
id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="ID", alias="id")
|
|
21
|
+
end_effective_date: Series[DateTime] = pa.Field(nullable=True, coerce=True, description="End Effective Date", alias="endEffectiveDate")
|
|
22
|
+
payment_period: Series[String] = pa.Field(coerce=True, description="Payment Period", alias="paymentPeriod")
|
|
23
|
+
effective_date: Series[DateTime] = pa.Field(coerce=True, description="Effective Date", alias="effectiveDate")
|
|
24
|
+
amount_value: Series[Float] = pa.Field(coerce=True, description="Amount Value", alias="amount.value")
|
|
25
|
+
amount_currency: Series[String] = pa.Field(coerce=True, description="Amount Currency", alias="amount.currency")
|
|
26
|
+
change_reason: Series[String] = pa.Field(nullable=True, coerce=True, description="Change Reason", alias="change.reason")
|
|
27
|
+
change_changed_by: Series[String] = pa.Field(nullable=True, coerce=True, description="Change Changed By", alias="change.changedBy")
|
|
28
|
+
change_changed_by_id: Series[pd.Int64Dtype] = pa.Field(nullable=True, coerce=True, description="Change Changed By ID", alias="change.changedById")
|
|
29
|
+
employee_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Employee ID", alias="employeeId") #set manually
|
|
30
|
+
class Config:
|
|
31
|
+
coerce = True
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import pandera as pa
|
|
6
|
+
from pandera import Bool
|
|
7
|
+
from pandera.typing import Series, String, Float, DateTime
|
|
8
|
+
import pandera.extensions as extensions
|
|
9
|
+
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@extensions.register_check_method()
|
|
14
|
+
def check_list(x):
|
|
15
|
+
return isinstance(x, list)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class PeopleSchema(BrynQPanderaDataFrameModel):
|
|
19
|
+
id: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, description="Person ID", alias="id")
|
|
20
|
+
display_name: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Display Name", alias="displayName")
|
|
21
|
+
company_id: Optional[Series[String]] = pa.Field(coerce=True, description="Company ID", alias="companyId")
|
|
22
|
+
email: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Email", alias="email")
|
|
23
|
+
home_mobile_phone: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Personal Mobile Phone", alias="home.mobilePhone")
|
|
24
|
+
surname: Optional[Series[String]] = pa.Field(coerce=True, description="Surname", alias="surname")
|
|
25
|
+
first_name: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="First Name", alias="firstName")
|
|
26
|
+
full_name: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Full Name", alias="fullName")
|
|
27
|
+
personal_birth_date: Optional[Series[DateTime]] = pa.Field(coerce=True, nullable=True, description="Personal Birth Date", alias="personal.birthDate")
|
|
28
|
+
personal_pronouns: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Personal Pronouns", alias="personal.pronouns")
|
|
29
|
+
personal_honorific: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Personal Honorific", alias="personal.honorific")
|
|
30
|
+
personal_nationality: Optional[Series[object]] = pa.Field(coerce=True, check_name=check_list, description="Personal Nationality", alias="personal.nationality")
|
|
31
|
+
# employee_payroll_manager: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
32
|
+
# employee_hrbp: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
33
|
+
# employee_it_admin: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
34
|
+
# employee_buddy: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
35
|
+
employee_veteran_status: Optional[Series[object]] = pa.Field(coerce=True, check_name=check_list, description="Employee Veteran Status", alias="employee.veteranStatus")
|
|
36
|
+
employee_disability_status: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Employee Disability Status", alias="employee.disabilityStatus")
|
|
37
|
+
work_start_date: Optional[Series[DateTime]] = pa.Field(coerce=True, nullable=True, description="Work Start Date", alias="work.startDate")
|
|
38
|
+
work_manager: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Manager", alias="work.manager")
|
|
39
|
+
work_work_phone: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Work Phone", alias="work.workPhone")
|
|
40
|
+
work_tenure_duration_period_i_s_o: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Tenure Duration Period ISO", alias="work.tenureDurationPeriodIso")
|
|
41
|
+
work_tenure_duration_sort_factor: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=False, description="Work Tenure Duration Sort Factor", alias="work.tenureDurationSortFactor")
|
|
42
|
+
work_tenure_duration_humanize: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Tenure Duration Humanize", alias="work.tenureDurationHumanize")
|
|
43
|
+
work_duration_of_employment_period_i_s_o: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Duration of Employment Period ISO", alias="work.durationOfEmploymentPeriodIso")
|
|
44
|
+
work_duration_of_employment_sort_factor: Optional[Series[String]] = pa.Field(coerce=True, nullable=False, description="Work Duration of Employment Sort Factor", alias="work.durationOfEmploymentSortFactor")
|
|
45
|
+
work_duration_of_employment_humanize: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Duration of Employment Humanize", alias="work.durationOfEmploymentHumanize")
|
|
46
|
+
work_reports_to_id_in_company: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Work Reports to ID in Company", alias="work.reportsToIdInCompany")
|
|
47
|
+
work_employee_id_in_company: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Work Employee ID in Company", alias="work.employeeIdInCompany")
|
|
48
|
+
work_reports_to_display_name: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Reports to Display Name", alias="work.reportsToDisplayName")
|
|
49
|
+
work_reports_to_email: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Reports to Email", alias="work.reportsToEmail")
|
|
50
|
+
work_reports_to_surname: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Reports to Surname", alias="work.reportsToSurname")
|
|
51
|
+
work_reports_to_first_name: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Reports to First Name", alias="work.reportsToFirstName")
|
|
52
|
+
work_reports_to_id: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Work Reports to ID", alias="work.reportsToId")
|
|
53
|
+
work_work_mobile: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Work Mobile", alias="work.workMobile")
|
|
54
|
+
work_indirect_reports: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Work Indirect Reports", alias="work.indirectReports")
|
|
55
|
+
work_site_id: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Work Site ID", alias="work.siteId")
|
|
56
|
+
work_department: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Department", alias="work.department")
|
|
57
|
+
work_tenure_duration_years: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Work Tenure Duration Years", alias="work.tenureDurationYears")
|
|
58
|
+
work_tenure_years: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Work Tenure Years", alias="work.tenureYears")
|
|
59
|
+
work_is_manager: Optional[Series[Bool]] = pa.Field(coerce=True, nullable=True, description="Work Is Manager", alias="work.isManager")
|
|
60
|
+
work_title: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Title", alias="work.title")
|
|
61
|
+
work_site: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Site", alias="work.site")
|
|
62
|
+
work_original_start_date: Optional[Series[DateTime]] = pa.Field(coerce=True, nullable=True, description="Work Original Start Date", alias="work.originalStartDate")
|
|
63
|
+
work_active_effective_date: Optional[Series[DateTime]] = pa.Field(coerce=True, nullable=True, description="Work Active Effective Date", alias="work.activeEffectiveDate")
|
|
64
|
+
work_direct_reports: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Work Direct Reports", alias="work.directReports")
|
|
65
|
+
# work_work_change_type: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
66
|
+
work_second_level_manager: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Work Second Level Manager", alias="work.secondLevelManager")
|
|
67
|
+
work_days_of_previous_service: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Work Days of Previous Service", alias="work.daysOfPreviousService")
|
|
68
|
+
work_years_of_service: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Work Years of Service", alias="work.yearsOfService")
|
|
69
|
+
payroll_employment_contract: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Contract Type", alias="payroll.employment.contract")
|
|
70
|
+
payroll_employment_type: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Employment Type", alias="payroll.employment.type")
|
|
71
|
+
|
|
72
|
+
about_food_preferences: Optional[Series[object]] = pa.Field(coerce=True, check_name=check_list, description="About Food Preferences", alias="about.foodPreferences")
|
|
73
|
+
# about_social_data_linkedin: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
74
|
+
about_social_data_twitter: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="About Social Data Twitter", alias="about.socialDataTwitter")
|
|
75
|
+
about_social_data_facebook: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="About Social Data Facebook", alias="about.socialDataFacebook")
|
|
76
|
+
about_superpowers: Optional[Series[object]] = pa.Field(coerce=True, check_name=check_list, description="About Superpowers", alias="about.superpowers")
|
|
77
|
+
about_hobbies: Optional[Series[object]] = pa.Field(coerce=True, check_name=check_list, description="About Hobbies", alias="about.hobbies")
|
|
78
|
+
about_about: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="About About", alias="about.about")
|
|
79
|
+
about_avatar: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="About Avatar", alias="about.avatar")
|
|
80
|
+
address_city: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Address City", alias="address.city")
|
|
81
|
+
address_post_code: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Address Post Code", alias="address.postCode")
|
|
82
|
+
address_line1: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Address Line 1", alias="address.line1")
|
|
83
|
+
address_line2: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Address Line 2", alias="address.line2")
|
|
84
|
+
address_country: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Address Country", alias="address.country")
|
|
85
|
+
address_active_effective_date: Optional[Series[DateTime]] = pa.Field(coerce=True, nullable=True, description="Address Active Effective Date", alias="address.activeEffectiveDate")
|
|
86
|
+
home_legal_gender: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Legal Gender", alias="home.legalGender")
|
|
87
|
+
home_family_status: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Family / Marital Status", alias="home.familyStatus")
|
|
88
|
+
home_spouse_first_name: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Spouse First Name", alias="home.SpouseFirstName")
|
|
89
|
+
home_spouse_surname: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Spouse Surname", alias="home.SpouseSurname")
|
|
90
|
+
# home_spouse_birth_date: Series[DateTime] = pa.Field(coerce=True, nullable=True)
|
|
91
|
+
home_spouse_gender: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Spouse Gender", alias="home.SpouseGender")
|
|
92
|
+
identification_ssn_serial_number: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="SSN Serial Number", alias="identification.ssnSerialNumber")
|
|
93
|
+
internal_termination_reason: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Internal Termination Reason", alias="internal.terminationReason")
|
|
94
|
+
internal_termination_date: Optional[Series[DateTime]] = pa.Field(coerce=True, nullable=True, description="Internal Termination Date", alias="internal.terminationDate")
|
|
95
|
+
internal_termination_type: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Internal Termination Type", alias="internal.terminationType")
|
|
96
|
+
employee_last_day_of_work: Optional[Series[DateTime]] = pa.Field(coerce=True, nullable=True, description="Employee Last Day of Work", alias="employee.lastDayOfWork")
|
|
97
|
+
|
|
98
|
+
class Config:
|
|
99
|
+
coerce = True
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import pandera as pa
|
|
3
|
+
from pandera import Bool
|
|
4
|
+
from pandera.typing import Series, String, Float, DateTime
|
|
5
|
+
import pandera.extensions as extensions
|
|
6
|
+
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SalarySchema(BrynQPanderaDataFrameModel):
|
|
10
|
+
id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Salary ID", alias="id")
|
|
11
|
+
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
12
|
+
pay_frequency: Series[String] = pa.Field(coerce=True, nullable=True, description="Pay Frequency", alias="payFrequency") # has a list of possible values , isin=['Monthly']
|
|
13
|
+
creation_date: Series[DateTime] = pa.Field(coerce=True, nullable=True, description="Creation Date", alias="creationDate")
|
|
14
|
+
is_current: Series[Bool] = pa.Field(coerce=True, description="Is Current", alias="isCurrent")
|
|
15
|
+
modification_date: Series[DateTime] = pa.Field(coerce=True, nullable=True, description="Modification Date", alias="modificationDate")
|
|
16
|
+
effective_date: Series[DateTime] = pa.Field(coerce=True, description="Effective Date", alias="effectiveDate")
|
|
17
|
+
end_effective_date: Series[DateTime] = pa.Field(coerce=True, nullable=True, description="End Effective Date", alias="endEffectiveDate")
|
|
18
|
+
change_reason: Series[str] = pa.Field(coerce=True, nullable=True, description="Change Reason", alias="change.reason")
|
|
19
|
+
pay_period: Series[String] = pa.Field(coerce=True, nullable=True, description="Pay Period", alias="payPeriod")
|
|
20
|
+
base_value: Series[Float] = pa.Field(coerce=True, nullable=True, description="Base Value", alias="base.value") #needs to become base.value?
|
|
21
|
+
base_currency: Series[String] = pa.Field(coerce=True, nullable=True, description="Base Currency", alias="base.currency")
|
|
22
|
+
active_effective_date: Series[DateTime] = pa.Field(coerce=True, nullable=True, description="Active Effective Date", alias="activeEffectiveDate")
|
|
23
|
+
|
|
24
|
+
class Config:
|
|
25
|
+
coerce = True
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import pandera as pa
|
|
2
|
+
from pandera.typing import Series, String, Float
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
5
|
+
|
|
6
|
+
class TimeOffSchema(BrynQPanderaDataFrameModel):
|
|
7
|
+
change_type: Series[String] = pa.Field(coerce=True, description="Change Type", alias="changeType")
|
|
8
|
+
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
9
|
+
employee_display_name: Series[String] = pa.Field(coerce=True, description="Employee Display Name", alias="employeeDisplayName")
|
|
10
|
+
employee_email: Series[String] = pa.Field(coerce=True, description="Employee Email", alias="employeeEmail")
|
|
11
|
+
request_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Request ID", alias="requestId")
|
|
12
|
+
policy_type_display_name: Series[String] = pa.Field(coerce=True, description="Policy Type Display Name", alias="policyTypeDisplayName")
|
|
13
|
+
type: Series[String] = pa.Field(coerce=True, description="Type", alias="type")
|
|
14
|
+
start_date: Series[String] = pa.Field(coerce=True, description="Start Date", alias="startDate")
|
|
15
|
+
start_portion: Series[String] = pa.Field(coerce=True, description="Start Portion", alias="startPortion")
|
|
16
|
+
end_date: Series[String] = pa.Field(coerce=True, description="End Date", alias="endDate")
|
|
17
|
+
end_portion: Series[String] = pa.Field(coerce=True, description="End Portion", alias="endPortion")
|
|
18
|
+
day_portion: Series[String] = pa.Field(coerce=True, description="Day Portion", alias="dayPortion")
|
|
19
|
+
date: Series[String] = pa.Field(coerce=True, description="Date", alias="date")
|
|
20
|
+
hours_on_date: Series[Float] = pa.Field(coerce=True, description="Hours on Date", alias="hoursOnDate")
|
|
21
|
+
daily_hours: Series[Float] = pa.Field(coerce=True, description="Daily Hours", alias="dailyHours")
|
|
22
|
+
duration_unit: Series[String] = pa.Field(coerce=True, description="Duration Unit", alias="durationUnit")
|
|
23
|
+
total_duration: Series[Float] = pa.Field(coerce=True, description="Total Duration", alias="totalDuration")
|
|
24
|
+
total_cost: Series[Float] = pa.Field(coerce=True, description="Total Cost", alias="totalCost")
|
|
25
|
+
change_reason: Series[String] = pa.Field(nullable=True, coerce=True, description="Change Reason", alias="changeReason")
|
|
26
|
+
visibility: Series[String] = pa.Field(coerce=True, description="Visibility", alias="visibility")
|
|
27
|
+
|
|
28
|
+
class Config:
|
|
29
|
+
coerce = True
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import pandera as pa
|
|
2
|
+
from pandera.typing import Series
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
6
|
+
|
|
7
|
+
class WorkSchema(BrynQPanderaDataFrameModel):
|
|
8
|
+
can_be_deleted: Series[pa.Bool] = pa.Field(coerce=True, description="Can Be Deleted", alias="canBeDeleted")
|
|
9
|
+
work_change_type: Series[str] = pa.Field(coerce=True, description="Work Change Type", alias="workChangeType")
|
|
10
|
+
creation_date: Series[datetime] = pa.Field(coerce=True, nullable=True, description="Creation Date", alias="creationDate")
|
|
11
|
+
title: Series[str] = pa.Field(coerce=True, nullable=True, description="Title", alias="title")
|
|
12
|
+
is_current: Series[pa.Bool] = pa.Field(coerce=True, description="Is Current", alias="isCurrent")
|
|
13
|
+
modification_date: Series[datetime] = pa.Field(coerce=True, nullable=True, description="Modification Date", alias="modificationDate")
|
|
14
|
+
site: Series[str] = pa.Field(coerce=True, nullable=True, description="Site", alias="site")
|
|
15
|
+
site_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Site ID", alias="siteId")
|
|
16
|
+
id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="ID", alias="id")
|
|
17
|
+
end_effective_date: Series[datetime] = pa.Field(coerce=True, nullable=True, description="End Effective Date", alias="endEffectiveDate")
|
|
18
|
+
active_effective_date: Series[datetime] = pa.Field(coerce=True, nullable=True, description="Active Effective Date", alias="activeEffectiveDate")
|
|
19
|
+
department: Series[str] = pa.Field(coerce=True, nullable=True, description="Department", alias="department")
|
|
20
|
+
effective_date: Series[datetime] = pa.Field(coerce=True, nullable=True, description="Effective Date", alias="effectiveDate")
|
|
21
|
+
change_reason: Series[str] = pa.Field(coerce=True, nullable=True, description="Change Reason", alias="changeReason")
|
|
22
|
+
change_changed_by: Series[str] = pa.Field(coerce=True, nullable=True, description="Change Changed By", alias="changeChangedBy")
|
|
23
|
+
change_changed_by_id: Series[str] = pa.Field(coerce=True, nullable=True, description="Change Changed By ID", alias="changeChangedById")
|
|
24
|
+
reports_to_id: Series[str] = pa.Field(coerce=True, nullable=True, description="Reports To ID", alias="reportsToId")
|
|
25
|
+
reports_to_first_name: Series[str] = pa.Field(coerce=True, nullable=True, description="Reports To First Name", alias="reportsToFirstName")
|
|
26
|
+
reports_to_surname: Series[str] = pa.Field(coerce=True, nullable=True, description="Reports To Surname", alias="reportsToSurname")
|
|
27
|
+
reports_to_email: Series[str] = pa.Field(coerce=True, nullable=True, description="Reports To Email", alias="reportsToEmail")
|
|
28
|
+
reports_to_display_name: Series[str] = pa.Field(coerce=True, nullable=True, description="Reports To Display Name", alias="reportsToDisplayName")
|
|
29
|
+
reports_to: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=True, description="Reports To", alias="reportsTo")
|
|
30
|
+
employee_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
31
|
+
|
|
32
|
+
class Config:
|
|
33
|
+
coerce = True
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
from datetime import datetime, timezone, timedelta
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from brynq_sdk_functions import Functions
|
|
4
|
+
from .schemas.timeoff import TimeOffSchema
|
|
5
|
+
import warnings
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TimeOff:
|
|
9
|
+
def __init__(self, bob):
|
|
10
|
+
self.bob = bob
|
|
11
|
+
self.schema = TimeOffSchema
|
|
12
|
+
|
|
13
|
+
def get(self, since: datetime = None) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
14
|
+
"""
|
|
15
|
+
Get time off requests
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
since (datetime, optional): The start date of the time off requests max 6 months ago. Defaults to 6 months ago if not provided.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
tuple[pd.DataFrame, pd.DataFrame]: A tuple of (valid_timeoff, invalid_timeoff) as pandas DataFrames
|
|
22
|
+
"""
|
|
23
|
+
max_lookback = timedelta(days=int((365 / 2) - 1))
|
|
24
|
+
now_utc = datetime.now(timezone.utc)
|
|
25
|
+
six_months_ago = now_utc - max_lookback
|
|
26
|
+
#if since is provided, use it and cap to 6 months max
|
|
27
|
+
if since is not None:
|
|
28
|
+
if since.tzinfo is None:
|
|
29
|
+
since = since.replace(tzinfo=timezone.utc)
|
|
30
|
+
if since < six_months_ago:
|
|
31
|
+
warnings.warn("The 'since' date is more than 6 months ago. Limiting to 6 months ago due to API restrictions.")
|
|
32
|
+
since = six_months_ago
|
|
33
|
+
#if no since is provided, use 6 months ago
|
|
34
|
+
else:
|
|
35
|
+
since = six_months_ago
|
|
36
|
+
|
|
37
|
+
since = since.replace(tzinfo=timezone.utc).isoformat(timespec='milliseconds').replace('+00:00', 'Z')
|
|
38
|
+
resp = self.bob.session.get(url=f"{self.bob.base_url}timeoff/requests/changes",
|
|
39
|
+
params={'since': since},
|
|
40
|
+
timeout=self.bob.timeout)
|
|
41
|
+
resp.raise_for_status()
|
|
42
|
+
data = resp.json()['changes']
|
|
43
|
+
# data = self.bob.get_paginated_result(request)
|
|
44
|
+
df = pd.json_normalize(
|
|
45
|
+
data,
|
|
46
|
+
record_path='changes',
|
|
47
|
+
meta=['employeeId']
|
|
48
|
+
)
|
|
49
|
+
valid_timeoff, invalid_timeoff = Functions.validate_data(df=df, schema=self.schema, debug=True)
|
|
50
|
+
|
|
51
|
+
return valid_timeoff, invalid_timeoff
|
|
@@ -7,6 +7,7 @@ from .schemas.work import WorkSchema
|
|
|
7
7
|
class Work:
|
|
8
8
|
def __init__(self, bob):
|
|
9
9
|
self.bob = bob
|
|
10
|
+
self.schema = WorkSchema
|
|
10
11
|
|
|
11
12
|
def get(self) ->(pd.DataFrame, pd.DataFrame):
|
|
12
13
|
request = requests.Request(method='GET',
|
|
@@ -17,8 +18,6 @@ class Work:
|
|
|
17
18
|
record_path='values',
|
|
18
19
|
meta=['employeeId']
|
|
19
20
|
)
|
|
20
|
-
|
|
21
|
+
valid_work, invalid_work = Functions.validate_data(df=df, schema=self.schema, debug=True)
|
|
21
22
|
|
|
22
|
-
valid_work, invalid_work
|
|
23
|
-
|
|
24
|
-
return valid_work, invalid_work
|
|
23
|
+
return valid_work, invalid_work
|
|
@@ -2,7 +2,7 @@ from setuptools import setup, find_namespace_packages
|
|
|
2
2
|
|
|
3
3
|
setup(
|
|
4
4
|
name='brynq_sdk_bob',
|
|
5
|
-
version='
|
|
5
|
+
version='2.2.0',
|
|
6
6
|
description='Bob wrapper from BrynQ',
|
|
7
7
|
long_description='Bob wrapper from BrynQ',
|
|
8
8
|
author='BrynQ',
|
|
@@ -10,7 +10,7 @@ setup(
|
|
|
10
10
|
packages=find_namespace_packages(include=['brynq_sdk*']),
|
|
11
11
|
license='BrynQ License',
|
|
12
12
|
install_requires=[
|
|
13
|
-
'brynq-sdk-brynq>=
|
|
13
|
+
'brynq-sdk-brynq>=4,<5',
|
|
14
14
|
'pandas>=2.2.0,<3.0.0',
|
|
15
15
|
],
|
|
16
16
|
zip_safe=False,
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import pandas as pd
|
|
2
|
-
from brynq_sdk_functions import Functions
|
|
3
|
-
from .bank import Bank
|
|
4
|
-
from .employment import Employment
|
|
5
|
-
from .salaries import Salaries
|
|
6
|
-
from .schemas.people import PeopleSchema
|
|
7
|
-
from .work import Work
|
|
8
|
-
from .custom_tables import CustomTables
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class People:
|
|
12
|
-
def __init__(self, bob):
|
|
13
|
-
self.bob = bob
|
|
14
|
-
self.salaries = Salaries(bob)
|
|
15
|
-
self.employment = Employment(bob)
|
|
16
|
-
self.bank = Bank(bob)
|
|
17
|
-
self.work = Work(bob)
|
|
18
|
-
self.custom_tables = CustomTables(bob)
|
|
19
|
-
|
|
20
|
-
def get(self) -> pd.DataFrame:
|
|
21
|
-
resp = self.bob.session.get(url=f"{self.bob.base_url}profiles", timeout=self.bob.timeout)
|
|
22
|
-
# Bob sucks with default fields so you need to do a search call to retrieve additional fields.
|
|
23
|
-
additional_fields = [
|
|
24
|
-
"personal.birthDate",
|
|
25
|
-
"address.city",
|
|
26
|
-
"address.postCode",
|
|
27
|
-
"address.line1",
|
|
28
|
-
"address.line2",
|
|
29
|
-
"address.activeEffectiveDate",
|
|
30
|
-
"address.country",
|
|
31
|
-
# "home.legalGender",
|
|
32
|
-
"home.spouse.firstName",
|
|
33
|
-
"home.spouse.surname",
|
|
34
|
-
# "home.spouse.birthDate",
|
|
35
|
-
"home.spouse.gender",
|
|
36
|
-
"internal.terminationReason",
|
|
37
|
-
"internal.terminationDate",
|
|
38
|
-
"internal.terminationType",
|
|
39
|
-
"employee.lastDayOfWork",
|
|
40
|
-
# housenumber addition
|
|
41
|
-
"address.customColumns.column_1740046184782",
|
|
42
|
-
# contract end date (bob only fills this when you get a new contract normally)
|
|
43
|
-
"payroll.employment.customColumns.column_1680013460318",
|
|
44
|
-
# iban
|
|
45
|
-
"financial.iban"
|
|
46
|
-
# ploegentoeslag
|
|
47
|
-
]
|
|
48
|
-
resp_additional_fields = self.bob.session.post(url=f"{self.bob.base_url}people/search",
|
|
49
|
-
json={
|
|
50
|
-
"fields": ["root.id"] + additional_fields,
|
|
51
|
-
"filters": []
|
|
52
|
-
},
|
|
53
|
-
timeout=self.bob.timeout)
|
|
54
|
-
df_extra_fields = pd.json_normalize(resp_additional_fields.json()['employees'])
|
|
55
|
-
resp.raise_for_status()
|
|
56
|
-
data = resp.json()
|
|
57
|
-
df = pd.json_normalize(data['employees'])
|
|
58
|
-
df = pd.merge(df, df_extra_fields[["id"] + additional_fields], left_on='id', right_on='id')
|
|
59
|
-
df = self.bob.rename_camel_columns_to_snake_case(df)
|
|
60
|
-
valid_people, invalid_people = Functions.validate_data(df=df, schema=PeopleSchema, debug=True)
|
|
61
|
-
|
|
62
|
-
return valid_people, invalid_people
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import pandera as pa
|
|
2
|
-
from pandera.typing import Series, String
|
|
3
|
-
import pandas as pd
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class BankSchema(pa.DataFrameModel):
|
|
7
|
-
id: Series[pd.Int64Dtype] = pa.Field(coerce=True)
|
|
8
|
-
employee_id: Series[pd.Int64Dtype] = pa.Field(coerce=True)
|
|
9
|
-
amount: Series[pd.Int64Dtype] = pa.Field(coerce=True)
|
|
10
|
-
allocation: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
11
|
-
branch_address: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
12
|
-
bank_name: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
13
|
-
account_number: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
14
|
-
routing_number: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
15
|
-
bank_account_type: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
16
|
-
bic_or_swift: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
17
|
-
changed_by: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
18
|
-
iban: Series[String] = pa.Field(coerce=True)
|
|
19
|
-
account_nickname: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
20
|
-
use_for_bonus: Series[pd.BooleanDtype] = pa.Field(coerce=True, nullable=True)
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import pandera as pa
|
|
2
|
-
from pandera.typing import Series
|
|
3
|
-
import pandas as pd
|
|
4
|
-
|
|
5
|
-
class CustomTableSchema(pa.DataFrameModel):
|
|
6
|
-
id: Series[pd.Int64Dtype] = pa.Field(coerce=True)
|
|
7
|
-
employee_id: Series[pd.Int64Dtype] = pa.Field(coerce=True)
|
|
8
|
-
|
|
9
|
-
class Config:
|
|
10
|
-
coerce = True
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import pandas as pd
|
|
2
|
-
import pandera as pa
|
|
3
|
-
from pandera import Bool
|
|
4
|
-
from pandera.typing import Series, String, Float, DateTime
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class EmploymentSchema(pa.DataFrameModel):
|
|
8
|
-
id: Series[pd.Int64Dtype] = pa.Field(coerce=True)
|
|
9
|
-
employee_id: Series[pd.Int64Dtype] = pa.Field(coerce=True)
|
|
10
|
-
active_effective_date: Series[DateTime] = pa.Field(coerce=True)
|
|
11
|
-
contract: Series[String] = pa.Field(coerce=True, nullable=True) # has a list of possible values
|
|
12
|
-
creation_date: Series[DateTime] = pa.Field(coerce=True, nullable=True)
|
|
13
|
-
effective_date: Series[DateTime] = pa.Field(coerce=True)
|
|
14
|
-
end_effective_date: Series[DateTime] = pa.Field(coerce=True, nullable=True)
|
|
15
|
-
fte: Series[Float] = pa.Field(coerce=True)
|
|
16
|
-
is_current: Series[Bool] = pa.Field(coerce=True)
|
|
17
|
-
modification_date: Series[DateTime] = pa.Field(coerce=True, nullable=True)
|
|
18
|
-
salary_pay_type: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
19
|
-
weekly_hours: Series[Float] = pa.Field(coerce=True, nullable=True)
|
|
20
|
-
# weekly_hours_sort_factor: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=False)
|
|
21
|
-
actual_working_pattern_working_pattern_type: Series[pa.String] = pa.Field(nullable=True)
|
|
22
|
-
actual_working_pattern_days_sunday: Series[Float] = pa.Field(nullable=True)
|
|
23
|
-
actual_working_pattern_days_tuesday: Series[Float] = pa.Field(nullable=True)
|
|
24
|
-
actual_working_pattern_days_wednesday: Series[Float] = pa.Field(nullable=True)
|
|
25
|
-
actual_working_pattern_days_monday: Series[Float] = pa.Field(nullable=True)
|
|
26
|
-
actual_working_pattern_days_friday: Series[Float] = pa.Field(nullable=True)
|
|
27
|
-
actual_working_pattern_days_thursday: Series[Float] = pa.Field(nullable=True)
|
|
28
|
-
actual_working_pattern_days_saturday: Series[Float] = pa.Field(nullable=True)
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import pandera as pa
|
|
2
|
-
from pandera.typing import Series
|
|
3
|
-
|
|
4
|
-
class NamedListSchema(pa.DataFrameModel):
|
|
5
|
-
id: Series[str] = pa.Field(coerce=True)
|
|
6
|
-
value: Series[str] = pa.Field(coerce=True)
|
|
7
|
-
name: Series[str] = pa.Field(coerce=True)
|
|
8
|
-
archived: Series[bool] = pa.Field(coerce=True)
|
|
9
|
-
# children: Series[list] = pa.Field(coerce=True)
|
|
10
|
-
type: Series[str] = pa.Field(coerce=True)
|
|
11
|
-
|
|
12
|
-
class Config:
|
|
13
|
-
coerce = True
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import pandera as pa
|
|
2
|
-
from pandera.typing import Series, String, Float, DateTime
|
|
3
|
-
import pandas as pd
|
|
4
|
-
|
|
5
|
-
class VariablePaymentSchema(pa.DataFrameModel):
|
|
6
|
-
can_be_deleted: Series[bool] = pa.Field(nullable=True, coerce=True)
|
|
7
|
-
department_percent: Series[Float] = pa.Field(nullable=True, coerce=True)
|
|
8
|
-
payout_type: Series[String] = pa.Field(coerce=True)
|
|
9
|
-
num_of_salaries: Series[pd.Int64Dtype] = pa.Field(nullable=True, coerce=True)
|
|
10
|
-
end_date: Series[DateTime] = pa.Field(nullable=True, coerce=True)
|
|
11
|
-
creation_date: Series[DateTime] = pa.Field(coerce=True)
|
|
12
|
-
percentage_of_annual_salary: Series[Float] = pa.Field(nullable=True, coerce=True)
|
|
13
|
-
individual_percent: Series[Float] = pa.Field(nullable=True, coerce=True)
|
|
14
|
-
variable_type: Series[String] = pa.Field(nullable=True, coerce=True)
|
|
15
|
-
is_current: Series[bool] = pa.Field(nullable=True, coerce=True)
|
|
16
|
-
modification_date: Series[DateTime] = pa.Field(nullable=True, coerce=True)
|
|
17
|
-
company_percent: Series[Float] = pa.Field(nullable=True, coerce=True)
|
|
18
|
-
id: Series[pd.Int64Dtype] = pa.Field(coerce=True)
|
|
19
|
-
end_effective_date: Series[DateTime] = pa.Field(nullable=True, coerce=True)
|
|
20
|
-
payment_period: Series[String] = pa.Field(coerce=True)
|
|
21
|
-
effective_date: Series[DateTime] = pa.Field(coerce=True)
|
|
22
|
-
amount_value: Series[Float] = pa.Field(coerce=True)
|
|
23
|
-
amount_currency: Series[String] = pa.Field(coerce=True)
|
|
24
|
-
change_reason: Series[String] = pa.Field(nullable=True, coerce=True)
|
|
25
|
-
change_changed_by: Series[String] = pa.Field(nullable=True, coerce=True)
|
|
26
|
-
change_changed_by_id: Series[pd.Int64Dtype] = pa.Field(nullable=True, coerce=True)
|
|
27
|
-
employee_id: Series[pd.Int64Dtype] = pa.Field(coerce=True)
|
|
28
|
-
|
|
29
|
-
class Config:
|
|
30
|
-
coerce = True
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
|
|
3
|
-
import pandas as pd
|
|
4
|
-
import pandera as pa
|
|
5
|
-
from pandera import Bool
|
|
6
|
-
from pandera.typing import Series, String, Float, DateTime
|
|
7
|
-
import pandera.extensions as extensions
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@extensions.register_check_method()
|
|
12
|
-
def check_list(x):
|
|
13
|
-
return isinstance(x, list)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class PeopleSchema(pa.DataFrameModel):
|
|
17
|
-
id: Series[pd.Int64Dtype] = pa.Field(coerce=True)
|
|
18
|
-
display_name: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
19
|
-
company_id: Series[String] = pa.Field(coerce=True)
|
|
20
|
-
email: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
21
|
-
surname: Series[String] = pa.Field(coerce=True)
|
|
22
|
-
first_name: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
23
|
-
personal_birth_date: Series[DateTime] = pa.Field(coerce=True)
|
|
24
|
-
personal_pronouns: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
25
|
-
personal_honorific: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
26
|
-
personal_nationality: Series[object] = pa.Field(coerce=True, check_name=check_list)
|
|
27
|
-
# employee_payroll_manager: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
28
|
-
# employee_hrbp: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
29
|
-
# employee_it_admin: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
30
|
-
# employee_buddy: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
31
|
-
employee_veteran_status: Series[object] = pa.Field(coerce=True, check_name=check_list)
|
|
32
|
-
employee_disability_status: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
33
|
-
work_start_date: Series[DateTime] = pa.Field(coerce=True, nullable=True)
|
|
34
|
-
work_manager: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
35
|
-
work_work_phone: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
36
|
-
work_tenure_duration_period_i_s_o: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
37
|
-
work_tenure_duration_sort_factor: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=False)
|
|
38
|
-
work_tenure_duration_humanize: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
39
|
-
work_duration_of_employment_period_i_s_o: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
40
|
-
work_duration_of_employment_sort_factor: Series[String] = pa.Field(coerce=True, nullable=False)
|
|
41
|
-
work_duration_of_employment_humanize: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
42
|
-
work_reports_to_id_in_company: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=True)
|
|
43
|
-
work_employee_id_in_company: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=True)
|
|
44
|
-
work_reports_to_display_name: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
45
|
-
work_reports_to_email: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
46
|
-
work_reports_to_surname: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
47
|
-
work_reports_to_first_name: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
48
|
-
work_reports_to_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=True)
|
|
49
|
-
work_work_mobile: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
50
|
-
work_indirect_reports: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=True)
|
|
51
|
-
work_site_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=True)
|
|
52
|
-
work_department: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
53
|
-
work_tenure_duration_years: Series[Float] = pa.Field(coerce=True, nullable=True)
|
|
54
|
-
work_tenure_years: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=True)
|
|
55
|
-
work_is_manager: Series[Bool] = pa.Field(coerce=True)
|
|
56
|
-
work_title: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
57
|
-
work_site: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
58
|
-
work_original_start_date: Series[DateTime] = pa.Field(coerce=True, nullable=True)
|
|
59
|
-
work_active_effective_date: Series[DateTime] = pa.Field(coerce=True, nullable=True)
|
|
60
|
-
work_direct_reports: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=True)
|
|
61
|
-
# work_work_change_type: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
62
|
-
work_second_level_manager: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=True)
|
|
63
|
-
work_days_of_previous_service: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=True)
|
|
64
|
-
work_years_of_service: Series[Float] = pa.Field(coerce=True, nullable=True)
|
|
65
|
-
about_food_preferences: Series[object] = pa.Field(coerce=True, check_name=check_list)
|
|
66
|
-
# about_social_data_linkedin: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
67
|
-
about_social_data_twitter: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
68
|
-
about_social_data_facebook: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
69
|
-
about_superpowers: Series[object] = pa.Field(coerce=True, check_name=check_list)
|
|
70
|
-
about_hobbies: Series[object] = pa.Field(coerce=True, check_name=check_list)
|
|
71
|
-
about_about: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
72
|
-
about_avatar: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
73
|
-
address_city: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
74
|
-
address_post_code: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
75
|
-
address_line1: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
76
|
-
address_line2: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
77
|
-
# address_country: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
78
|
-
address_active_effective_date: Series[DateTime] = pa.Field(coerce=True, nullable=True)
|
|
79
|
-
# home_legal_gender: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
80
|
-
home_spouse_first_name: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
81
|
-
home_spouse_surname: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
82
|
-
# home_spouse_birth_date: Series[DateTime] = pa.Field(coerce=True, nullable=True)
|
|
83
|
-
home_spouse_gender: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
84
|
-
internal_termination_reason: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
85
|
-
internal_termination_date: Series[DateTime] = pa.Field(coerce=True, nullable=True)
|
|
86
|
-
internal_termination_type: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
87
|
-
employee_last_day_of_work: Series[DateTime] = pa.Field(coerce=True, nullable=True)
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import pandas as pd
|
|
2
|
-
import pandera as pa
|
|
3
|
-
from pandera import Bool
|
|
4
|
-
from pandera.typing import Series, String, Float, DateTime
|
|
5
|
-
import pandera.extensions as extensions
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class SalarySchema(pa.DataFrameModel):
|
|
9
|
-
id: Series[pd.Int64Dtype] = pa.Field(coerce=True)
|
|
10
|
-
employee_id: Series[pd.Int64Dtype] = pa.Field(coerce=True)
|
|
11
|
-
pay_frequency: Series[String] = pa.Field(coerce=True, nullable=True) # has a list of possible values , isin=['Monthly']
|
|
12
|
-
creation_date: Series[DateTime] = pa.Field(coerce=True, nullable=True)
|
|
13
|
-
is_current: Series[Bool] = pa.Field(coerce=True)
|
|
14
|
-
modification_date: Series[DateTime] = pa.Field(coerce=True, nullable=True)
|
|
15
|
-
effective_date: Series[DateTime] = pa.Field(coerce=True)
|
|
16
|
-
end_effective_date: Series[DateTime] = pa.Field(coerce=True, nullable=True)
|
|
17
|
-
change_reason: Series[str] = pa.Field(coerce=True, nullable=True)
|
|
18
|
-
pay_period: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
19
|
-
base_value: Series[Float] = pa.Field(coerce=True, nullable=True)
|
|
20
|
-
base_currency: Series[String] = pa.Field(coerce=True, isin=['EUR', 'USD'])
|
|
21
|
-
active_effective_date: Series[DateTime] = pa.Field(coerce=True)
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import pandera as pa
|
|
2
|
-
from pandera.typing import Series, String, Float
|
|
3
|
-
import pandas as pd
|
|
4
|
-
|
|
5
|
-
class TimeOffSchema(pa.DataFrameModel):
|
|
6
|
-
change_type: Series[String] = pa.Field(coerce=True)
|
|
7
|
-
employee_id: Series[String] = pa.Field(coerce=True)
|
|
8
|
-
employee_display_name: Series[String] = pa.Field(coerce=True)
|
|
9
|
-
employee_email: Series[String] = pa.Field(coerce=True)
|
|
10
|
-
request_id: Series[pd.Int64Dtype] = pa.Field(coerce=True)
|
|
11
|
-
policy_type_display_name: Series[String] = pa.Field(coerce=True)
|
|
12
|
-
type: Series[String] = pa.Field(coerce=True)
|
|
13
|
-
start_date: Series[String] = pa.Field(coerce=True)
|
|
14
|
-
start_portion: Series[String] = pa.Field(coerce=True)
|
|
15
|
-
end_date: Series[String] = pa.Field(coerce=True)
|
|
16
|
-
end_portion: Series[String] = pa.Field(coerce=True)
|
|
17
|
-
day_portion: Series[String] = pa.Field(coerce=True)
|
|
18
|
-
date: Series[String] = pa.Field(coerce=True)
|
|
19
|
-
hours_on_date: Series[Float] = pa.Field(coerce=True)
|
|
20
|
-
daily_hours: Series[Float] = pa.Field(coerce=True)
|
|
21
|
-
duration_unit: Series[String] = pa.Field(coerce=True)
|
|
22
|
-
total_duration: Series[Float] = pa.Field(coerce=True)
|
|
23
|
-
total_cost: Series[Float] = pa.Field(coerce=True)
|
|
24
|
-
change_reason: Series[String] = pa.Field(nullable=True, coerce=True)
|
|
25
|
-
visibility: Series[String] = pa.Field(coerce=True)
|
|
26
|
-
|
|
27
|
-
class Config:
|
|
28
|
-
coerce = True
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import pandera as pa
|
|
2
|
-
from pandera.typing import Series
|
|
3
|
-
import pandas as pd
|
|
4
|
-
from datetime import datetime
|
|
5
|
-
|
|
6
|
-
class WorkSchema(pa.DataFrameModel):
|
|
7
|
-
can_be_deleted: Series[pa.Bool] = pa.Field(coerce=True)
|
|
8
|
-
work_change_type: Series[str] = pa.Field(coerce=True)
|
|
9
|
-
creation_date: Series[datetime] = pa.Field(coerce=True, nullable=True)
|
|
10
|
-
title: Series[str] = pa.Field(coerce=True, nullable=True)
|
|
11
|
-
is_current: Series[pa.Bool] = pa.Field(coerce=True)
|
|
12
|
-
modification_date: Series[datetime] = pa.Field(coerce=True, nullable=True)
|
|
13
|
-
site: Series[str] = pa.Field(coerce=True, nullable=True)
|
|
14
|
-
site_id: Series[pd.Int64Dtype] = pa.Field(coerce=True)
|
|
15
|
-
id: Series[pd.Int64Dtype] = pa.Field(coerce=True)
|
|
16
|
-
end_effective_date: Series[datetime] = pa.Field(coerce=True, nullable=True)
|
|
17
|
-
active_effective_date: Series[datetime] = pa.Field(coerce=True, nullable=True)
|
|
18
|
-
department: Series[str] = pa.Field(coerce=True, nullable=True)
|
|
19
|
-
effective_date: Series[datetime] = pa.Field(coerce=True, nullable=True)
|
|
20
|
-
change_reason: Series[str] = pa.Field(coerce=True, nullable=True)
|
|
21
|
-
change_changed_by: Series[str] = pa.Field(coerce=True, nullable=True)
|
|
22
|
-
change_changed_by_id: Series[str] = pa.Field(coerce=True, nullable=True)
|
|
23
|
-
reports_to_id: Series[str] = pa.Field(coerce=True, nullable=True)
|
|
24
|
-
reports_to_first_name: Series[str] = pa.Field(coerce=True, nullable=True)
|
|
25
|
-
reports_to_surname: Series[str] = pa.Field(coerce=True, nullable=True)
|
|
26
|
-
reports_to_email: Series[str] = pa.Field(coerce=True, nullable=True)
|
|
27
|
-
reports_to_display_name: Series[str] = pa.Field(coerce=True, nullable=True)
|
|
28
|
-
reports_to: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=True)
|
|
29
|
-
employee_id: Series[pd.Int64Dtype] = pa.Field(coerce=True)
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
from datetime import datetime, timezone
|
|
2
|
-
import pandas as pd
|
|
3
|
-
from brynq_sdk_functions import Functions
|
|
4
|
-
from .schemas.timeoff import TimeOffSchema
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class TimeOff:
|
|
8
|
-
def __init__(self, bob):
|
|
9
|
-
self.bob = bob
|
|
10
|
-
|
|
11
|
-
def get(self, since: datetime) -> (pd.DataFrame, pd.DataFrame):
|
|
12
|
-
resp = self.bob.session.get(url=f"{self.bob.base_url}timeoff/requests/changes",
|
|
13
|
-
params={'since': since.replace(tzinfo=timezone.utc).isoformat(timespec='milliseconds')},
|
|
14
|
-
timeout=self.bob.timeout)
|
|
15
|
-
resp.raise_for_status()
|
|
16
|
-
data = resp.json()['changes']
|
|
17
|
-
# data = self.bob.get_paginated_result(request)
|
|
18
|
-
df = pd.json_normalize(
|
|
19
|
-
data,
|
|
20
|
-
record_path='changes',
|
|
21
|
-
meta=['employeeId']
|
|
22
|
-
)
|
|
23
|
-
df = self.bob.rename_camel_columns_to_snake_case(df)
|
|
24
|
-
valid_timeoff, invalid_timeoff = Functions.validate_data(df=df, schema=TimeOffSchema, debug=True)
|
|
25
|
-
|
|
26
|
-
return valid_timeoff, invalid_timeoff
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|