brynq-sdk-bob 2.9.6__py3-none-any.whl → 2.10.1__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 +3 -4
- brynq_sdk_bob/bank.py +7 -7
- brynq_sdk_bob/company.py +4 -4
- brynq_sdk_bob/custom_tables.py +8 -8
- brynq_sdk_bob/documents.py +7 -17
- brynq_sdk_bob/employment.py +8 -7
- brynq_sdk_bob/entitlements.py +37 -0
- brynq_sdk_bob/named_lists.py +8 -9
- brynq_sdk_bob/payments.py +14 -13
- brynq_sdk_bob/payroll_history.py +16 -17
- brynq_sdk_bob/people.py +15 -16
- brynq_sdk_bob/reports.py +17 -14
- brynq_sdk_bob/salaries.py +12 -12
- brynq_sdk_bob/schemas/bank.py +2 -2
- brynq_sdk_bob/schemas/custom_tables.py +2 -2
- brynq_sdk_bob/schemas/employment.py +9 -9
- brynq_sdk_bob/schemas/entitlements.py +110 -0
- brynq_sdk_bob/schemas/named_lists.py +1 -1
- brynq_sdk_bob/schemas/payments.py +3 -2
- brynq_sdk_bob/schemas/payroll_history.py +1 -1
- brynq_sdk_bob/schemas/people.py +1 -1
- brynq_sdk_bob/schemas/reports.py +129 -0
- brynq_sdk_bob/schemas/salary.py +3 -4
- brynq_sdk_bob/schemas/timeoff.py +2 -2
- brynq_sdk_bob/schemas/work.py +1 -1
- brynq_sdk_bob/timeoff.py +13 -13
- brynq_sdk_bob/work.py +8 -7
- {brynq_sdk_bob-2.9.6.dist-info → brynq_sdk_bob-2.10.1.dist-info}/METADATA +4 -1
- brynq_sdk_bob-2.10.1.dist-info/RECORD +32 -0
- {brynq_sdk_bob-2.9.6.dist-info → brynq_sdk_bob-2.10.1.dist-info}/WHEEL +1 -1
- brynq_sdk_bob-2.9.6.dist-info/RECORD +0 -29
- {brynq_sdk_bob-2.9.6.dist-info → brynq_sdk_bob-2.10.1.dist-info}/top_level.txt +0 -0
brynq_sdk_bob/__init__.py
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import base64
|
|
2
2
|
import os
|
|
3
3
|
from typing import List, Literal, Optional
|
|
4
|
-
|
|
5
4
|
import requests
|
|
6
5
|
from requests.adapters import HTTPAdapter
|
|
7
6
|
from urllib3.util.retry import Retry
|
|
8
|
-
|
|
9
7
|
from brynq_sdk_brynq import BrynQ
|
|
10
|
-
|
|
11
8
|
from .bank import Bank
|
|
12
9
|
from .company import Company
|
|
13
|
-
from .custom_tables import CustomTables
|
|
14
10
|
from .documents import CustomDocuments
|
|
15
11
|
from .employment import Employment
|
|
16
12
|
from .named_lists import NamedLists
|
|
@@ -21,6 +17,8 @@ from .reports import Reports
|
|
|
21
17
|
from .salaries import Salaries
|
|
22
18
|
from .timeoff import TimeOff
|
|
23
19
|
from .work import Work
|
|
20
|
+
from .custom_tables import CustomTables
|
|
21
|
+
from .entitlements import Entitlements
|
|
24
22
|
|
|
25
23
|
|
|
26
24
|
class Bob(BrynQ):
|
|
@@ -57,6 +55,7 @@ class Bob(BrynQ):
|
|
|
57
55
|
self.custom_tables = CustomTables(self)
|
|
58
56
|
self.payroll_history = History(self)
|
|
59
57
|
self.reports = Reports(self)
|
|
58
|
+
self.entitlements = Entitlements(self)
|
|
60
59
|
self.data_interface_id = os.getenv("DATA_INTERFACE_ID")
|
|
61
60
|
self.debug = debug
|
|
62
61
|
|
brynq_sdk_bob/bank.py
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
from brynq_sdk_functions import Functions
|
|
3
|
-
from .schemas.bank import
|
|
3
|
+
from .schemas.bank import BankGet
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class Bank:
|
|
7
|
-
def __init__(self,
|
|
8
|
-
self.
|
|
9
|
-
self.schema =
|
|
7
|
+
def __init__(self, client):
|
|
8
|
+
self.client = client
|
|
9
|
+
self.schema = BankGet
|
|
10
10
|
|
|
11
|
-
def get(self, person_ids: pd.Series, field_selection: list[str] = []) ->
|
|
11
|
+
def get(self, person_ids: pd.Series, field_selection: list[str] = []) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
12
12
|
data = []
|
|
13
13
|
for person_id in person_ids:
|
|
14
|
-
resp = self.
|
|
14
|
+
resp = self.client.session.get(url=f"{self.client.base_url}people/{person_id}/bank-accounts", timeout=self.client.timeout)
|
|
15
15
|
resp.raise_for_status()
|
|
16
16
|
temp_data = resp.json()['values']
|
|
17
17
|
# when an employee has one or more bank accounts, the response is a list of dictionaries.
|
|
@@ -21,6 +21,6 @@ class Bank:
|
|
|
21
21
|
|
|
22
22
|
df = pd.DataFrame(data)
|
|
23
23
|
|
|
24
|
-
valid_banks, invalid_banks = Functions.validate_data(df=df, schema=
|
|
24
|
+
valid_banks, invalid_banks = Functions.validate_data(df=df, schema=BankGet, debug=True)
|
|
25
25
|
|
|
26
26
|
return valid_banks, invalid_banks
|
brynq_sdk_bob/company.py
CHANGED
|
@@ -2,19 +2,19 @@ import pandas as pd
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class Company:
|
|
5
|
-
def __init__(self,
|
|
6
|
-
self.
|
|
5
|
+
def __init__(self, client):
|
|
6
|
+
self.client = client
|
|
7
7
|
|
|
8
8
|
def get_variable_values(self, list_name: str = None) -> dict:
|
|
9
9
|
values = {}
|
|
10
10
|
|
|
11
11
|
if list_name is not None:
|
|
12
|
-
resp = self.
|
|
12
|
+
resp = self.client.session.get(url=f"{self.client.base_url}company/named-lists/{list_name}", timeout=self.client.timeout)
|
|
13
13
|
resp.raise_for_status()
|
|
14
14
|
data = resp.json()
|
|
15
15
|
values.update({data["name"]: [value['id'] for value in data['values']]})
|
|
16
16
|
else:
|
|
17
|
-
resp = self.
|
|
17
|
+
resp = self.client.session.get(url=f"{self.client.base_url}company/named-lists", timeout=self.client.timeout)
|
|
18
18
|
resp.raise_for_status()
|
|
19
19
|
data = resp.json()
|
|
20
20
|
for list_key, list_data in data.items():
|
brynq_sdk_bob/custom_tables.py
CHANGED
|
@@ -4,13 +4,13 @@ import pandas as pd
|
|
|
4
4
|
|
|
5
5
|
from brynq_sdk_functions import BrynQPanderaDataFrameModel, Functions
|
|
6
6
|
|
|
7
|
-
from .schemas.custom_tables import
|
|
7
|
+
from .schemas.custom_tables import CustomTableMetadataGet, CustomTableGet
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class CustomTables:
|
|
11
|
-
def __init__(self,
|
|
12
|
-
self.
|
|
13
|
-
self.schema =
|
|
11
|
+
def __init__(self, client):
|
|
12
|
+
self.client = client
|
|
13
|
+
self.schema = CustomTableGet
|
|
14
14
|
|
|
15
15
|
def get(self, employee_ids: List[str], custom_table_id: str, schema_custom_fields: Optional[BrynQPanderaDataFrameModel] = None) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
16
16
|
"""
|
|
@@ -26,7 +26,7 @@ class CustomTables:
|
|
|
26
26
|
"""
|
|
27
27
|
df = pd.DataFrame()
|
|
28
28
|
for employee_id in employee_ids:
|
|
29
|
-
resp = self.
|
|
29
|
+
resp = self.client.session.get(url=f"{self.client.base_url}people/custom-tables/{employee_id}/{custom_table_id}", timeout=self.client.timeout)
|
|
30
30
|
resp.raise_for_status()
|
|
31
31
|
data = resp.json()
|
|
32
32
|
|
|
@@ -53,8 +53,8 @@ class CustomTables:
|
|
|
53
53
|
Returns:
|
|
54
54
|
A tuple of (valid_data, invalid_data) as pandas DataFrames containing table and column metadata
|
|
55
55
|
"""
|
|
56
|
-
url = f"{self.
|
|
57
|
-
resp = self.
|
|
56
|
+
url = f"{self.client.base_url}people/custom-tables/metadata"
|
|
57
|
+
resp = self.client.session.get(url=url)
|
|
58
58
|
resp.raise_for_status()
|
|
59
59
|
data = resp.json()
|
|
60
60
|
|
|
@@ -82,6 +82,6 @@ class CustomTables:
|
|
|
82
82
|
df = pd.DataFrame(rows)
|
|
83
83
|
|
|
84
84
|
# Validate against the metadata schema
|
|
85
|
-
valid_data, invalid_data = Functions.validate_data(df=df, schema=
|
|
85
|
+
valid_data, invalid_data = Functions.validate_data(df=df, schema=CustomTableMetadataGet, debug=True)
|
|
86
86
|
|
|
87
87
|
return valid_data, invalid_data
|
brynq_sdk_bob/documents.py
CHANGED
|
@@ -6,30 +6,20 @@ from brynq_sdk_functions import Functions
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class CustomDocuments:
|
|
9
|
-
def __init__(self,
|
|
10
|
-
self.
|
|
11
|
-
# self.headers_upload = self.bob.headers.copy()
|
|
12
|
-
# self.headers_upload['Content-Type'] = 'multipart/form-data'
|
|
13
|
-
# self.headers_upload['Accept'] = 'application/json'
|
|
9
|
+
def __init__(self, client):
|
|
10
|
+
self.client = client
|
|
14
11
|
|
|
15
12
|
def get(self, person_id: datetime) -> pd.DataFrame:
|
|
16
|
-
resp = self.
|
|
13
|
+
resp = self.client.session.get(url=f"{self.client.base_url}docs/people/{person_id}", timeout=self.client.timeout)
|
|
17
14
|
resp.raise_for_status()
|
|
18
15
|
data = resp.json()['documents']
|
|
19
16
|
df = pd.DataFrame(data)
|
|
20
|
-
|
|
21
|
-
# df = pd.json_normalize(
|
|
22
|
-
# data,
|
|
23
|
-
# record_path='changes',
|
|
24
|
-
# meta=['employeeId']
|
|
25
|
-
# )
|
|
26
|
-
df = self.bob.rename_camel_columns_to_snake_case(df)
|
|
27
|
-
# valid_documents, invalid_documents = Functions.validate_data(df=df, schema=DocumentsSchema, debug=True)
|
|
17
|
+
df = self.client.rename_camel_columns_to_snake_case(df)
|
|
28
18
|
|
|
29
19
|
return df
|
|
30
20
|
|
|
31
21
|
def get_folders(self) -> dict:
|
|
32
|
-
resp = self.
|
|
22
|
+
resp = self.client.session.get(url=f"{self.client.base_url}docs/folders/metadata", timeout=self.client.timeout)
|
|
33
23
|
resp.raise_for_status()
|
|
34
24
|
data = resp.json()
|
|
35
25
|
|
|
@@ -41,7 +31,7 @@ class CustomDocuments:
|
|
|
41
31
|
file_name: str,
|
|
42
32
|
file_object: BytesIO):
|
|
43
33
|
files = {"file": (file_name, file_object, "application/pdf")}
|
|
44
|
-
resp = self.
|
|
34
|
+
resp = self.client.session.post(url=f"{self.client.base_url}docs/people/{person_id}/folders/{folder_id}/upload",
|
|
45
35
|
files=files,
|
|
46
|
-
timeout=self.
|
|
36
|
+
timeout=self.client.timeout)
|
|
47
37
|
resp.raise_for_status()
|
brynq_sdk_bob/employment.py
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
import requests
|
|
3
|
-
from .schemas.employment import
|
|
3
|
+
from .schemas.employment import EmploymentGet
|
|
4
4
|
from brynq_sdk_functions import Functions
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class Employment:
|
|
8
|
-
def __init__(self,
|
|
9
|
-
self.
|
|
10
|
-
self.schema =
|
|
8
|
+
def __init__(self, client):
|
|
9
|
+
self.client = client
|
|
10
|
+
self.schema = EmploymentGet
|
|
11
11
|
|
|
12
|
-
def get(self) ->
|
|
12
|
+
def get(self) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
13
13
|
request = requests.Request(method='GET',
|
|
14
|
-
url=f"{self.
|
|
15
|
-
|
|
14
|
+
url=f"{self.client.base_url}bulk/people/employment",
|
|
15
|
+
params={"includeArchived": "true"})
|
|
16
|
+
data = self.client.get_paginated_result(request)
|
|
16
17
|
df = pd.json_normalize(
|
|
17
18
|
data,
|
|
18
19
|
record_path='values',
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from typing import Tuple
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from brynq_sdk_functions import Functions
|
|
4
|
+
from brynq_sdk_bob.schemas.entitlements import EntitlementReportGet
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Entitlements:
|
|
8
|
+
def __init__(self, client):
|
|
9
|
+
self.client = client
|
|
10
|
+
|
|
11
|
+
def get(self, report_id: str | None = None, debug: bool = False) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
12
|
+
"""
|
|
13
|
+
Get entitlement history data from the Bob reports.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
report_id: Optional report ID. If not provided, will search for 'Entitlement history' report.
|
|
17
|
+
debug: Whether to print debug information.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Tuple of (valid_entitlements, invalid_entitlements) DataFrames
|
|
21
|
+
"""
|
|
22
|
+
reports_df, _ = self.client.reports.get()
|
|
23
|
+
if report_id is None:
|
|
24
|
+
entitlement_report = reports_df[reports_df['name'] == 'Entitlement history']
|
|
25
|
+
if entitlement_report.empty:
|
|
26
|
+
raise ValueError("Report 'Entitlement history' not found.")
|
|
27
|
+
report_id = entitlement_report['id'].iloc[0]
|
|
28
|
+
|
|
29
|
+
report_data = self.client.reports.download(report_id=report_id)
|
|
30
|
+
df_raw = pd.json_normalize(report_data, record_path='employees')
|
|
31
|
+
valid_entitlements, invalid_entitlements = Functions.validate_data(
|
|
32
|
+
df=df_raw,
|
|
33
|
+
schema=EntitlementReportGet,
|
|
34
|
+
debug=debug,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
return valid_entitlements, invalid_entitlements
|
brynq_sdk_bob/named_lists.py
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
2
|
import pandas as pd
|
|
3
3
|
from brynq_sdk_functions import Functions
|
|
4
|
-
from .schemas.named_lists import
|
|
4
|
+
from .schemas.named_lists import NamedListGet
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class NamedLists:
|
|
8
|
-
def __init__(self,
|
|
9
|
-
self.
|
|
10
|
-
self.schema =
|
|
8
|
+
def __init__(self, client):
|
|
9
|
+
self.client = client
|
|
10
|
+
self.schema = NamedListGet
|
|
11
11
|
|
|
12
|
-
def get(self) ->
|
|
12
|
+
def get(self) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
13
13
|
"""
|
|
14
14
|
Get custom table data for an employee
|
|
15
15
|
|
|
@@ -19,8 +19,8 @@ class NamedLists:
|
|
|
19
19
|
Returns:
|
|
20
20
|
A tuple of (valid_data, invalid_data) as pandas DataFrames
|
|
21
21
|
"""
|
|
22
|
-
url = f"{self.
|
|
23
|
-
resp = self.
|
|
22
|
+
url = f"{self.client.base_url}company/named-lists/"
|
|
23
|
+
resp = self.client.session.get(url=url)
|
|
24
24
|
resp.raise_for_status()
|
|
25
25
|
data = resp.json()
|
|
26
26
|
|
|
@@ -31,7 +31,6 @@ class NamedLists:
|
|
|
31
31
|
])
|
|
32
32
|
|
|
33
33
|
# Normalize the nested JSON response
|
|
34
|
-
|
|
35
|
-
valid_data, invalid_data = Functions.validate_data(df=df, schema=NamedListSchema, debug=True)
|
|
34
|
+
valid_data, invalid_data = Functions.validate_data(df=df, schema=NamedListGet, debug=True)
|
|
36
35
|
|
|
37
36
|
return valid_data, invalid_data
|
brynq_sdk_bob/payments.py
CHANGED
|
@@ -5,24 +5,25 @@ import pandas as pd
|
|
|
5
5
|
|
|
6
6
|
from brynq_sdk_functions import Functions
|
|
7
7
|
|
|
8
|
-
from .schemas.payments import
|
|
8
|
+
from .schemas.payments import ActualPaymentsGet, VariablePaymentGet
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
class Payments:
|
|
12
|
-
def __init__(self,
|
|
13
|
-
self.
|
|
14
|
-
self.schema =
|
|
12
|
+
def __init__(self, client):
|
|
13
|
+
self.client = client
|
|
14
|
+
self.schema = VariablePaymentGet
|
|
15
15
|
|
|
16
|
-
def get(self, person_ids: List[str]) ->
|
|
16
|
+
def get(self, person_ids: List[str]) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
17
17
|
records = []
|
|
18
18
|
|
|
19
19
|
for person_id in person_ids:
|
|
20
20
|
# Throttle requests to respect API rate limits
|
|
21
21
|
time.sleep(0.2)
|
|
22
22
|
|
|
23
|
-
resp = self.
|
|
24
|
-
url=f"{self.
|
|
25
|
-
timeout=self.
|
|
23
|
+
resp = self.client.session.get(
|
|
24
|
+
url=f"{self.client.base_url}people/{person_id}/variable",
|
|
25
|
+
timeout=self.client.timeout,
|
|
26
|
+
params={"includeArchived": "true"}
|
|
26
27
|
)
|
|
27
28
|
resp.raise_for_status()
|
|
28
29
|
|
|
@@ -46,7 +47,7 @@ class Payments:
|
|
|
46
47
|
employee_ids: Optional[List[str]] = None,
|
|
47
48
|
pay_date_from: Optional[str] = None,
|
|
48
49
|
pay_date_to: Optional[str] = None
|
|
49
|
-
) ->
|
|
50
|
+
) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
50
51
|
"""
|
|
51
52
|
Search for actual payments with optional employee and pay date filters.
|
|
52
53
|
This method auto-paginates until all results are fetched.
|
|
@@ -101,10 +102,10 @@ class Payments:
|
|
|
101
102
|
if next_cursor:
|
|
102
103
|
payload["pagination"]["cursor"] = next_cursor
|
|
103
104
|
|
|
104
|
-
resp = self.
|
|
105
|
-
url=f"{self.
|
|
105
|
+
resp = self.client.session.post(
|
|
106
|
+
url=f"{self.client.base_url}people/actual-payments/search",
|
|
106
107
|
json=payload,
|
|
107
|
-
timeout=self.
|
|
108
|
+
timeout=self.client.timeout
|
|
108
109
|
)
|
|
109
110
|
resp.raise_for_status()
|
|
110
111
|
data = resp.json()
|
|
@@ -125,7 +126,7 @@ class Payments:
|
|
|
125
126
|
|
|
126
127
|
valid_payments, invalid_payments = Functions.validate_data(
|
|
127
128
|
df=df,
|
|
128
|
-
schema=
|
|
129
|
+
schema=ActualPaymentsGet,
|
|
129
130
|
debug=True
|
|
130
131
|
)
|
|
131
132
|
|
brynq_sdk_bob/payroll_history.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
from brynq_sdk_functions import Functions
|
|
3
|
-
from .schemas.people import
|
|
3
|
+
from .schemas.people import PeopleGet
|
|
4
4
|
|
|
5
5
|
class History:
|
|
6
|
-
def __init__(self,
|
|
7
|
-
self.
|
|
8
|
-
self.schema =
|
|
6
|
+
def __init__(self, client):
|
|
7
|
+
self.client = client
|
|
8
|
+
self.schema = PeopleGet
|
|
9
9
|
self.field_name_in_body, self.field_name_in_response, self.endpoint_to_response = self._init_fields()
|
|
10
10
|
|
|
11
11
|
def get(self, additional_fields: list[str] = [], field_selection: list[str] = []) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
@@ -16,7 +16,6 @@ class History:
|
|
|
16
16
|
additional_fields (list[str]): Additional fields to get (not defined in the schema)
|
|
17
17
|
field_selection (list[str]): Fields to get (defined in the schema), if not provided, all fields are returned
|
|
18
18
|
"""
|
|
19
|
-
#resp = self.bob.session.get(url=f"{self.bob.base_url}profiles", timeout=self.bob.timeout)
|
|
20
19
|
body_fields = list(set(self.field_name_in_body + additional_fields))
|
|
21
20
|
response_fields = list(set(self.field_name_in_response + additional_fields))
|
|
22
21
|
|
|
@@ -25,25 +24,25 @@ class History:
|
|
|
25
24
|
response_fields = [self.endpoint_to_response.get(field) for field in field_selection if field in self.endpoint_to_response]
|
|
26
25
|
|
|
27
26
|
# Bob sucks with default fields so you need to do a search call to retrieve additional fields.
|
|
28
|
-
resp_additional_fields = self.
|
|
27
|
+
resp_additional_fields = self.client.session.post(url=f"{self.client.base_url}people/search",
|
|
29
28
|
json={
|
|
30
29
|
"fields": body_fields,
|
|
31
30
|
"filters": []
|
|
32
31
|
},
|
|
33
|
-
timeout=self.
|
|
32
|
+
timeout=self.client.timeout)
|
|
34
33
|
json_response = resp_additional_fields.json()
|
|
35
34
|
df = pd.json_normalize(resp_additional_fields.json()['employees'])
|
|
36
35
|
df = df[[col for col in response_fields if col in df.columns]]
|
|
37
|
-
# Get the valid column names from
|
|
38
|
-
valid_people, invalid_people = Functions.validate_data(df=df, schema=
|
|
36
|
+
# Get the valid column names from PeopleGet
|
|
37
|
+
valid_people, invalid_people = Functions.validate_data(df=df, schema=PeopleGet, debug=True)
|
|
39
38
|
return valid_people, invalid_people
|
|
40
39
|
|
|
41
40
|
|
|
42
41
|
def _init_fields(self) -> tuple[list[str], list[str], dict[str, str]]:
|
|
43
|
-
resp_fields = self.
|
|
44
|
-
url=f"{self.
|
|
45
|
-
timeout=self.
|
|
46
|
-
headers=self.
|
|
42
|
+
resp_fields = self.client.session.get(
|
|
43
|
+
url=f"{self.client.base_url}company/people/fields",
|
|
44
|
+
timeout=self.client.timeout,
|
|
45
|
+
headers=self.client.headers
|
|
47
46
|
)
|
|
48
47
|
fields = resp_fields.json()
|
|
49
48
|
field_name_in_body = [field.get('id') for field in fields]
|
|
@@ -58,14 +57,14 @@ class History:
|
|
|
58
57
|
body_fields = [employee_id_in_company, person_id]
|
|
59
58
|
response_fields = [self.endpoint_to_response.get(field) for field in body_fields if field in self.endpoint_to_response]
|
|
60
59
|
|
|
61
|
-
resp_additional_fields = self.
|
|
60
|
+
resp_additional_fields = self.client.session.post(url=f"{self.client.base_url}people/search",
|
|
62
61
|
json={
|
|
63
62
|
"fields": body_fields,
|
|
64
63
|
"filters": []
|
|
65
64
|
},
|
|
66
|
-
timeout=self.
|
|
65
|
+
timeout=self.client.timeout)
|
|
67
66
|
df = pd.json_normalize(resp_additional_fields.json()['employees'])
|
|
68
67
|
df = df[[col for col in response_fields if col in df.columns]]
|
|
69
|
-
# Get the valid column names from
|
|
70
|
-
valid_people, invalid_people = Functions.validate_data(df=df, schema=
|
|
68
|
+
# Get the valid column names from PeopleGet
|
|
69
|
+
valid_people, invalid_people = Functions.validate_data(df=df, schema=PeopleGet, debug=True)
|
|
71
70
|
return valid_people, invalid_people
|
brynq_sdk_bob/people.py
CHANGED
|
@@ -9,19 +9,19 @@ from .bank import Bank
|
|
|
9
9
|
from .custom_tables import CustomTables
|
|
10
10
|
from .employment import Employment
|
|
11
11
|
from .salaries import Salaries
|
|
12
|
-
from .schemas.people import
|
|
12
|
+
from .schemas.people import PeopleGet
|
|
13
13
|
from .work import Work
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class People:
|
|
17
|
-
def __init__(self,
|
|
18
|
-
self.
|
|
19
|
-
self.salaries = Salaries(
|
|
20
|
-
self.employment = Employment(
|
|
21
|
-
self.bank = Bank(
|
|
22
|
-
self.work = Work(
|
|
23
|
-
self.custom_tables = CustomTables(
|
|
24
|
-
self.schema =
|
|
17
|
+
def __init__(self, client):
|
|
18
|
+
self.client = client
|
|
19
|
+
self.salaries = Salaries(client)
|
|
20
|
+
self.employment = Employment(client)
|
|
21
|
+
self.bank = Bank(client)
|
|
22
|
+
self.work = Work(client)
|
|
23
|
+
self.custom_tables = CustomTables(client)
|
|
24
|
+
self.schema = PeopleGet
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
|
|
@@ -33,19 +33,18 @@ class People:
|
|
|
33
33
|
for col_name, col in schema.columns.items()
|
|
34
34
|
]
|
|
35
35
|
|
|
36
|
-
def get(self, schema_custom_fields: Optional[BrynQPanderaDataFrameModel] = None) -> pd.DataFrame:
|
|
36
|
+
def get(self, schema_custom_fields: Optional[BrynQPanderaDataFrameModel] = None) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
37
37
|
|
|
38
|
-
core_fields = self.__build_api_fields(
|
|
38
|
+
core_fields = self.__build_api_fields(PeopleGet)
|
|
39
39
|
custom_fields = self.__build_api_fields(schema_custom_fields) if schema_custom_fields is not None else []
|
|
40
40
|
fields = core_fields + custom_fields
|
|
41
41
|
|
|
42
|
-
resp = self.
|
|
42
|
+
resp = self.client.session.post(url=f"{self.client.base_url}people/search",
|
|
43
43
|
json={
|
|
44
44
|
"fields": fields,
|
|
45
45
|
"filters": []
|
|
46
|
-
#"humanReadable": "REPLACE"
|
|
47
46
|
},
|
|
48
|
-
timeout=self.
|
|
47
|
+
timeout=self.client.timeout)
|
|
49
48
|
resp.raise_for_status()
|
|
50
49
|
df = pd.json_normalize(resp.json()['employees'])
|
|
51
50
|
|
|
@@ -72,7 +71,7 @@ class People:
|
|
|
72
71
|
|
|
73
72
|
|
|
74
73
|
# 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.
|
|
75
|
-
resp_named_lists = self.
|
|
74
|
+
resp_named_lists = self.client.session.get(url=f"{self.client.base_url}company/named-lists", timeout=self.client.timeout, headers=self.client.headers)
|
|
76
75
|
named_lists = resp_named_lists.json()
|
|
77
76
|
|
|
78
77
|
# Transform named_lists to create id-to-value mappings for each field
|
|
@@ -102,7 +101,7 @@ class People:
|
|
|
102
101
|
invalid_people_custom = pd.DataFrame()
|
|
103
102
|
|
|
104
103
|
|
|
105
|
-
valid_people, invalid_people = Functions.validate_data(df=valid_people, schema=
|
|
104
|
+
valid_people, invalid_people = Functions.validate_data(df=valid_people, schema=PeopleGet, debug=True)
|
|
106
105
|
|
|
107
106
|
# For columns ending with .value.value, use fillna to fill the corresponding base column since that's not done automatically
|
|
108
107
|
def _normalize_key(key: str) -> str:
|
brynq_sdk_bob/reports.py
CHANGED
|
@@ -1,38 +1,41 @@
|
|
|
1
|
-
from
|
|
2
|
-
from io import BytesIO
|
|
3
|
-
from typing import Optional, TYPE_CHECKING
|
|
1
|
+
from typing import Literal, TYPE_CHECKING
|
|
4
2
|
|
|
5
3
|
import pandas as pd
|
|
6
4
|
from brynq_sdk_functions import Functions
|
|
5
|
+
from brynq_sdk_bob.schemas.reports import ReportGet
|
|
7
6
|
if TYPE_CHECKING:
|
|
8
7
|
from brynq_sdk_bob import Bob
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
class Reports:
|
|
12
|
-
def __init__(self,
|
|
13
|
-
self.
|
|
11
|
+
def __init__(self, client):
|
|
12
|
+
self.client: Bob = client
|
|
14
13
|
|
|
15
|
-
def get(self) -> pd.DataFrame:
|
|
16
|
-
resp = self.
|
|
14
|
+
def get(self) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
15
|
+
resp = self.client.session.get(url=f"{self.client.base_url}company/reports", timeout=self.client.timeout)
|
|
17
16
|
resp.raise_for_status()
|
|
18
17
|
data = resp.json()
|
|
19
18
|
df = pd.json_normalize(
|
|
20
19
|
data,
|
|
21
20
|
record_path='views'
|
|
22
21
|
)
|
|
23
|
-
|
|
24
|
-
# valid_documents, invalid_documents = Functions.validate_data(df=df, schema=DocumentsSchema, debug=True)
|
|
22
|
+
valid_reports, invalid_reports = Functions.validate_data(df=df, schema=ReportGet, debug=True)
|
|
25
23
|
|
|
26
|
-
return
|
|
24
|
+
return valid_reports, invalid_reports
|
|
27
25
|
|
|
28
|
-
def download(self, report_id: int | str = None, report_format:
|
|
26
|
+
def download(self, report_id: int | str = None, report_format: Literal["json", "csv"] = "json") -> dict | bytes:
|
|
29
27
|
if report_id:
|
|
30
|
-
url = f"{self.
|
|
28
|
+
url = f"{self.client.base_url}company/reports/{report_id}/download"
|
|
31
29
|
else:
|
|
32
30
|
raise ValueError("Either report_id or report_name must be provided")
|
|
33
31
|
|
|
34
|
-
resp = self.
|
|
32
|
+
resp = self.client.session.get(url=url, timeout=self.client.timeout, params={"format": report_format})
|
|
35
33
|
resp.raise_for_status()
|
|
36
|
-
|
|
34
|
+
if report_format == "json":
|
|
35
|
+
data = resp.json()
|
|
36
|
+
elif report_format == "csv":
|
|
37
|
+
data = resp.content
|
|
38
|
+
else:
|
|
39
|
+
raise ValueError(f"Invalid report format: {report_format}")
|
|
37
40
|
|
|
38
41
|
return data
|
brynq_sdk_bob/salaries.py
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
import requests
|
|
3
3
|
from brynq_sdk_functions import Functions
|
|
4
|
-
from .schemas.salary import
|
|
4
|
+
from .schemas.salary import SalaryGet, SalaryCreate
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class Salaries:
|
|
8
|
-
def __init__(self,
|
|
9
|
-
self.
|
|
10
|
-
self.schema =
|
|
8
|
+
def __init__(self, client):
|
|
9
|
+
self.client = client
|
|
10
|
+
self.schema = SalaryGet
|
|
11
11
|
|
|
12
12
|
def get(self) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
13
13
|
request = requests.Request(method='GET',
|
|
14
|
-
url=f"{self.
|
|
15
|
-
params={"limit": 100})
|
|
16
|
-
data = self.
|
|
14
|
+
url=f"{self.client.base_url}bulk/people/salaries",
|
|
15
|
+
params={"limit": 100, "includeArchived": "true"})
|
|
16
|
+
data = self.client.get_paginated_result(request)
|
|
17
17
|
df = pd.json_normalize(
|
|
18
18
|
data,
|
|
19
19
|
record_path='values',
|
|
20
20
|
meta=['employeeId']
|
|
21
21
|
)
|
|
22
|
-
valid_salaries, invalid_salaries = Functions.validate_data(df=df, schema=
|
|
22
|
+
valid_salaries, invalid_salaries = Functions.validate_data(df=df, schema=SalaryGet, debug=True)
|
|
23
23
|
|
|
24
24
|
return valid_salaries, invalid_salaries
|
|
25
25
|
|
|
26
26
|
def create(self, salary_data: dict) -> requests.Response:
|
|
27
|
-
nested_data = self.
|
|
28
|
-
salary_data =
|
|
27
|
+
nested_data = self.client.flat_dict_to_nested_dict(salary_data, SalaryCreate)
|
|
28
|
+
salary_data = SalaryCreate(**nested_data)
|
|
29
29
|
payload = salary_data.model_dump(exclude_none=True, by_alias=True)
|
|
30
30
|
|
|
31
|
-
resp = self.
|
|
31
|
+
resp = self.client.session.post(url=f"{self.client.base_url}people/{salary_data.employee_id}/salaries", json=payload)
|
|
32
32
|
resp.raise_for_status()
|
|
33
33
|
return resp
|
|
34
34
|
|
|
35
35
|
def delete(self, employee_id: str, salary_id: str) -> requests.Response:
|
|
36
|
-
resp = self.
|
|
36
|
+
resp = self.client.session.delete(url=f"{self.client.base_url}people/{employee_id}/salaries/{salary_id}")
|
|
37
37
|
resp.raise_for_status()
|
|
38
38
|
return resp
|
brynq_sdk_bob/schemas/bank.py
CHANGED
|
@@ -4,9 +4,9 @@ import pandas as pd
|
|
|
4
4
|
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
class
|
|
7
|
+
class BankGet(BrynQPanderaDataFrameModel):
|
|
8
8
|
id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Bank ID", alias="id")
|
|
9
|
-
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="
|
|
9
|
+
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employee_id")
|
|
10
10
|
amount: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Amount", alias="amount")
|
|
11
11
|
allocation: Series[String] = pa.Field(coerce=True, nullable=True, description="Allocation", alias="allocation")
|
|
12
12
|
branch_address: Series[String] = pa.Field(coerce=True, nullable=True, description="Branch Address", alias="branchAddress")
|
|
@@ -3,13 +3,13 @@ from pandera.typing import Series
|
|
|
3
3
|
import pandas as pd
|
|
4
4
|
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
5
5
|
|
|
6
|
-
class
|
|
6
|
+
class CustomTableGet(BrynQPanderaDataFrameModel):
|
|
7
7
|
id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Custom Table ID", alias="id")
|
|
8
8
|
employee_id: Series[str] = pa.Field(coerce=True, description="Employee ID", alias="employee_id")
|
|
9
9
|
|
|
10
10
|
class Config:
|
|
11
11
|
coerce = True
|
|
12
|
-
class
|
|
12
|
+
class CustomTableMetadataGet(BrynQPanderaDataFrameModel):
|
|
13
13
|
# Table information
|
|
14
14
|
table_id: Series[str] = pa.Field(coerce=True, description="Table ID", alias="table_id")
|
|
15
15
|
table_name: Series[str] = pa.Field(coerce=True, description="Table Name", alias="table_name")
|
|
@@ -5,7 +5,7 @@ from pandera import Bool
|
|
|
5
5
|
from pandera.typing import Series, String, Float, DateTime
|
|
6
6
|
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
7
7
|
|
|
8
|
-
class
|
|
8
|
+
class EmploymentGet(BrynQPanderaDataFrameModel):
|
|
9
9
|
id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Employment ID", alias="id")
|
|
10
10
|
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
11
11
|
active_effective_date: Series[DateTime] = pa.Field(coerce=True, description="Active Effective Date", alias="activeEffectiveDate")
|
|
@@ -19,14 +19,14 @@ class EmploymentSchema(BrynQPanderaDataFrameModel):
|
|
|
19
19
|
salary_pay_type: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Salary Pay Type", alias="salaryPayType")
|
|
20
20
|
weekly_hours: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Weekly Hours", alias="weeklyHours")
|
|
21
21
|
# weekly_hours_sort_factor: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=False)
|
|
22
|
-
actual_working_pattern_working_pattern_type: Optional[Series[pa.String]] = pa.Field(nullable=True, description="Actual Working Pattern Working Pattern Type", alias="actualWorkingPattern.workingPatternType")
|
|
23
|
-
actual_working_pattern_days_sunday: Optional[Series[Float]] = pa.Field(nullable=True, description="Actual Working Pattern Days Sunday", alias="actualWorkingPattern.days.sunday")
|
|
24
|
-
actual_working_pattern_days_tuesday: Optional[Series[Float]] = pa.Field(nullable=True, description="Actual Working Pattern Days Tuesday", alias="actualWorkingPattern.days.tuesday")
|
|
25
|
-
actual_working_pattern_days_wednesday: Optional[Series[Float]] = pa.Field(nullable=True, description="Actual Working Pattern Days Wednesday", alias="actualWorkingPattern.days.wednesday")
|
|
26
|
-
actual_working_pattern_days_monday: Optional[Series[Float]] = pa.Field(nullable=True, description="Actual Working Pattern Days Monday", alias="actualWorkingPattern.days.monday")
|
|
27
|
-
actual_working_pattern_days_friday: Optional[Series[Float]] = pa.Field(nullable=True, description="Actual Working Pattern Days Friday", alias="actualWorkingPattern.days.friday")
|
|
28
|
-
actual_working_pattern_days_thursday: Optional[Series[Float]] = pa.Field(nullable=True, description="Actual Working Pattern Days Thursday", alias="actualWorkingPattern.days.thursday")
|
|
29
|
-
actual_working_pattern_days_saturday: Optional[Series[Float]] = pa.Field(nullable=True, description="Actual Working Pattern Days Saturday", alias="actualWorkingPattern.days.saturday")
|
|
22
|
+
actual_working_pattern_working_pattern_type: Optional[Series[pa.String]] = pa.Field(coerce=True, nullable=True, description="Actual Working Pattern Working Pattern Type", alias="actualWorkingPattern.workingPatternType")
|
|
23
|
+
actual_working_pattern_days_sunday: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Actual Working Pattern Days Sunday", alias="actualWorkingPattern.days.sunday")
|
|
24
|
+
actual_working_pattern_days_tuesday: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Actual Working Pattern Days Tuesday", alias="actualWorkingPattern.days.tuesday")
|
|
25
|
+
actual_working_pattern_days_wednesday: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Actual Working Pattern Days Wednesday", alias="actualWorkingPattern.days.wednesday")
|
|
26
|
+
actual_working_pattern_days_monday: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Actual Working Pattern Days Monday", alias="actualWorkingPattern.days.monday")
|
|
27
|
+
actual_working_pattern_days_friday: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Actual Working Pattern Days Friday", alias="actualWorkingPattern.days.friday")
|
|
28
|
+
actual_working_pattern_days_thursday: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Actual Working Pattern Days Thursday", alias="actualWorkingPattern.days.thursday")
|
|
29
|
+
actual_working_pattern_days_saturday: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Actual Working Pattern Days Saturday", alias="actualWorkingPattern.days.saturday")
|
|
30
30
|
|
|
31
31
|
class Config:
|
|
32
32
|
coerce = True
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import pandera as pa
|
|
2
|
+
from typing import Optional
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class EntitlementReportGet(BrynQPanderaDataFrameModel):
|
|
8
|
+
surname: Optional[pd.StringDtype] = pa.Field(
|
|
9
|
+
coerce=True,
|
|
10
|
+
nullable=True,
|
|
11
|
+
description="Employee surname",
|
|
12
|
+
alias="surname",
|
|
13
|
+
)
|
|
14
|
+
first_name: Optional[pd.StringDtype] = pa.Field(
|
|
15
|
+
coerce=True,
|
|
16
|
+
nullable=True,
|
|
17
|
+
description="Employee first name",
|
|
18
|
+
alias="firstName",
|
|
19
|
+
)
|
|
20
|
+
employee_id: pd.StringDtype = pa.Field(
|
|
21
|
+
coerce=True,
|
|
22
|
+
description="Employee identifier",
|
|
23
|
+
alias="id",
|
|
24
|
+
)
|
|
25
|
+
entitlement_name: pd.StringDtype = pa.Field(
|
|
26
|
+
coerce=True,
|
|
27
|
+
description="Entitlement name",
|
|
28
|
+
alias="payroll.entitlement.entitlement",
|
|
29
|
+
)
|
|
30
|
+
entitlement_is_current: pd.BooleanDtype = pa.Field(
|
|
31
|
+
coerce=True,
|
|
32
|
+
description="Whether entitlement is current",
|
|
33
|
+
alias="payroll.entitlement.isCurrent",
|
|
34
|
+
)
|
|
35
|
+
entitlement_end_date: Optional[str] = pa.Field(
|
|
36
|
+
coerce=True,
|
|
37
|
+
nullable=True,
|
|
38
|
+
description="Entitlement end date",
|
|
39
|
+
alias="payroll.entitlement.endDate",
|
|
40
|
+
)
|
|
41
|
+
entitlement_can_be_deleted: pd.BooleanDtype = pa.Field(
|
|
42
|
+
coerce=True,
|
|
43
|
+
description="Whether entitlement can be deleted",
|
|
44
|
+
alias="payroll.entitlement.canBeDeleted",
|
|
45
|
+
)
|
|
46
|
+
entitlement_amount_value: Optional[pd.Float64Dtype] = pa.Field(
|
|
47
|
+
coerce=True,
|
|
48
|
+
nullable=True,
|
|
49
|
+
description="Entitlement amount value",
|
|
50
|
+
alias="payroll.entitlement.amount.value",
|
|
51
|
+
)
|
|
52
|
+
entitlement_amount_currency: Optional[pd.StringDtype] = pa.Field(
|
|
53
|
+
coerce=True,
|
|
54
|
+
nullable=True,
|
|
55
|
+
description="Entitlement currency",
|
|
56
|
+
alias="payroll.entitlement.amount.currency",
|
|
57
|
+
)
|
|
58
|
+
entitlement_end_effective_date: Optional[str] = pa.Field(
|
|
59
|
+
coerce=True,
|
|
60
|
+
nullable=True,
|
|
61
|
+
description="Entitlement end effective date",
|
|
62
|
+
alias="payroll.entitlement.endEffectiveDate",
|
|
63
|
+
)
|
|
64
|
+
entitlement_change_reason: Optional[pd.StringDtype] = pa.Field(
|
|
65
|
+
coerce=True,
|
|
66
|
+
nullable=True,
|
|
67
|
+
description="Reason for change",
|
|
68
|
+
alias="payroll.entitlement.change.reason",
|
|
69
|
+
)
|
|
70
|
+
entitlement_change_changed_by: Optional[pd.StringDtype] = pa.Field(
|
|
71
|
+
coerce=True,
|
|
72
|
+
nullable=True,
|
|
73
|
+
description="User that changed the entitlement",
|
|
74
|
+
alias="payroll.entitlement.change.changedBy",
|
|
75
|
+
)
|
|
76
|
+
entitlement_change_changed_by_id: Optional[pd.StringDtype] = pa.Field(
|
|
77
|
+
coerce=True,
|
|
78
|
+
nullable=True,
|
|
79
|
+
description="Identifier of the user that changed the entitlement",
|
|
80
|
+
alias="payroll.entitlement.change.changedById",
|
|
81
|
+
)
|
|
82
|
+
entitlement_id: pd.Int64Dtype = pa.Field(
|
|
83
|
+
coerce=True,
|
|
84
|
+
description="Entitlement record identifier",
|
|
85
|
+
alias="payroll.entitlement.id",
|
|
86
|
+
)
|
|
87
|
+
entitlement_effective_date: Optional[str] = pa.Field(
|
|
88
|
+
coerce=True,
|
|
89
|
+
nullable=True,
|
|
90
|
+
description="Entitlement effective date",
|
|
91
|
+
alias="payroll.entitlement.effectiveDate",
|
|
92
|
+
)
|
|
93
|
+
entitlement_creation_date: Optional[str] = pa.Field(
|
|
94
|
+
coerce=True,
|
|
95
|
+
nullable=True,
|
|
96
|
+
description="Entitlement creation date",
|
|
97
|
+
alias="payroll.entitlement.creationDate",
|
|
98
|
+
)
|
|
99
|
+
entitlement_modification_date: Optional[str] = pa.Field(
|
|
100
|
+
coerce=True,
|
|
101
|
+
nullable=True,
|
|
102
|
+
description="Entitlement modification date",
|
|
103
|
+
alias="payroll.entitlement.modificationDate",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
class Config:
|
|
107
|
+
coerce = True
|
|
108
|
+
|
|
109
|
+
class _Annotation:
|
|
110
|
+
primary_key = "entitlement_id"
|
|
@@ -2,7 +2,7 @@ import pandera as pa
|
|
|
2
2
|
from pandera.typing import Series
|
|
3
3
|
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class NamedListGet(BrynQPanderaDataFrameModel):
|
|
6
6
|
id: Series[str] = pa.Field(coerce=True, description="Named List ID", alias="id")
|
|
7
7
|
value: Series[str] = pa.Field(coerce=True, description="Named List Value", alias="value")
|
|
8
8
|
name: Series[str] = pa.Field(coerce=True, description="Named List Name", alias="name")
|
|
@@ -7,7 +7,7 @@ from pandera.typing import DateTime, Float, Series, String
|
|
|
7
7
|
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class
|
|
10
|
+
class VariablePaymentGet(BrynQPanderaDataFrameModel):
|
|
11
11
|
can_be_deleted: Series[bool] = pa.Field(nullable=True, coerce=True, description="Can Be Deleted", alias="canBeDeleted")
|
|
12
12
|
department_percent: Series[Float] = pa.Field(nullable=True, coerce=True, description="Department Percent", alias="departmentPercent")
|
|
13
13
|
payout_type: Series[String] = pa.Field(coerce=True, description="Payout Type", alias="payoutType")
|
|
@@ -33,7 +33,7 @@ class VariablePaymentSchema(BrynQPanderaDataFrameModel):
|
|
|
33
33
|
class Config:
|
|
34
34
|
coerce = True
|
|
35
35
|
|
|
36
|
-
class
|
|
36
|
+
class ActualPaymentsGet(BrynQPanderaDataFrameModel):
|
|
37
37
|
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
38
38
|
id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Payment ID", alias="id")
|
|
39
39
|
pay_date: Series[DateTime] = pa.Field(coerce=True, description="Pay Date", alias="payDate")
|
|
@@ -45,3 +45,4 @@ class ActualPaymentsSchema(BrynQPanderaDataFrameModel):
|
|
|
45
45
|
|
|
46
46
|
class Config:
|
|
47
47
|
coerce = True
|
|
48
|
+
|
|
@@ -15,7 +15,7 @@ def check_list(x):
|
|
|
15
15
|
return isinstance(x, list)
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
class
|
|
18
|
+
class PayrollHistoryGet(BrynQPanderaDataFrameModel):
|
|
19
19
|
id: Optional[Series[String]] = pa.Field(coerce=True, description="Person ID", alias="id")
|
|
20
20
|
display_name: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Display Name", alias="displayName")
|
|
21
21
|
company_id: Optional[Series[String]] = pa.Field(coerce=True, description="Company ID", alias="companyId")
|
brynq_sdk_bob/schemas/people.py
CHANGED
|
@@ -16,7 +16,7 @@ def check_list(x):
|
|
|
16
16
|
return isinstance(x, list)
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
class
|
|
19
|
+
class PeopleGet(BrynQPanderaDataFrameModel):
|
|
20
20
|
id: Optional[Series[String]] = pa.Field(coerce=True, description="Person ID", alias="id", metadata={"api_field": "root.id"})
|
|
21
21
|
display_name: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Display Name", alias="displayName", metadata={"api_field": "root.displayName"})
|
|
22
22
|
company_id: Optional[Series[String]] = pa.Field(coerce=True, description="Company ID", alias="companyId", metadata={"api_field": "root.companyId"})
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import pandera as pa
|
|
2
|
+
from typing import Optional
|
|
3
|
+
import pandas as pd
|
|
4
|
+
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ReportGet(BrynQPanderaDataFrameModel):
|
|
8
|
+
modification_date: Optional[str] = pa.Field(
|
|
9
|
+
coerce=True,
|
|
10
|
+
nullable=True,
|
|
11
|
+
description="Modification date of the report view",
|
|
12
|
+
alias="modificationDate",
|
|
13
|
+
)
|
|
14
|
+
created_by: pd.StringDtype = pa.Field(
|
|
15
|
+
coerce=True,
|
|
16
|
+
description="User identifier that created the report",
|
|
17
|
+
alias="createdBy",
|
|
18
|
+
)
|
|
19
|
+
configuration_instructions: Optional[object] = pa.Field(
|
|
20
|
+
coerce=True,
|
|
21
|
+
nullable=True,
|
|
22
|
+
description="Configuration instructions for the report view",
|
|
23
|
+
alias="configuration.instructions",
|
|
24
|
+
)
|
|
25
|
+
configuration_changes: Optional[object] = pa.Field(
|
|
26
|
+
coerce=True,
|
|
27
|
+
nullable=True,
|
|
28
|
+
description="Configuration changes associated with the report view",
|
|
29
|
+
alias="configuration.changes",
|
|
30
|
+
)
|
|
31
|
+
configuration_display_preferences_export_configuration: Optional[object] = pa.Field(
|
|
32
|
+
coerce=True,
|
|
33
|
+
nullable=True,
|
|
34
|
+
description="Export configuration within display preferences",
|
|
35
|
+
alias="configuration.displayPreferences.exportConfiguration",
|
|
36
|
+
)
|
|
37
|
+
configuration_display_preferences_include_flat_json: pd.BooleanDtype = pa.Field(
|
|
38
|
+
coerce=True,
|
|
39
|
+
description="Flag to include flat JSON in the export",
|
|
40
|
+
alias="configuration.displayPreferences.includeFlatJson",
|
|
41
|
+
)
|
|
42
|
+
configuration_display_preferences_date_format: Optional[pd.StringDtype] = pa.Field(
|
|
43
|
+
coerce=True,
|
|
44
|
+
nullable=True,
|
|
45
|
+
description="Date format specified in display preferences",
|
|
46
|
+
alias="configuration.displayPreferences.dateFormat",
|
|
47
|
+
)
|
|
48
|
+
configuration_display_preferences_support_error_wrapping: pd.BooleanDtype = pa.Field(
|
|
49
|
+
coerce=True,
|
|
50
|
+
description="Whether error wrapping is supported in display preferences",
|
|
51
|
+
alias="configuration.displayPreferences.supportErrorWrapping",
|
|
52
|
+
)
|
|
53
|
+
configuration_display_preferences_columns_properties: Optional[object] = pa.Field(
|
|
54
|
+
coerce=True,
|
|
55
|
+
nullable=True,
|
|
56
|
+
description="Column properties defined in display preferences",
|
|
57
|
+
alias="configuration.displayPreferences.columnsProperties",
|
|
58
|
+
)
|
|
59
|
+
configuration_display_preferences_include_human_readable: pd.BooleanDtype = pa.Field(
|
|
60
|
+
coerce=True,
|
|
61
|
+
description="Flag to include human-readable output in display preferences",
|
|
62
|
+
alias="configuration.displayPreferences.includeHumanReadable",
|
|
63
|
+
)
|
|
64
|
+
configuration_sort_by: Optional[object] = pa.Field(
|
|
65
|
+
coerce=True,
|
|
66
|
+
nullable=True,
|
|
67
|
+
description="Sort configuration for the report view",
|
|
68
|
+
alias="configuration.sortBy",
|
|
69
|
+
)
|
|
70
|
+
configuration_fields: Optional[object] = pa.Field(
|
|
71
|
+
coerce=True,
|
|
72
|
+
nullable=True,
|
|
73
|
+
description="Fields included in the report view",
|
|
74
|
+
alias="configuration.fields",
|
|
75
|
+
)
|
|
76
|
+
is_comparable: pd.BooleanDtype = pa.Field(
|
|
77
|
+
coerce=True,
|
|
78
|
+
description="Flag indicating if the report is comparable",
|
|
79
|
+
alias="isComparable",
|
|
80
|
+
)
|
|
81
|
+
name: Optional[pd.StringDtype] = pa.Field(
|
|
82
|
+
coerce=True,
|
|
83
|
+
nullable=True,
|
|
84
|
+
description="Name of the report view",
|
|
85
|
+
alias="name",
|
|
86
|
+
)
|
|
87
|
+
description: Optional[pd.StringDtype] = pa.Field(
|
|
88
|
+
coerce=True,
|
|
89
|
+
nullable=True,
|
|
90
|
+
description="Description of the report view",
|
|
91
|
+
alias="description",
|
|
92
|
+
)
|
|
93
|
+
schedule_status: Optional[pd.StringDtype] = pa.Field(
|
|
94
|
+
coerce=True,
|
|
95
|
+
nullable=True,
|
|
96
|
+
description="Scheduling status of the report view",
|
|
97
|
+
alias="scheduleStatus",
|
|
98
|
+
)
|
|
99
|
+
is_scheduled: pd.BooleanDtype = pa.Field(
|
|
100
|
+
coerce=True,
|
|
101
|
+
description="Flag indicating if the report is scheduled",
|
|
102
|
+
alias="isScheduled",
|
|
103
|
+
)
|
|
104
|
+
id: pd.StringDtype = pa.Field(
|
|
105
|
+
coerce=True,
|
|
106
|
+
description="Report identifier",
|
|
107
|
+
alias="id",
|
|
108
|
+
)
|
|
109
|
+
type: pd.StringDtype = pa.Field(
|
|
110
|
+
coerce=True,
|
|
111
|
+
description="Type of the report",
|
|
112
|
+
alias="type",
|
|
113
|
+
)
|
|
114
|
+
creation_date: str = pa.Field(
|
|
115
|
+
coerce=True,
|
|
116
|
+
description="Creation date of the report view",
|
|
117
|
+
alias="creationDate",
|
|
118
|
+
)
|
|
119
|
+
folder_id: pd.Int64Dtype = pa.Field(
|
|
120
|
+
coerce=True,
|
|
121
|
+
description="Identifier of the folder containing the report view",
|
|
122
|
+
alias="folderId",
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
class Config:
|
|
126
|
+
coerce = True
|
|
127
|
+
|
|
128
|
+
class _Annotation:
|
|
129
|
+
primary_key = "id"
|
brynq_sdk_bob/schemas/salary.py
CHANGED
|
@@ -11,7 +11,7 @@ from pydantic import BaseModel, Field
|
|
|
11
11
|
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
class
|
|
14
|
+
class SalaryGet(BrynQPanderaDataFrameModel):
|
|
15
15
|
id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Salary ID", alias="id")
|
|
16
16
|
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
17
17
|
pay_frequency: Series[String] = pa.Field(coerce=True, nullable=True, description="Pay Frequency", alias="payFrequency") # has a list of possible values , isin=['Monthly']
|
|
@@ -26,7 +26,7 @@ class SalarySchema(BrynQPanderaDataFrameModel):
|
|
|
26
26
|
active_effective_date: Series[DateTime] = pa.Field(coerce=True, nullable=True, description="Active Effective Date", alias="activeEffectiveDate")
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
class
|
|
29
|
+
class SalaryCreate(BaseModel):
|
|
30
30
|
# Function parameters
|
|
31
31
|
salary_data: Optional[Dict[str, Any]] = Field(None, description="Salary data", alias="salaryData")
|
|
32
32
|
|
|
@@ -49,5 +49,4 @@ class SalaryCreateSchema(BaseModel):
|
|
|
49
49
|
effective_date: Optional[date] = Field(None, description="The date this entry becomes effective. This is a mandatory field for a work entry.", alias="effectiveDate")
|
|
50
50
|
|
|
51
51
|
class Config:
|
|
52
|
-
|
|
53
|
-
coerce = True
|
|
52
|
+
populate_by_name = True
|
brynq_sdk_bob/schemas/timeoff.py
CHANGED
|
@@ -9,7 +9,7 @@ from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
|
9
9
|
# TimeOffSchema - For /timeoff/requests/changes endpoint (change events)
|
|
10
10
|
# =============================================================================
|
|
11
11
|
|
|
12
|
-
class
|
|
12
|
+
class TimeOffGet(BrynQPanderaDataFrameModel):
|
|
13
13
|
"""Schema for time off change events from /timeoff/requests/changes endpoint."""
|
|
14
14
|
change_type: Series[String] = pa.Field(coerce=True, description="Change Type", alias="changeType")
|
|
15
15
|
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
@@ -219,7 +219,7 @@ class TimeOffRequest(BrynQPanderaDataFrameModel):
|
|
|
219
219
|
# TimeOffBalanceSchema - For /timeoff/employees/{id}/balance endpoint
|
|
220
220
|
# =============================================================================
|
|
221
221
|
|
|
222
|
-
class
|
|
222
|
+
class TimeOffBalanceGet(BrynQPanderaDataFrameModel):
|
|
223
223
|
"""Schema for time off balance from /timeoff/employees/{id}/balance endpoint."""
|
|
224
224
|
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
225
225
|
policy_type_name: Series[String] = pa.Field(coerce=True, description="Policy Type Name", alias="policyTypeName")
|
brynq_sdk_bob/schemas/work.py
CHANGED
|
@@ -8,7 +8,7 @@ from pandera.typing import Series
|
|
|
8
8
|
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
class
|
|
11
|
+
class WorkGet(BrynQPanderaDataFrameModel):
|
|
12
12
|
can_be_deleted: Series[pa.Bool] = pa.Field(coerce=True, description="Can Be Deleted", alias="canBeDeleted")
|
|
13
13
|
work_change_type: Series[str] = pa.Field(coerce=True, description="Work Change Type", alias="workChangeType")
|
|
14
14
|
creation_date: Series[datetime] = pa.Field(coerce=True, nullable=True, description="Creation Date", alias="creationDate")
|
brynq_sdk_bob/timeoff.py
CHANGED
|
@@ -2,15 +2,15 @@ from datetime import datetime, timezone, timedelta
|
|
|
2
2
|
from typing import Union
|
|
3
3
|
import pandas as pd
|
|
4
4
|
from brynq_sdk_functions import Functions
|
|
5
|
-
from .schemas.timeoff import
|
|
5
|
+
from .schemas.timeoff import TimeOffGet, TimeOffBalanceGet, TimeOffRequest
|
|
6
6
|
import warnings
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class TimeOff:
|
|
10
|
-
def __init__(self,
|
|
11
|
-
self.
|
|
12
|
-
self.schema =
|
|
13
|
-
self.balance_schema =
|
|
10
|
+
def __init__(self, client):
|
|
11
|
+
self.client = client
|
|
12
|
+
self.schema = TimeOffGet
|
|
13
|
+
self.balance_schema = TimeOffBalanceGet
|
|
14
14
|
|
|
15
15
|
def get(self, since: datetime = None, include_pending: bool = False) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
16
16
|
"""
|
|
@@ -37,9 +37,9 @@ class TimeOff:
|
|
|
37
37
|
since = six_months_ago
|
|
38
38
|
|
|
39
39
|
since = since.replace(tzinfo=timezone.utc).isoformat(timespec='milliseconds').replace('+00:00', 'Z')
|
|
40
|
-
resp = self.
|
|
40
|
+
resp = self.client.session.get(url=f"{self.client.base_url}timeoff/requests/changes",
|
|
41
41
|
params={'since': since, 'includePending': 'true' if include_pending else 'false'},
|
|
42
|
-
timeout=self.
|
|
42
|
+
timeout=self.client.timeout)
|
|
43
43
|
resp.raise_for_status()
|
|
44
44
|
data = resp.json().get('changes', [])
|
|
45
45
|
df = pd.DataFrame(data)
|
|
@@ -63,9 +63,9 @@ class TimeOff:
|
|
|
63
63
|
Returns:
|
|
64
64
|
tuple[pd.DataFrame, pd.DataFrame]: (valid_request, invalid_request) as single-row DataFrames.
|
|
65
65
|
"""
|
|
66
|
-
resp = self.
|
|
67
|
-
url=f"{self.
|
|
68
|
-
timeout=self.
|
|
66
|
+
resp = self.client.session.get(
|
|
67
|
+
url=f"{self.client.base_url}timeoff/employees/{employee_id}/requests/{request_id}",
|
|
68
|
+
timeout=self.client.timeout
|
|
69
69
|
)
|
|
70
70
|
resp.raise_for_status()
|
|
71
71
|
data = resp.json()
|
|
@@ -96,10 +96,10 @@ class TimeOff:
|
|
|
96
96
|
if as_of_date:
|
|
97
97
|
params['asOfDate'] = as_of_date
|
|
98
98
|
|
|
99
|
-
resp = self.
|
|
100
|
-
url=f"{self.
|
|
99
|
+
resp = self.client.session.get(
|
|
100
|
+
url=f"{self.client.base_url}timeoff/employees/{employee_id}/balance",
|
|
101
101
|
params=params,
|
|
102
|
-
timeout=self.
|
|
102
|
+
timeout=self.client.timeout
|
|
103
103
|
)
|
|
104
104
|
resp.raise_for_status()
|
|
105
105
|
data = resp.json()
|
brynq_sdk_bob/work.py
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
import requests
|
|
3
3
|
from brynq_sdk_functions import Functions
|
|
4
|
-
from .schemas.work import
|
|
4
|
+
from .schemas.work import WorkGet
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class Work:
|
|
8
|
-
def __init__(self,
|
|
9
|
-
self.
|
|
10
|
-
self.schema =
|
|
8
|
+
def __init__(self, client):
|
|
9
|
+
self.client = client
|
|
10
|
+
self.schema = WorkGet
|
|
11
11
|
|
|
12
|
-
def get(self) ->
|
|
12
|
+
def get(self) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
13
13
|
request = requests.Request(method='GET',
|
|
14
|
-
url=f"{self.
|
|
15
|
-
|
|
14
|
+
url=f"{self.client.base_url}bulk/people/work",
|
|
15
|
+
params={"includeArchived": "true"})
|
|
16
|
+
data = self.client.get_paginated_result(request)
|
|
16
17
|
df = pd.json_normalize(
|
|
17
18
|
data,
|
|
18
19
|
record_path='values',
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: brynq_sdk_bob
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.10.1
|
|
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
|
+
Requires-Dist: brynq-sdk-functions>=2.0.5
|
|
9
10
|
Requires-Dist: pandas<3.0.0,>=2.2.0
|
|
11
|
+
Requires-Dist: pydantic<3.0.0,>=2.5.0
|
|
12
|
+
Requires-Dist: pandera<1.0.0,>=0.16.0
|
|
10
13
|
Dynamic: author
|
|
11
14
|
Dynamic: author-email
|
|
12
15
|
Dynamic: description
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
brynq_sdk_bob/__init__.py,sha256=D922dfjXAPti__4DBtQCAV6ilc60EU59ljHqCRb8nbw,3984
|
|
2
|
+
brynq_sdk_bob/bank.py,sha256=nhePvkOXFQ9TZb90dNGKaB_j3yJ49nBzyf0oVC7dYyw,980
|
|
3
|
+
brynq_sdk_bob/company.py,sha256=MWkDs8tilBIiHR0OQpT-CrbsZYJn-SAUvOtSEtv7VUQ,875
|
|
4
|
+
brynq_sdk_bob/custom_tables.py,sha256=IXxMv6jXn89cQmsISdUNaf6I0zbioP_NwXCaGZlPWPo,3265
|
|
5
|
+
brynq_sdk_bob/documents.py,sha256=hGgl2XGxbEyOGua7MtaCrK8F8iCPFYXEJR8OXsldEOs,1301
|
|
6
|
+
brynq_sdk_bob/employment.py,sha256=2fVHl3nlcntF7tr03F4MD-DLyKuo02yXQaaAJPz7qrs,848
|
|
7
|
+
brynq_sdk_bob/entitlements.py,sha256=Erw0BsY0NWV1RIsh1mUeBMmS177o-RjmZYX-m1MeoaM,1419
|
|
8
|
+
brynq_sdk_bob/named_lists.py,sha256=Om_4zBUNmqaDksjQpaf1HI7S2Pa3Dhpx3b5TZUNiSmM,1032
|
|
9
|
+
brynq_sdk_bob/payments.py,sha256=BEli8K9DoUwb9-WDC014FZ6Me0wy0FbHPdcTkSJt48s,4298
|
|
10
|
+
brynq_sdk_bob/payroll_history.py,sha256=8bhlqlGhOgUo7B0BMWH9AV8jYPhB8TItF6pvKAQrRwI,3894
|
|
11
|
+
brynq_sdk_bob/people.py,sha256=cVgYzVImjbU3JiY6dYK-EpOcGWriRC_uFQxvfruXjyw,6195
|
|
12
|
+
brynq_sdk_bob/reports.py,sha256=FaRQXgca4_bQy6y55jMPzwZR8BgtiKGFO_GVYZ9bEbU,1465
|
|
13
|
+
brynq_sdk_bob/salaries.py,sha256=0JpigQr1lLNPCbk3DEo6LHkK6fJjZxTHeXlgMxvXFYE,1551
|
|
14
|
+
brynq_sdk_bob/timeoff.py,sha256=QGvjgseOKg3znt2l4zXEBXar6Z9jowHelQVVgwn4gCM,4462
|
|
15
|
+
brynq_sdk_bob/work.py,sha256=ERDbj92dWmcbFakFlY7FwLpnitHo6sTeyVW-GINT5js,798
|
|
16
|
+
brynq_sdk_bob/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
+
brynq_sdk_bob/schemas/bank.py,sha256=Oci8ZN_e0prV3sF5F9sZsUOphhtFCmcCYHT900w1pcM,1844
|
|
18
|
+
brynq_sdk_bob/schemas/custom_tables.py,sha256=WZFReQQxAj2cLzlhnfWoyogR14B56UDXYD4n-Akcq6o,1561
|
|
19
|
+
brynq_sdk_bob/schemas/employment.py,sha256=yG3SI7jma30PAjNBozXrAzfaNfjwSIaCU4Xn1CUWje4,3488
|
|
20
|
+
brynq_sdk_bob/schemas/entitlements.py,sha256=5wAyqLso238MMmjO3tuq_szXB_cdK1Q96qgyE5GH6u0,3648
|
|
21
|
+
brynq_sdk_bob/schemas/named_lists.py,sha256=QBHK1JDbKAvOD2PU6ycZcGd5DI6HP44LeVDeqEVFDIE,722
|
|
22
|
+
brynq_sdk_bob/schemas/payments.py,sha256=Ob4ebX8bVo8UM2XboCgeqN-8tXUDHTD5Q6eo0Ec3fyk,4038
|
|
23
|
+
brynq_sdk_bob/schemas/payroll_history.py,sha256=T2vuzuPDKoEoOiX4RVf_Qnwg0yjx4AMLavAzXc1csy4,803
|
|
24
|
+
brynq_sdk_bob/schemas/people.py,sha256=NFm9-3-4c-7lRBNv5JxnRA_rAMu2RLGoF2mEQs0t_h4,40438
|
|
25
|
+
brynq_sdk_bob/schemas/reports.py,sha256=h0vrrzFkwTYR6DZ1VxkK2B7ZQBNWPWA_ukSDevyDlMs,4541
|
|
26
|
+
brynq_sdk_bob/schemas/salary.py,sha256=czKJYjzMTSP0SHYIWEJFS-rjQ4NYjZCGV2PErrcKLIY,4505
|
|
27
|
+
brynq_sdk_bob/schemas/timeoff.py,sha256=XYN489nn6BhKxYOARrpB6-7IUhsSanlpRCQz6gzGGFg,12811
|
|
28
|
+
brynq_sdk_bob/schemas/work.py,sha256=X9QS2psQfZ9torbjNBUDmp9X2KLYdgRpuS2cvyy4waM,3014
|
|
29
|
+
brynq_sdk_bob-2.10.1.dist-info/METADATA,sha256=vU7LlX1K57bIP4CSVN6ISokIJ1KfSYf2CP5ExaYd5TA,490
|
|
30
|
+
brynq_sdk_bob-2.10.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
31
|
+
brynq_sdk_bob-2.10.1.dist-info/top_level.txt,sha256=oGiWqOuAAiVoLIzGe6F-Lo4IJBYz5ftOwBft7HtPuoY,14
|
|
32
|
+
brynq_sdk_bob-2.10.1.dist-info/RECORD,,
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
brynq_sdk_bob/__init__.py,sha256=sP1DRvGpViN8e0yMw9RMHMmuFH8-0rgv0m4E5vRZYuI,3901
|
|
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=VHcZYxGU-rRZjo5tBaAVAawsUxgh90CeVT9rsxMfzvY,3253
|
|
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=43Ctdt5T8gtpCud67dm75xa90W8m6FyMrU2hAWKrzMc,4221
|
|
9
|
-
brynq_sdk_bob/payroll_history.py,sha256=wHo6da7kLDe1ViL4egyMdyJBMZnWVhwjNjmh4cTCTeY,3972
|
|
10
|
-
brynq_sdk_bob/people.py,sha256=Cg7I-Ibo4UdhyjOtAtjmcK9nd5AwQWy2B9Zsn6VhZzU,6211
|
|
11
|
-
brynq_sdk_bob/reports.py,sha256=Tawmqm_ZmQ487loyk-29-A_fTCrgImbWCEf6zfwuaq4,1245
|
|
12
|
-
brynq_sdk_bob/salaries.py,sha256=BGQm-PT9QuKKJ9DP5nX6wmC8SZRAlm9M9I2EJhoZaII,1523
|
|
13
|
-
brynq_sdk_bob/timeoff.py,sha256=JtTu14PWFqQIEn9r-Z8ipeNE-5p7hqPz5N6wjjBeLTs,4438
|
|
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=1LsPjp-TexEc4B9nXjciMKFw94bl6xhEp3TNsgnLcds,3387
|
|
19
|
-
brynq_sdk_bob/schemas/named_lists.py,sha256=HJBRKrAI2vhrkq-5MVXqQcmpGNzFtoOnaZI2Ii_6_vs,725
|
|
20
|
-
brynq_sdk_bob/schemas/payments.py,sha256=ZaF34kXCroX_AG5jm9XRrfG2QwMbkn-I4wsnWgJMFpk,4043
|
|
21
|
-
brynq_sdk_bob/schemas/payroll_history.py,sha256=JdAq0XaArHHEw8EsXo3GD0EhSAyBhPtYQMmdvjCiY8g,806
|
|
22
|
-
brynq_sdk_bob/schemas/people.py,sha256=H0HgSIPVVBWeyXU1N7J6NUgohfFsBWK4hfxwMMqCDR8,40441
|
|
23
|
-
brynq_sdk_bob/schemas/salary.py,sha256=WIGlN0CVcG5PvA0OQuSrFdPjeFVJdEN87Hzm3hPRTHc,4550
|
|
24
|
-
brynq_sdk_bob/schemas/timeoff.py,sha256=gTYu_bNcfHrkTz4eIHCZ4WzgMTj2U4nI3X6JTzDovhk,12817
|
|
25
|
-
brynq_sdk_bob/schemas/work.py,sha256=1odd3ia97SZff8VjLzL1a0FEQaF2ojGeWsfovcWvkhM,3017
|
|
26
|
-
brynq_sdk_bob-2.9.6.dist-info/METADATA,sha256=wTblpCzXjrZgJRYYotw-KaAKIXl7yfjhNftQngwRF4A,371
|
|
27
|
-
brynq_sdk_bob-2.9.6.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
|
|
28
|
-
brynq_sdk_bob-2.9.6.dist-info/top_level.txt,sha256=oGiWqOuAAiVoLIzGe6F-Lo4IJBYz5ftOwBft7HtPuoY,14
|
|
29
|
-
brynq_sdk_bob-2.9.6.dist-info/RECORD,,
|
|
File without changes
|