brynq-sdk-bob 2.6.2.dev13__py3-none-any.whl → 2.8.2__py3-none-any.whl
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/__init__.py +5 -8
- brynq_sdk_bob/bank.py +3 -15
- brynq_sdk_bob/employment.py +1 -3
- brynq_sdk_bob/payments.py +3 -53
- brynq_sdk_bob/people.py +59 -41
- brynq_sdk_bob/reports.py +38 -0
- brynq_sdk_bob/salaries.py +2 -9
- brynq_sdk_bob/schemas/bank.py +7 -8
- brynq_sdk_bob/schemas/employment.py +1 -1
- brynq_sdk_bob/schemas/payments.py +2 -2
- brynq_sdk_bob/schemas/people.py +21 -12
- brynq_sdk_bob/schemas/salary.py +1 -0
- brynq_sdk_bob/schemas/timeoff.py +1 -1
- brynq_sdk_bob/schemas/work.py +2 -0
- brynq_sdk_bob/work.py +2 -26
- {brynq_sdk_bob-2.6.2.dev13.dist-info → brynq_sdk_bob-2.8.2.dist-info}/METADATA +1 -2
- brynq_sdk_bob-2.8.2.dist-info/RECORD +29 -0
- {brynq_sdk_bob-2.6.2.dev13.dist-info → brynq_sdk_bob-2.8.2.dist-info}/WHEEL +1 -1
- brynq_sdk_bob-2.6.2.dev13.dist-info/RECORD +0 -28
- {brynq_sdk_bob-2.6.2.dev13.dist-info → brynq_sdk_bob-2.8.2.dist-info}/top_level.txt +0 -0
brynq_sdk_bob/__init__.py
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import base64
|
|
2
|
-
import
|
|
3
|
-
from typing import Union, List, Optional, Literal
|
|
4
|
-
import pandas as pd
|
|
2
|
+
from typing import List, Optional, Literal
|
|
5
3
|
import requests
|
|
6
4
|
import os
|
|
5
|
+
from .reports import Reports
|
|
7
6
|
from brynq_sdk_brynq import BrynQ
|
|
8
|
-
from brynq_sdk_functions import Functions
|
|
9
7
|
from .bank import Bank
|
|
10
8
|
from .company import Company
|
|
11
9
|
from .documents import CustomDocuments
|
|
@@ -17,6 +15,7 @@ from .salaries import Salaries
|
|
|
17
15
|
from .timeoff import TimeOff
|
|
18
16
|
from .work import Work
|
|
19
17
|
from .custom_tables import CustomTables
|
|
18
|
+
from .payroll_history import History
|
|
20
19
|
|
|
21
20
|
class Bob(BrynQ):
|
|
22
21
|
def __init__(self, system_type: Optional[Literal['source', 'target']] = None, test_environment: bool = True, debug: bool = False, target_system: str = None):
|
|
@@ -40,15 +39,13 @@ class Bob(BrynQ):
|
|
|
40
39
|
self.companies = Company(self)
|
|
41
40
|
self.named_lists = NamedLists(self)
|
|
42
41
|
self.custom_tables = CustomTables(self)
|
|
42
|
+
self.payroll_history = History(self)
|
|
43
|
+
self.reports = Reports(self)
|
|
43
44
|
self.data_interface_id = os.getenv("DATA_INTERFACE_ID")
|
|
44
45
|
self.debug = debug
|
|
45
46
|
|
|
46
47
|
def _get_request_headers(self, system_type):
|
|
47
48
|
credentials = self.interfaces.credentials.get(system='bob', system_type=system_type)
|
|
48
|
-
if type(credentials) is list:
|
|
49
|
-
credentials = credentials[0]
|
|
50
|
-
|
|
51
|
-
print(credentials)
|
|
52
49
|
auth_token = base64.b64encode(f"{credentials.get('data').get('User ID')}:{credentials.get('data').get('API Token')}".encode()).decode('utf-8')
|
|
53
50
|
headers = {
|
|
54
51
|
"accept": "application/json",
|
brynq_sdk_bob/bank.py
CHANGED
|
@@ -2,35 +2,23 @@ import pandas as pd
|
|
|
2
2
|
from brynq_sdk_functions import Functions
|
|
3
3
|
from .schemas.bank import BankSchema
|
|
4
4
|
|
|
5
|
-
import time
|
|
6
|
-
from tqdm import tqdm
|
|
7
|
-
from tenacity import retry, stop_after_delay, wait_exponential
|
|
8
5
|
|
|
9
6
|
class Bank:
|
|
10
7
|
def __init__(self, bob):
|
|
11
8
|
self.bob = bob
|
|
12
9
|
self.schema = BankSchema
|
|
13
10
|
|
|
14
|
-
@retry(stop=stop_after_delay(120), wait=wait_exponential(multiplier=1, min=1, max=10))
|
|
15
|
-
def _get_bank_accounts(self, person_id: str):
|
|
16
|
-
"""Fetch bank accounts for a person with retry logic (max 2 minutes)."""
|
|
17
|
-
resp = self.bob.session.get(url=f"{self.bob.base_url}people/{person_id}/bank-accounts", timeout=self.bob.timeout)
|
|
18
|
-
resp.raise_for_status()
|
|
19
|
-
return resp
|
|
20
|
-
|
|
21
11
|
def get(self, person_ids: pd.Series, field_selection: list[str] = []) -> (pd.DataFrame, pd.DataFrame):
|
|
22
12
|
data = []
|
|
23
|
-
for person_id in
|
|
24
|
-
resp = self.
|
|
13
|
+
for person_id in person_ids:
|
|
14
|
+
resp = self.bob.session.get(url=f"{self.bob.base_url}people/{person_id}/bank-accounts", timeout=self.bob.timeout)
|
|
15
|
+
resp.raise_for_status()
|
|
25
16
|
temp_data = resp.json()['values']
|
|
26
17
|
# when an employee has one or more bank accounts, the response is a list of dictionaries.
|
|
27
18
|
for account in temp_data:
|
|
28
19
|
account['employee_id'] = person_id
|
|
29
20
|
data += temp_data
|
|
30
21
|
|
|
31
|
-
# rate limit is 50 per minute
|
|
32
|
-
time.sleep(1.3)
|
|
33
|
-
|
|
34
22
|
df = pd.DataFrame(data)
|
|
35
23
|
|
|
36
24
|
valid_banks, invalid_banks = Functions.validate_data(df=df, schema=BankSchema, debug=True)
|
brynq_sdk_bob/employment.py
CHANGED
brynq_sdk_bob/payments.py
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import time
|
|
2
|
-
from typing import List, Optional
|
|
3
|
-
|
|
4
1
|
import pandas as pd
|
|
5
|
-
from
|
|
6
|
-
|
|
2
|
+
from typing import Optional, List
|
|
7
3
|
from brynq_sdk_functions import Functions
|
|
8
|
-
|
|
9
|
-
from .schemas.payments import ActualPaymentsSchema, VariablePaymentSchema
|
|
4
|
+
from .schemas.payments import VariablePaymentSchema, ActualPaymentsSchema
|
|
10
5
|
|
|
11
6
|
|
|
12
7
|
class Payments:
|
|
@@ -14,43 +9,9 @@ class Payments:
|
|
|
14
9
|
self.bob = bob
|
|
15
10
|
self.schema = VariablePaymentSchema
|
|
16
11
|
|
|
17
|
-
def _apply_named_list_mappings(self, df: pd.DataFrame) -> pd.DataFrame:
|
|
18
|
-
"""Apply named list ID-to-value mappings to dataframe columns."""
|
|
19
|
-
if df.empty:
|
|
20
|
-
return df
|
|
21
|
-
|
|
22
|
-
# Fetch named lists from Bob API
|
|
23
|
-
resp_named_lists = self.bob.session.get(
|
|
24
|
-
url=f"{self.bob.base_url}company/named-lists",
|
|
25
|
-
timeout=self.bob.timeout,
|
|
26
|
-
headers=self.bob.headers
|
|
27
|
-
)
|
|
28
|
-
named_lists = resp_named_lists.json()
|
|
29
|
-
|
|
30
|
-
# Transform named_lists to create id-to-value mappings for each field
|
|
31
|
-
named_lists = {
|
|
32
|
-
key.split('.')[-1]: {item['id']: item['value'] for item in value['values']}
|
|
33
|
-
for key, value in named_lists.items()
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
# rename payrollVariableType to variableType in named lists
|
|
37
|
-
named_lists['variableType'] = named_lists['payrollVariableType']
|
|
38
|
-
|
|
39
|
-
for field in df.columns:
|
|
40
|
-
# Fields in the response and in the named-list have different building blocks
|
|
41
|
-
# but they both end with the same last block
|
|
42
|
-
field_df = field.split('.')[-1].split('work_')[-1]
|
|
43
|
-
if field_df in named_lists.keys() and field_df not in ['site']:
|
|
44
|
-
mapping = named_lists[field_df]
|
|
45
|
-
df[field] = df[field].apply(
|
|
46
|
-
lambda v: [mapping.get(x, x) for x in v] if isinstance(v, list) else mapping.get(v, v)
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
return df
|
|
50
|
-
|
|
51
12
|
def get(self, person_ids: List[str]) -> (pd.DataFrame, pd.DataFrame):
|
|
52
13
|
df = pd.DataFrame()
|
|
53
|
-
for person_id in
|
|
14
|
+
for person_id in person_ids:
|
|
54
15
|
resp = self.bob.session.get(url=f"{self.bob.base_url}people/{person_id}/variable", timeout=self.bob.timeout)
|
|
55
16
|
resp.raise_for_status()
|
|
56
17
|
data = resp.json()
|
|
@@ -59,15 +20,7 @@ class Payments:
|
|
|
59
20
|
record_path='values'
|
|
60
21
|
)])
|
|
61
22
|
df['employee_id'] = person_id
|
|
62
|
-
|
|
63
|
-
# Rate limit is 50 per minute
|
|
64
|
-
time.sleep(1.3)
|
|
65
|
-
|
|
66
23
|
df = df.reset_index(drop=True)
|
|
67
|
-
|
|
68
|
-
# Apply named list mappings
|
|
69
|
-
df = self._apply_named_list_mappings(df)
|
|
70
|
-
|
|
71
24
|
valid_payments, invalid_payments = Functions.validate_data(df=df, schema=self.schema, debug=True)
|
|
72
25
|
return valid_payments, invalid_payments
|
|
73
26
|
|
|
@@ -154,9 +107,6 @@ class Payments:
|
|
|
154
107
|
|
|
155
108
|
df = pd.json_normalize(all_results)
|
|
156
109
|
|
|
157
|
-
# Apply named list mappings
|
|
158
|
-
df = self._apply_named_list_mappings(df)
|
|
159
|
-
|
|
160
110
|
valid_payments, invalid_payments = Functions.validate_data(
|
|
161
111
|
df=df,
|
|
162
112
|
schema=ActualPaymentsSchema,
|
brynq_sdk_bob/people.py
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
from typing import List, Optional
|
|
2
|
-
|
|
3
1
|
import pandas as pd
|
|
4
|
-
|
|
5
|
-
from
|
|
6
|
-
|
|
2
|
+
import re
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from brynq_sdk_functions import Functions
|
|
5
|
+
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
7
6
|
from .bank import Bank
|
|
8
|
-
from .custom_tables import CustomTables
|
|
9
7
|
from .employment import Employment
|
|
10
8
|
from .salaries import Salaries
|
|
11
9
|
from .schemas.people import PeopleSchema
|
|
12
10
|
from .work import Work
|
|
11
|
+
from .custom_tables import CustomTables
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
class People:
|
|
@@ -23,6 +22,7 @@ class People:
|
|
|
23
22
|
self.schema = PeopleSchema
|
|
24
23
|
|
|
25
24
|
|
|
25
|
+
|
|
26
26
|
# Build API fields using column metadata if present (api_field), otherwise use the column (alias) name
|
|
27
27
|
def __build_api_fields(self, schema_model: BrynQPanderaDataFrameModel) -> list[str]:
|
|
28
28
|
schema = schema_model.to_schema()
|
|
@@ -31,78 +31,96 @@ class People:
|
|
|
31
31
|
for col_name, col in schema.columns.items()
|
|
32
32
|
]
|
|
33
33
|
|
|
34
|
-
def get(self, schema_custom_fields: Optional[BrynQPanderaDataFrameModel] = None
|
|
34
|
+
def get(self, schema_custom_fields: Optional[BrynQPanderaDataFrameModel] = None) -> pd.DataFrame:
|
|
35
|
+
|
|
35
36
|
core_fields = self.__build_api_fields(PeopleSchema)
|
|
36
37
|
custom_fields = self.__build_api_fields(schema_custom_fields) if schema_custom_fields is not None else []
|
|
37
38
|
fields = core_fields + custom_fields
|
|
38
39
|
|
|
39
|
-
# Build filters based on employee_ids if provided
|
|
40
|
-
filters = []
|
|
41
|
-
if employee_ids is not None:
|
|
42
|
-
filters = [
|
|
43
|
-
{
|
|
44
|
-
"fieldPath": "root.id",
|
|
45
|
-
"operator": "equals",
|
|
46
|
-
"values": employee_ids
|
|
47
|
-
}
|
|
48
|
-
]
|
|
49
|
-
|
|
50
40
|
resp = self.bob.session.post(url=f"{self.bob.base_url}people/search",
|
|
51
41
|
json={
|
|
52
42
|
"fields": fields,
|
|
53
|
-
"filters":
|
|
54
|
-
"showInactive": show_inactive,
|
|
43
|
+
"filters": []
|
|
55
44
|
#"humanReadable": "REPLACE"
|
|
56
45
|
},
|
|
57
46
|
timeout=self.bob.timeout)
|
|
58
47
|
resp.raise_for_status()
|
|
59
48
|
df = pd.json_normalize(resp.json()['employees'])
|
|
60
|
-
if df.empty and employee_ids is not None and resp.status_code == 200:
|
|
61
|
-
raise Exception(f"No employees found in HiBob for employee_ids: {employee_ids}")
|
|
62
49
|
|
|
63
|
-
df = df.loc[:, ~df.columns.str.contains('value')]
|
|
64
50
|
|
|
65
51
|
# Normalize separators in incoming data: convert '/' to '.' to match schema aliases
|
|
66
52
|
df.columns = df.columns.str.replace('/', '.', regex=False)
|
|
67
53
|
|
|
54
|
+
|
|
55
|
+
# Clean up custom .value columns; keeps only one field per custom key. the .value column actually contains the value., other column is nested key.
|
|
56
|
+
custom_cols = [col for col in df.columns if "custom" in str(col) and str(col).endswith('.value')]
|
|
57
|
+
for col in custom_cols:
|
|
58
|
+
new_col = col.removesuffix('.value')
|
|
59
|
+
# prefer non-empty clean column, otherwise upgrade .value data
|
|
60
|
+
if new_col not in df.columns:
|
|
61
|
+
df = df.rename(columns={col: new_col})
|
|
62
|
+
elif df[new_col].isna().all() and not df[col].isna().all():
|
|
63
|
+
df[new_col] = df[col]
|
|
64
|
+
df = df.drop(columns=[col])
|
|
65
|
+
else:
|
|
66
|
+
# Drop identical/redundant .value col
|
|
67
|
+
if df[new_col].equals(df[col]):
|
|
68
|
+
df = df.drop(columns=[col])
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
|
|
68
72
|
# A lot of fields from Bob are returned with only ID's. Those fields should be mapped to names. Therefore, we need to get the mapping from the named-lists endpoint.
|
|
69
73
|
resp_named_lists = self.bob.session.get(url=f"{self.bob.base_url}company/named-lists", timeout=self.bob.timeout, headers=self.bob.headers)
|
|
70
74
|
named_lists = resp_named_lists.json()
|
|
71
|
-
# save json to file
|
|
72
|
-
# import json
|
|
73
|
-
# with open('named_lists.json', 'w') as f:
|
|
74
|
-
# json.dump(named_lists, f, indent=4)
|
|
75
75
|
|
|
76
76
|
# Transform named_lists to create id-to-value mappings for each field
|
|
77
77
|
named_lists = {key.split('.')[-1]: {item['id']: item['value'] for item in value['values']} for key, value in named_lists.items()}
|
|
78
78
|
|
|
79
|
-
deviating_named_list_cols_mapping = {
|
|
80
|
-
'payroll.employment.actualWorkingPattern.workingPatternId': 'workingPattern_entity_list',
|
|
81
|
-
'payroll.employment.type': 'payrollEmploymentType',
|
|
82
|
-
'home.familyStatus': 'familystatus',
|
|
83
|
-
'personal.nationality': 'nationalities',
|
|
84
|
-
'internal.terminationReason': 'terminationreason',
|
|
85
|
-
}
|
|
86
|
-
|
|
87
79
|
for field in df.columns:
|
|
88
80
|
# Fields in the response and in the named-list does have different building blocks (e.g. people.payroll.entitlement. or people.entitlement.). But they both end with the same last block
|
|
89
81
|
field_df = field.split('.')[-1].split('work_')[-1]
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
named_list_key = deviating_named_list_cols_mapping.get(field, field_df)
|
|
93
|
-
|
|
94
|
-
if named_list_key in named_lists.keys() and named_list_key not in ['site']:
|
|
95
|
-
mapping = named_lists[named_list_key]
|
|
82
|
+
if field_df in named_lists.keys() and field_df not in ['site']:
|
|
83
|
+
mapping = named_lists[field_df]
|
|
96
84
|
df[field] = df[field].apply(
|
|
97
85
|
lambda v: [mapping.get(x, x) for x in v] if isinstance(v, list) else mapping.get(v, v)
|
|
98
86
|
)
|
|
99
87
|
|
|
88
|
+
|
|
100
89
|
if schema_custom_fields is not None:
|
|
90
|
+
|
|
101
91
|
valid_people, invalid_people_custom = Functions.validate_data(df=df, schema=schema_custom_fields, debug=True)
|
|
92
|
+
|
|
93
|
+
|
|
102
94
|
else:
|
|
103
95
|
valid_people = df
|
|
104
96
|
invalid_people_custom = pd.DataFrame()
|
|
105
97
|
|
|
98
|
+
|
|
106
99
|
valid_people, invalid_people = Functions.validate_data(df=valid_people, schema=PeopleSchema, debug=True)
|
|
107
100
|
|
|
101
|
+
# For columns ending with .value.value, use fillna to fill the corresponding base column since that's not done automatically
|
|
102
|
+
def _normalize_key(key: str) -> str:
|
|
103
|
+
# Build mapping from custom schema alias (API path) to the real column name used after validation
|
|
104
|
+
key = key.lstrip('.')
|
|
105
|
+
key = key.replace('/', '.')
|
|
106
|
+
key = key.replace('.', '_')
|
|
107
|
+
key = re.sub(r'(?<!^)([A-Z])', r'_\1', key).lower()
|
|
108
|
+
return key
|
|
109
|
+
|
|
110
|
+
alias_to_real: dict = {}
|
|
111
|
+
if schema_custom_fields is not None:
|
|
112
|
+
alias_map = getattr(schema_custom_fields, "_alias_map", {}) # real_name -> alias
|
|
113
|
+
alias_to_real = {_normalize_key(alias): real for real, alias in alias_map.items()}
|
|
114
|
+
|
|
115
|
+
for col in valid_people.columns:
|
|
116
|
+
if col.endswith('value.value'):
|
|
117
|
+
# Compute the base alias (remove suffix), normalise, and resolve to real column name via custom schema
|
|
118
|
+
base_alias = col[:-12]
|
|
119
|
+
target_key = _normalize_key(base_alias)
|
|
120
|
+
target_col = alias_to_real.get(target_key, target_key)
|
|
121
|
+
if target_col in valid_people.columns:
|
|
122
|
+
valid_people[target_col] = valid_people[target_col].fillna(valid_people[col])
|
|
123
|
+
|
|
124
|
+
# Remove columns that contain '.value' or '_get'
|
|
125
|
+
valid_people = valid_people.loc[:, ~valid_people.columns.str.contains(r'\.value|_get')]
|
|
108
126
|
return valid_people, pd.concat([invalid_people, invalid_people_custom])
|
brynq_sdk_bob/reports.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from io import BytesIO
|
|
3
|
+
from typing import Optional, TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
from brynq_sdk_functions import Functions
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from brynq_sdk_bob import Bob
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Reports:
|
|
12
|
+
def __init__(self, bob):
|
|
13
|
+
self.bob: Bob = bob
|
|
14
|
+
|
|
15
|
+
def get(self) -> pd.DataFrame:
|
|
16
|
+
resp = self.bob.session.get(url=f"{self.bob.base_url}company/reports", timeout=self.bob.timeout)
|
|
17
|
+
resp.raise_for_status()
|
|
18
|
+
data = resp.json()
|
|
19
|
+
df = pd.json_normalize(
|
|
20
|
+
data,
|
|
21
|
+
record_path='views'
|
|
22
|
+
)
|
|
23
|
+
# df = self.bob.rename_camel_columns_to_snake_case(df)
|
|
24
|
+
# valid_documents, invalid_documents = Functions.validate_data(df=df, schema=DocumentsSchema, debug=True)
|
|
25
|
+
|
|
26
|
+
return df
|
|
27
|
+
|
|
28
|
+
def download(self, report_id: int | str = None) -> bytes:
|
|
29
|
+
if report_id:
|
|
30
|
+
url = f"{self.bob.base_url}company/reports/{report_id}/download"
|
|
31
|
+
else:
|
|
32
|
+
raise ValueError("Either report_id or report_name must be provided")
|
|
33
|
+
|
|
34
|
+
resp = self.bob.session.get(url=url, timeout=self.bob.timeout, params={"format": "csv"})
|
|
35
|
+
resp.raise_for_status()
|
|
36
|
+
data = resp.content
|
|
37
|
+
|
|
38
|
+
return data
|
brynq_sdk_bob/salaries.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
import requests
|
|
3
|
-
from typing import Optional, List
|
|
4
3
|
from brynq_sdk_functions import Functions
|
|
5
4
|
from .schemas.salary import SalarySchema, SalaryCreateSchema
|
|
6
5
|
|
|
@@ -10,16 +9,10 @@ class Salaries:
|
|
|
10
9
|
self.bob = bob
|
|
11
10
|
self.schema = SalarySchema
|
|
12
11
|
|
|
13
|
-
def get(self
|
|
14
|
-
params = {"limit": 100}
|
|
15
|
-
|
|
16
|
-
# Add employeeIds filter if provided
|
|
17
|
-
if employee_ids is not None:
|
|
18
|
-
params["employeeIds"] = ",".join(employee_ids)
|
|
19
|
-
|
|
12
|
+
def get(self) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
20
13
|
request = requests.Request(method='GET',
|
|
21
14
|
url=f"{self.bob.base_url}bulk/people/salaries",
|
|
22
|
-
params=
|
|
15
|
+
params={"limit": 100})
|
|
23
16
|
data = self.bob.get_paginated_result(request)
|
|
24
17
|
df = pd.json_normalize(
|
|
25
18
|
data,
|
brynq_sdk_bob/schemas/bank.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import pandera as pa
|
|
2
|
-
from typing import Optional
|
|
3
2
|
from pandera.typing import Series, String
|
|
4
3
|
import pandas as pd
|
|
5
4
|
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
@@ -7,19 +6,19 @@ from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
|
7
6
|
|
|
8
7
|
class BankSchema(BrynQPanderaDataFrameModel):
|
|
9
8
|
id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Bank ID", alias="id")
|
|
10
|
-
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="
|
|
11
|
-
amount:
|
|
12
|
-
allocation:
|
|
13
|
-
branch_address:
|
|
9
|
+
employee_id: Series[String] = 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")
|
|
14
13
|
bank_name: Series[String] = pa.Field(coerce=True, nullable=True, description="Bank Name", alias="bankName")
|
|
15
14
|
account_number: Series[String] = pa.Field(coerce=True, nullable=True, description="Account Number", alias="accountNumber")
|
|
16
|
-
routing_number:
|
|
15
|
+
routing_number: Series[String] = pa.Field(coerce=True, nullable=True, description="Routing Number", alias="routingNumber")
|
|
17
16
|
bank_account_type: Series[String] = pa.Field(coerce=True, nullable=True, description="Bank Account Type", alias="bankAccountType")
|
|
18
|
-
bic_or_swift:
|
|
17
|
+
bic_or_swift: Series[String] = pa.Field(coerce=True, nullable=True, description="BIC or SWIFT", alias="bicOrSwift")
|
|
19
18
|
changed_by: Series[String] = pa.Field(coerce=True, nullable=True, description="Changed By", alias="changedBy")
|
|
20
19
|
iban: Series[String] = pa.Field(coerce=True, description="IBAN", alias="iban")
|
|
21
20
|
account_nickname: Series[String] = pa.Field(coerce=True, nullable=True, description="Account Nickname", alias="accountNickname")
|
|
22
|
-
use_for_bonus:
|
|
21
|
+
use_for_bonus: Series[pd.BooleanDtype] = pa.Field(coerce=True, nullable=True, description="Use for Bonus", alias="useForBonus")
|
|
23
22
|
|
|
24
23
|
class Config:
|
|
25
24
|
coerce = True
|
|
@@ -6,7 +6,7 @@ from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
|
6
6
|
|
|
7
7
|
class EmploymentSchema(BrynQPanderaDataFrameModel):
|
|
8
8
|
id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Employment ID", alias="id")
|
|
9
|
-
employee_id: Series[
|
|
9
|
+
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
10
10
|
active_effective_date: Series[DateTime] = pa.Field(coerce=True, description="Active Effective Date", alias="activeEffectiveDate")
|
|
11
11
|
contract: Series[String] = pa.Field(coerce=True, nullable=True, description="Contract", alias="contract") # has a list of possible values
|
|
12
12
|
creation_date: Series[DateTime] = pa.Field(coerce=True, nullable=True, description="Creation Date", alias="creationDate")
|
|
@@ -38,8 +38,8 @@ class ActualPaymentsSchema(BrynQPanderaDataFrameModel):
|
|
|
38
38
|
pay_type: Series[String] = pa.Field(coerce=True, description="Pay Type", alias="payType")
|
|
39
39
|
amount_value: Series[Float] = pa.Field(coerce=True, description="Amount Value", alias="amount.value")
|
|
40
40
|
amount_currency: Series[String] = pa.Field(coerce=True, description="Amount Currency", alias="amount.currency")
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
change_reason: Series[String] = pa.Field(nullable=True, coerce=True, description="Change Reason", alias="change.reason")
|
|
42
|
+
change_changed_by: Series[String] = pa.Field(nullable=True, coerce=True, description="Change Changed By", alias="change.changedBy")
|
|
43
43
|
change_changed_by_id: Series[String] = pa.Field(nullable=True, coerce=True, description="Change Changed By ID", alias="change.changedById")
|
|
44
44
|
|
|
45
45
|
class Config:
|
brynq_sdk_bob/schemas/people.py
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Optional, List, Dict
|
|
3
3
|
|
|
4
4
|
import pandas as pd
|
|
5
5
|
import pandera as pa
|
|
6
|
-
import pandera.extensions as extensions
|
|
7
6
|
from pandera import Bool
|
|
8
|
-
from pandera.
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
from pandera.typing import Series, String, Float
|
|
8
|
+
import pandera.extensions as extensions
|
|
11
9
|
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
10
|
+
from pandera.engines.pandas_engine import DateTime
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
@extensions.register_check_method()
|
|
@@ -27,7 +26,7 @@ class PeopleSchema(BrynQPanderaDataFrameModel):
|
|
|
27
26
|
first_name: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="First Name", alias="firstName", metadata={"api_field": "root.firstName"})
|
|
28
27
|
full_name: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Full Name", alias="fullName", metadata={"api_field": "root.fullName"})
|
|
29
28
|
# the date is in DD/MM/YYYY format,
|
|
30
|
-
personal_birth_date: Optional[Series[DateTime]] = pa.Field(coerce=True, nullable=
|
|
29
|
+
personal_birth_date: Optional[Series[DateTime]] = pa.Field(coerce=True, nullable=False, description="Personal Birth Date", alias="personal.birthDate")
|
|
31
30
|
personal_pronouns: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Personal Pronouns", alias="personal.pronouns")
|
|
32
31
|
personal_honorific: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Personal Honorific", alias="personal.honorific")
|
|
33
32
|
personal_nationality: Optional[Series[object]] = pa.Field(coerce=True, check_name=check_list, description="Personal Nationality", alias="personal.nationality")
|
|
@@ -41,10 +40,10 @@ class PeopleSchema(BrynQPanderaDataFrameModel):
|
|
|
41
40
|
work_manager: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Manager", alias="work.manager")
|
|
42
41
|
work_work_phone: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Work Phone", alias="work.workPhone")
|
|
43
42
|
work_tenure_duration_period_i_s_o: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Tenure Duration Period ISO", alias="work.tenureDuration.periodISO")
|
|
44
|
-
work_tenure_duration_sort_factor: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=
|
|
43
|
+
work_tenure_duration_sort_factor: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=False, description="Work Tenure Duration Sort Factor", alias="work.tenureDuration.sortFactor")
|
|
45
44
|
work_tenure_duration_humanize: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Tenure Duration Humanize", alias="work.tenureDuration.humanize")
|
|
46
45
|
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.durationOfEmployment.periodISO")
|
|
47
|
-
work_duration_of_employment_sort_factor: Optional[Series[String]] = pa.Field(coerce=True, nullable=
|
|
46
|
+
work_duration_of_employment_sort_factor: Optional[Series[String]] = pa.Field(coerce=True, nullable=False, description="Work Duration of Employment Sort Factor", alias="work.durationOfEmployment.sortFactor")
|
|
48
47
|
work_duration_of_employment_humanize: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Duration of Employment Humanize", alias="work.durationOfEmployment.humanize")
|
|
49
48
|
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")
|
|
50
49
|
work_employee_id_in_company: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Work Employee ID in Company", alias="work.employeeIdInCompany")
|
|
@@ -203,7 +202,7 @@ class PeopleSchema(BrynQPanderaDataFrameModel):
|
|
|
203
202
|
payroll_employment_actual_working_pattern_days_thursday: Optional[Series[float]] = pa.Field(coerce=True, nullable=True, description="Actual Working Pattern - Thursday", alias="payroll.employment.actualWorkingPattern.days.thursday")
|
|
204
203
|
payroll_employment_actual_working_pattern_days_saturday: Optional[Series[float]] = pa.Field(coerce=True, nullable=True, description="Actual Working Pattern - Saturday", alias="payroll.employment.actualWorkingPattern.days.saturday")
|
|
205
204
|
payroll_employment_actual_working_pattern_hours_per_day: Optional[Series[float]] = pa.Field(coerce=True, nullable=True, description="Actual Working Pattern - Hours Per Day", alias="payroll.employment.actualWorkingPattern.hoursPerDay")
|
|
206
|
-
payroll_employment_actual_working_pattern_working_pattern_id: Optional[Series[
|
|
205
|
+
payroll_employment_actual_working_pattern_working_pattern_id: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Actual Working Pattern - Working Pattern ID", alias="payroll.employment.actualWorkingPattern.workingPatternId")
|
|
207
206
|
payroll_employment_site_working_pattern_working_pattern_type: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Site Working Pattern - Working Pattern Type", alias="payroll.employment.siteWorkingPattern.workingPatternType")
|
|
208
207
|
payroll_employment_site_working_pattern_days_sunday: Optional[Series[float]] = pa.Field(coerce=True, nullable=True, description="Site Working Pattern - Sunday", alias="payroll.employment.siteWorkingPattern.days.sunday")
|
|
209
208
|
payroll_employment_site_working_pattern_days_tuesday: Optional[Series[float]] = pa.Field(coerce=True, nullable=True, description="Site Working Pattern - Tuesday", alias="payroll.employment.siteWorkingPattern.days.tuesday")
|
|
@@ -215,13 +214,24 @@ class PeopleSchema(BrynQPanderaDataFrameModel):
|
|
|
215
214
|
payroll_employment_site_working_pattern_hours_per_day: Optional[Series[float]] = pa.Field(coerce=True, nullable=True, description="Site Working Pattern - Hours Per Day", alias="payroll.employment.siteWorkingPattern.hoursPerDay")
|
|
216
215
|
payroll_employment_site_working_pattern_working_pattern_id: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Site Working Pattern - Working Pattern ID", alias="payroll.employment.siteWorkingPattern.workingPatternId")
|
|
217
216
|
payroll_employment_calendar_id: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Calendar ID", alias="payroll.employment.calendarId")
|
|
218
|
-
|
|
219
|
-
|
|
220
217
|
payroll_employment_salary_pay_type: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Salary Pay Type", alias="payroll.employment.salaryPayType")
|
|
221
218
|
payroll_employment_flsa_code: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="FLSA Code", alias="payroll.employment.flsaCode")
|
|
222
219
|
payroll_employment_fte: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="FTE %", alias="payroll.employment.fte")
|
|
223
220
|
payroll_employment_weekly_hours: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Weekly Hours", alias="payroll.employment.weeklyHours")
|
|
224
221
|
|
|
222
|
+
# Salary information
|
|
223
|
+
# SOLUTION NOW FOR MFT: TODO: FIX UNNESTING (including .value.value)
|
|
224
|
+
payroll_salary_monthly_get: Optional[Series[str]] = pa.Field(coerce=True, nullable=True, description="Base salary (monthly), used for getting nested json", alias="payroll.salary.monthlyPayment")
|
|
225
|
+
payroll_salary_monthly_payment: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Base salary (monthly)", alias="payroll.salary.monthlyPayment.value")
|
|
226
|
+
payroll_salary_monthly_payment_currency: Optional[Series[str]] = pa.Field(coerce=True, nullable=True, description="Base salary (monthly) currency", alias="payroll.salary.monthlyPayment.currency")
|
|
227
|
+
|
|
228
|
+
payroll_salary_yearly_get: Optional[Series[str]] = pa.Field(coerce=True, nullable=True, description="Base salary (yearly), used for getting nested json", alias="payroll.salary.yearlyPayment")
|
|
229
|
+
payroll_salary_yearly_payment: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Base salary (yearly)", alias="payroll.salary.yearlyPayment.value")
|
|
230
|
+
payroll_salary_yearly_payment_currency: Optional[Series[str]] = pa.Field(coerce=True, nullable=True, description="Base salary (yearly) currency", alias="payroll.salary.yearlyPayment.currency")
|
|
231
|
+
|
|
232
|
+
payroll_salary_active_effective_date: Optional[Series[str]] = pa.Field(coerce=True, nullable=True, description="effective date payment", alias="payroll.salary.activeEffectiveDate")
|
|
233
|
+
payroll_salary_payment: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Base Salary", alias="payroll.salary.payment")
|
|
234
|
+
|
|
225
235
|
# Emergency contact
|
|
226
236
|
emergency_first_name: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Emergency First Name", alias="emergency.firstName")
|
|
227
237
|
emergency_second_name: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Emergency Middle Name", alias="emergency.secondName")
|
|
@@ -277,7 +287,6 @@ class PeopleSchema(BrynQPanderaDataFrameModel):
|
|
|
277
287
|
# Positions / Job profile
|
|
278
288
|
employee_position_opening_id: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Position Opening ID", alias="employee.positionOpeningId")
|
|
279
289
|
employee_job_profile_id: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Job Profile ID", alias="employee.jobProfileId")
|
|
280
|
-
employee_job_profile_code: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Job Profile Code", alias="employee.jobProfileCode")
|
|
281
290
|
employee_recent_leave_start_date: Optional[Series[DateTime]] = pa.Field(coerce=True, nullable=True, description="Recent Leave Start Date", alias="employee.recentLeaveStartDate")
|
|
282
291
|
employee_recent_leave_end_date: Optional[Series[DateTime]] = pa.Field(coerce=True, nullable=True, description="Recent Leave End Date", alias="employee.recentLeaveEndDate")
|
|
283
292
|
employee_first_day_of_work: Optional[Series[DateTime]] = pa.Field(coerce=True, nullable=True, description="First Day Of Work", alias="employee.firstDayOfWork")
|
brynq_sdk_bob/schemas/salary.py
CHANGED
|
@@ -18,6 +18,7 @@ class SalarySchema(BrynQPanderaDataFrameModel):
|
|
|
18
18
|
modification_date: Series[DateTime] = pa.Field(coerce=True, nullable=True, description="Modification Date", alias="modificationDate")
|
|
19
19
|
effective_date: Series[DateTime] = pa.Field(coerce=True, description="Effective Date", alias="effectiveDate")
|
|
20
20
|
end_effective_date: Series[DateTime] = pa.Field(coerce=True, nullable=True, description="End Effective Date", alias="endEffectiveDate")
|
|
21
|
+
change_reason: Series[str] = pa.Field(coerce=True, nullable=True, description="Change Reason", alias="change.reason")
|
|
21
22
|
pay_period: Series[String] = pa.Field(coerce=True, nullable=True, description="Pay Period", alias="payPeriod")
|
|
22
23
|
base_value: Series[Float] = pa.Field(coerce=True, nullable=True, description="Base Value", alias="base.value") #needs to become base.value?
|
|
23
24
|
base_currency: Series[String] = pa.Field(coerce=True, nullable=True, description="Base Currency", alias="base.currency")
|
brynq_sdk_bob/schemas/timeoff.py
CHANGED
|
@@ -6,7 +6,7 @@ from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
|
6
6
|
|
|
7
7
|
class TimeOffSchema(BrynQPanderaDataFrameModel):
|
|
8
8
|
change_type: Series[String] = pa.Field(coerce=True, description="Change Type", alias="changeType")
|
|
9
|
-
employee_id: Series[
|
|
9
|
+
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
10
10
|
employee_display_name: Series[String] = pa.Field(coerce=True, description="Employee Display Name", alias="employeeDisplayName")
|
|
11
11
|
employee_email: Series[String] = pa.Field(coerce=True, description="Employee Email", alias="employeeEmail")
|
|
12
12
|
request_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Request ID", alias="requestId")
|
brynq_sdk_bob/schemas/work.py
CHANGED
|
@@ -18,6 +18,7 @@ class WorkSchema(BrynQPanderaDataFrameModel):
|
|
|
18
18
|
active_effective_date: Series[datetime] = pa.Field(coerce=True, nullable=True, description="Active Effective Date", alias="activeEffectiveDate")
|
|
19
19
|
department: Series[str] = pa.Field(coerce=True, nullable=True, description="Department", alias="department")
|
|
20
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="change.reason")
|
|
21
22
|
change_changed_by: Series[str] = pa.Field(coerce=True, nullable=True, description="Change Changed By", alias="change.changedBy")
|
|
22
23
|
change_changed_by_id: Series[str] = pa.Field(coerce=True, nullable=True, description="Change Changed By ID", alias="change.changedById")
|
|
23
24
|
reports_to_id: Series[str] = pa.Field(coerce=True, nullable=True, description="Reports To ID", alias="reportsTo.id")
|
|
@@ -25,6 +26,7 @@ class WorkSchema(BrynQPanderaDataFrameModel):
|
|
|
25
26
|
reports_to_surname: Series[str] = pa.Field(coerce=True, nullable=True, description="Reports To Surname", alias="reportsTo.surname")
|
|
26
27
|
reports_to_email: Series[str] = pa.Field(coerce=True, nullable=True, description="Reports To Email", alias="reportsTo.email")
|
|
27
28
|
reports_to_display_name: Series[str] = pa.Field(coerce=True, nullable=True, description="Reports To Display Name", alias="reportsTo.displayName")
|
|
29
|
+
reports_to: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=True, description="Reports To", alias="reportsTo")
|
|
28
30
|
employee_id: Series[str] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
29
31
|
|
|
30
32
|
class Config:
|
brynq_sdk_bob/work.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
import requests
|
|
3
|
-
from typing import Optional, List
|
|
4
3
|
from brynq_sdk_functions import Functions
|
|
5
4
|
from .schemas.work import WorkSchema
|
|
6
5
|
|
|
@@ -10,38 +9,15 @@ class Work:
|
|
|
10
9
|
self.bob = bob
|
|
11
10
|
self.schema = WorkSchema
|
|
12
11
|
|
|
13
|
-
def
|
|
14
|
-
reports_to_columns = [
|
|
15
|
-
'reportsTo.id',
|
|
16
|
-
'reportsTo.firstName',
|
|
17
|
-
'reportsTo.surname',
|
|
18
|
-
'reportsTo.email',
|
|
19
|
-
'reportsTo.displayName'
|
|
20
|
-
]
|
|
21
|
-
|
|
22
|
-
for col in reports_to_columns:
|
|
23
|
-
if col not in df.columns:
|
|
24
|
-
df[col] = pd.NA
|
|
25
|
-
|
|
26
|
-
return df
|
|
27
|
-
|
|
28
|
-
def get(self, employee_ids: Optional[List[str]] = None) ->(pd.DataFrame, pd.DataFrame):
|
|
29
|
-
params = {"limit": 100}
|
|
30
|
-
|
|
31
|
-
# Add employeeIds filter if provided
|
|
32
|
-
if employee_ids is not None:
|
|
33
|
-
params["employeeIds"] = ",".join(employee_ids)
|
|
34
|
-
|
|
12
|
+
def get(self) ->(pd.DataFrame, pd.DataFrame):
|
|
35
13
|
request = requests.Request(method='GET',
|
|
36
|
-
url=f"{self.bob.base_url}bulk/people/work"
|
|
37
|
-
params=params)
|
|
14
|
+
url=f"{self.bob.base_url}bulk/people/work")
|
|
38
15
|
data = self.bob.get_paginated_result(request)
|
|
39
16
|
df = pd.json_normalize(
|
|
40
17
|
data,
|
|
41
18
|
record_path='values',
|
|
42
19
|
meta=['employeeId']
|
|
43
20
|
)
|
|
44
|
-
df = self._ensure_reports_to_columns(df)
|
|
45
21
|
valid_work, invalid_work = Functions.validate_data(df=df, schema=self.schema, debug=True)
|
|
46
22
|
|
|
47
23
|
return valid_work, invalid_work
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: brynq_sdk_bob
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.8.2
|
|
4
4
|
Summary: Bob wrapper from BrynQ
|
|
5
5
|
Author: BrynQ
|
|
6
6
|
Author-email: support@brynq.com
|
|
7
7
|
License: BrynQ License
|
|
8
8
|
Requires-Dist: brynq-sdk-brynq<5,>=4
|
|
9
9
|
Requires-Dist: pandas<3.0.0,>=2.2.0
|
|
10
|
-
Requires-Dist: tenacity==8.2.3
|
|
11
10
|
Dynamic: author
|
|
12
11
|
Dynamic: author-email
|
|
13
12
|
Dynamic: description
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
brynq_sdk_bob/__init__.py,sha256=M2y-juQ-GgzglQa0HvbWmeA9fBzv5L3MShHbTfb9rsk,3014
|
|
2
|
+
brynq_sdk_bob/bank.py,sha256=zTdfe_qCZt2FB7SZbQ7njIDspwTinLFdbeH_xUby2FY,966
|
|
3
|
+
brynq_sdk_bob/company.py,sha256=rjOpkm0CZ1EeJ-jddBl36GrGKUQviC1ca1aUL2tl1_M,848
|
|
4
|
+
brynq_sdk_bob/custom_tables.py,sha256=MvnR2mIcyK0rpwd0P7xV3BPIvCYQVEClBvo901GttPs,2642
|
|
5
|
+
brynq_sdk_bob/documents.py,sha256=ww101owiBGARCxOANdDtmWrNedSBe9V-BEed6QspQPg,1756
|
|
6
|
+
brynq_sdk_bob/employment.py,sha256=uNllQrIBbo8yPG_2-ln1PWeWUFU672T289PpWWvL-V8,763
|
|
7
|
+
brynq_sdk_bob/named_lists.py,sha256=ksLXV2ysBFegq4gZiiaC56gjkgdnPzL7WajZTGvjYIM,1069
|
|
8
|
+
brynq_sdk_bob/payments.py,sha256=HVXoMyA0Jyhyk5EcgCU2OQfdbMtElhdLfdBKgI9xC4Q,3922
|
|
9
|
+
brynq_sdk_bob/payroll_history.py,sha256=wHo6da7kLDe1ViL4egyMdyJBMZnWVhwjNjmh4cTCTeY,3972
|
|
10
|
+
brynq_sdk_bob/people.py,sha256=t1A1dABX6UZ0pyLTGOL-Sp5pHY630KWIyIO3JQ_Pjdk,5970
|
|
11
|
+
brynq_sdk_bob/reports.py,sha256=fiYzd6037siGl6c4KQLE7F4CeFRRDVDgSIVcWVVWsvI,1209
|
|
12
|
+
brynq_sdk_bob/salaries.py,sha256=BGQm-PT9QuKKJ9DP5nX6wmC8SZRAlm9M9I2EJhoZaII,1523
|
|
13
|
+
brynq_sdk_bob/timeoff.py,sha256=NbBZ39qy9D7jbS_z9bpmB-BKNuUGmNrkYTbEw034tZ0,3339
|
|
14
|
+
brynq_sdk_bob/work.py,sha256=0bVZkQ0I6z-z2_ql-EsOpFExx8VgsJvpcCQdOfiJYQM,712
|
|
15
|
+
brynq_sdk_bob/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
16
|
+
brynq_sdk_bob/schemas/bank.py,sha256=lDmXP4P8091N20fL2CmhPU2wFuaK60Z-p-dvYSNCMaQ,1846
|
|
17
|
+
brynq_sdk_bob/schemas/custom_tables.py,sha256=638NH2n50vHzw1LFlbKVCBKBhfSsfGqtEGuor0Z-QS4,1567
|
|
18
|
+
brynq_sdk_bob/schemas/employment.py,sha256=KUGbT8hjYuQIN-3BGlIrBBswXT6fSPkLtn5blT19xkY,3219
|
|
19
|
+
brynq_sdk_bob/schemas/named_lists.py,sha256=HJBRKrAI2vhrkq-5MVXqQcmpGNzFtoOnaZI2Ii_6_vs,725
|
|
20
|
+
brynq_sdk_bob/schemas/payments.py,sha256=LrSr8WApYxqbMDmhYmh0EISEbWJinWovsULZV6sItG0,4290
|
|
21
|
+
brynq_sdk_bob/schemas/payroll_history.py,sha256=JdAq0XaArHHEw8EsXo3GD0EhSAyBhPtYQMmdvjCiY8g,806
|
|
22
|
+
brynq_sdk_bob/schemas/people.py,sha256=Zs58mO4i8M-u-DLWRS0IHbyDNiwrhxSxOX8t3mLr2fw,40150
|
|
23
|
+
brynq_sdk_bob/schemas/salary.py,sha256=TSaM1g92y3oiDcUrfJW7ushgKZenI9xB6XW3kKuU0dE,4540
|
|
24
|
+
brynq_sdk_bob/schemas/timeoff.py,sha256=uswH42djiiWE2H0wXKHoneDvOJQ5BlaIeNdNl-kYd-s,4117
|
|
25
|
+
brynq_sdk_bob/schemas/work.py,sha256=YgtBJ0WXJOq55bFlT_kY_IbHh0SlQEtaa0W8vms-xA4,3048
|
|
26
|
+
brynq_sdk_bob-2.8.2.dist-info/METADATA,sha256=ulFwB84MiNowHTx0EF7zGUwi1OxfoZt2qMlJWXexwOA,371
|
|
27
|
+
brynq_sdk_bob-2.8.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
28
|
+
brynq_sdk_bob-2.8.2.dist-info/top_level.txt,sha256=oGiWqOuAAiVoLIzGe6F-Lo4IJBYz5ftOwBft7HtPuoY,14
|
|
29
|
+
brynq_sdk_bob-2.8.2.dist-info/RECORD,,
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
brynq_sdk_bob/__init__.py,sha256=bw2Www_wgVxqZczJpz9K_94k7OdgqwWKF0aQaKG5TQE,3052
|
|
2
|
-
brynq_sdk_bob/bank.py,sha256=5ncWsmeAvNoiLnVvIvPgFDRQ5DB5_VY2ipMC439GVHU,1460
|
|
3
|
-
brynq_sdk_bob/company.py,sha256=rjOpkm0CZ1EeJ-jddBl36GrGKUQviC1ca1aUL2tl1_M,848
|
|
4
|
-
brynq_sdk_bob/custom_tables.py,sha256=MvnR2mIcyK0rpwd0P7xV3BPIvCYQVEClBvo901GttPs,2642
|
|
5
|
-
brynq_sdk_bob/documents.py,sha256=ww101owiBGARCxOANdDtmWrNedSBe9V-BEed6QspQPg,1756
|
|
6
|
-
brynq_sdk_bob/employment.py,sha256=kBEKfUmKEw-A_FjC9fOuJqcsT7NxUKwXJs_V_-x9LbI,765
|
|
7
|
-
brynq_sdk_bob/named_lists.py,sha256=ksLXV2ysBFegq4gZiiaC56gjkgdnPzL7WajZTGvjYIM,1069
|
|
8
|
-
brynq_sdk_bob/payments.py,sha256=e1TnJcXlbotOfULukVUiaYZ1N-bDGynAtmPgpux7It0,5670
|
|
9
|
-
brynq_sdk_bob/payroll_history.py,sha256=wHo6da7kLDe1ViL4egyMdyJBMZnWVhwjNjmh4cTCTeY,3972
|
|
10
|
-
brynq_sdk_bob/people.py,sha256=6b7uCucl_xqtAq_4YJZU457fUY0qssMwfCCStzbNG0M,5036
|
|
11
|
-
brynq_sdk_bob/salaries.py,sha256=8xq9XDTK473Az2MpuAPofz9CvZstjufSoWtF0bi1wC4,1766
|
|
12
|
-
brynq_sdk_bob/timeoff.py,sha256=NbBZ39qy9D7jbS_z9bpmB-BKNuUGmNrkYTbEw034tZ0,3339
|
|
13
|
-
brynq_sdk_bob/work.py,sha256=DzShGngMETPYP4TrMLm7pg6GmIft1rgBUZNyNFwxPsM,1488
|
|
14
|
-
brynq_sdk_bob/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
brynq_sdk_bob/schemas/bank.py,sha256=Yfq-ouzcAyaqcZj5_lWLcaQgtLikI9zlcsHhsuPUQzY,1935
|
|
16
|
-
brynq_sdk_bob/schemas/custom_tables.py,sha256=638NH2n50vHzw1LFlbKVCBKBhfSsfGqtEGuor0Z-QS4,1567
|
|
17
|
-
brynq_sdk_bob/schemas/employment.py,sha256=uErbSyl8xYaYo5Hu0FZ7_tl1WCOaytcU9pjkIWJbmOo,3226
|
|
18
|
-
brynq_sdk_bob/schemas/named_lists.py,sha256=HJBRKrAI2vhrkq-5MVXqQcmpGNzFtoOnaZI2Ii_6_vs,725
|
|
19
|
-
brynq_sdk_bob/schemas/payments.py,sha256=LiFff0YwmgFi-6vHau1iuX2RZb42ZGX5keGL_Ai5Jlk,4294
|
|
20
|
-
brynq_sdk_bob/schemas/payroll_history.py,sha256=JdAq0XaArHHEw8EsXo3GD0EhSAyBhPtYQMmdvjCiY8g,806
|
|
21
|
-
brynq_sdk_bob/schemas/people.py,sha256=cy0mLKRdUhjOv52WB53AWd1XHn6mwrACGZAvK2ufsz4,38780
|
|
22
|
-
brynq_sdk_bob/schemas/salary.py,sha256=7pq66_JfxmPbSWowX-25c-aKQvz3IGmoG5toRIq3H7g,4418
|
|
23
|
-
brynq_sdk_bob/schemas/timeoff.py,sha256=BHImTTT4n8j7bF7T5Ue_B0WHmmj1_QTPV9TKAlHeBZM,4124
|
|
24
|
-
brynq_sdk_bob/schemas/work.py,sha256=USjLR6vNhfCFb0Qul_A9cWru8wIzb370p5j1YxcDBFM,2804
|
|
25
|
-
brynq_sdk_bob-2.6.2.dev13.dist-info/METADATA,sha256=fRJIgqWg-8uyqcNIhnBNrMOlwqdD3OXvf5sX-wRUyWY,408
|
|
26
|
-
brynq_sdk_bob-2.6.2.dev13.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
27
|
-
brynq_sdk_bob-2.6.2.dev13.dist-info/top_level.txt,sha256=oGiWqOuAAiVoLIzGe6F-Lo4IJBYz5ftOwBft7HtPuoY,14
|
|
28
|
-
brynq_sdk_bob-2.6.2.dev13.dist-info/RECORD,,
|
|
File without changes
|