brynq-sdk-bob 2.2.1__tar.gz → 2.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/PKG-INFO +1 -1
- brynq_sdk_bob-2.4.0/brynq_sdk_bob/payments.py +114 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/payments.py +15 -1
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/people.py +2 -2
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/salary.py +1 -1
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/timeoff.py +18 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/timeoff.py +33 -1
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob.egg-info/PKG-INFO +1 -1
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/setup.py +1 -1
- brynq_sdk_bob-2.2.1/brynq_sdk_bob/payments.py +0 -23
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/__init__.py +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/bank.py +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/company.py +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/custom_tables.py +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/documents.py +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/employment.py +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/named_lists.py +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/people.py +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/salaries.py +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/__init__.py +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/bank.py +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/custom_tables.py +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/employment.py +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/named_lists.py +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/schemas/work.py +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob/work.py +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob.egg-info/SOURCES.txt +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob.egg-info/dependency_links.txt +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob.egg-info/not-zip-safe +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob.egg-info/requires.txt +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/brynq_sdk_bob.egg-info/top_level.txt +0 -0
- {brynq_sdk_bob-2.2.1 → brynq_sdk_bob-2.4.0}/setup.cfg +0 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
from typing import Optional, List
|
|
3
|
+
from brynq_sdk_functions import Functions
|
|
4
|
+
from .schemas.payments import VariablePaymentSchema, ActualPaymentsSchema
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Payments:
|
|
8
|
+
def __init__(self, bob):
|
|
9
|
+
self.bob = bob
|
|
10
|
+
self.schema = VariablePaymentSchema
|
|
11
|
+
|
|
12
|
+
def get(self, person_id: str) -> (pd.DataFrame, pd.DataFrame):
|
|
13
|
+
resp = self.bob.session.get(url=f"{self.bob.base_url}people/{person_id}/variable", timeout=self.bob.timeout)
|
|
14
|
+
resp.raise_for_status()
|
|
15
|
+
data = resp.json()
|
|
16
|
+
df = pd.json_normalize(
|
|
17
|
+
data,
|
|
18
|
+
record_path='values'
|
|
19
|
+
)
|
|
20
|
+
df['employee_id'] = person_id
|
|
21
|
+
valid_payments, invalid_payments = Functions.validate_data(df=df, schema=self.schema, debug=True)
|
|
22
|
+
|
|
23
|
+
return valid_payments, invalid_payments
|
|
24
|
+
|
|
25
|
+
def get_actual_payments(
|
|
26
|
+
self,
|
|
27
|
+
limit: int = 200,
|
|
28
|
+
employee_ids: Optional[List[str]] = None,
|
|
29
|
+
pay_date_from: Optional[str] = None,
|
|
30
|
+
pay_date_to: Optional[str] = None
|
|
31
|
+
) -> (pd.DataFrame, pd.DataFrame):
|
|
32
|
+
"""
|
|
33
|
+
Search for actual payments with optional employee and pay date filters.
|
|
34
|
+
This method auto-paginates until all results are fetched.
|
|
35
|
+
|
|
36
|
+
See Bob API: https://apidocs.hibob.com/reference/post_people-actual-payments-search
|
|
37
|
+
See Pagination: https://apidocs.hibob.com/docs/pagination
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
limit (int): Number of records per page (default: 50, max: 200).
|
|
41
|
+
employee_ids (Optional[List[str]]): Filter by employee IDs.
|
|
42
|
+
pay_date_from (Optional[str]): Inclusive start date filter (YYYY-MM-DD).
|
|
43
|
+
pay_date_to (Optional[str]): Inclusive end date filter (YYYY-MM-DD).
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
tuple: (valid_payments DataFrame, invalid_payments DataFrame)
|
|
47
|
+
"""
|
|
48
|
+
base_payload = {
|
|
49
|
+
"pagination": {
|
|
50
|
+
"limit": limit
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
filters = []
|
|
55
|
+
if employee_ids:
|
|
56
|
+
filters.append({
|
|
57
|
+
"fieldPath": "employeeId",
|
|
58
|
+
"operator": "equals",
|
|
59
|
+
"values": employee_ids
|
|
60
|
+
})
|
|
61
|
+
if pay_date_from:
|
|
62
|
+
filters.append({
|
|
63
|
+
"fieldPath": "payDate",
|
|
64
|
+
"operator": "greaterThanOrEquals",
|
|
65
|
+
"value": pay_date_from
|
|
66
|
+
})
|
|
67
|
+
if pay_date_to:
|
|
68
|
+
filters.append({
|
|
69
|
+
"fieldPath": "payDate",
|
|
70
|
+
"operator": "lessThanOrEquals",
|
|
71
|
+
"value": pay_date_to
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
if filters:
|
|
75
|
+
base_payload["filters"] = filters
|
|
76
|
+
|
|
77
|
+
all_results = []
|
|
78
|
+
next_cursor = None
|
|
79
|
+
|
|
80
|
+
while True:
|
|
81
|
+
payload = dict(base_payload)
|
|
82
|
+
payload["pagination"] = dict(base_payload["pagination"])
|
|
83
|
+
if next_cursor:
|
|
84
|
+
payload["pagination"]["cursor"] = next_cursor
|
|
85
|
+
|
|
86
|
+
resp = self.bob.session.post(
|
|
87
|
+
url=f"{self.bob.base_url}people/actual-payments/search",
|
|
88
|
+
json=payload,
|
|
89
|
+
timeout=self.bob.timeout
|
|
90
|
+
)
|
|
91
|
+
resp.raise_for_status()
|
|
92
|
+
data = resp.json()
|
|
93
|
+
|
|
94
|
+
page_results = data.get('results') or []
|
|
95
|
+
if page_results:
|
|
96
|
+
all_results.extend(page_results)
|
|
97
|
+
|
|
98
|
+
next_cursor = (data.get('response_metadata') or {}).get('next_cursor')
|
|
99
|
+
if not next_cursor:
|
|
100
|
+
break
|
|
101
|
+
|
|
102
|
+
if not all_results:
|
|
103
|
+
empty_df = pd.DataFrame()
|
|
104
|
+
return empty_df, empty_df
|
|
105
|
+
|
|
106
|
+
df = pd.json_normalize(all_results)
|
|
107
|
+
|
|
108
|
+
valid_payments, invalid_payments = Functions.validate_data(
|
|
109
|
+
df=df,
|
|
110
|
+
schema=ActualPaymentsSchema,
|
|
111
|
+
debug=True
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
return valid_payments, invalid_payments
|
|
@@ -26,6 +26,20 @@ class VariablePaymentSchema(BrynQPanderaDataFrameModel):
|
|
|
26
26
|
change_reason: Series[String] = pa.Field(nullable=True, coerce=True, description="Change Reason", alias="change.reason")
|
|
27
27
|
change_changed_by: Series[String] = pa.Field(nullable=True, coerce=True, description="Change Changed By", alias="change.changedBy")
|
|
28
28
|
change_changed_by_id: Series[pd.Int64Dtype] = pa.Field(nullable=True, coerce=True, description="Change Changed By ID", alias="change.changedById")
|
|
29
|
-
employee_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Employee ID", alias="
|
|
29
|
+
employee_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Employee ID", alias="employee_id") #set manually
|
|
30
|
+
class Config:
|
|
31
|
+
coerce = True
|
|
32
|
+
|
|
33
|
+
class ActualPaymentsSchema(BrynQPanderaDataFrameModel):
|
|
34
|
+
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
35
|
+
id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Payment ID", alias="id")
|
|
36
|
+
pay_date: Series[DateTime] = pa.Field(coerce=True, description="Pay Date", alias="payDate")
|
|
37
|
+
pay_type: Series[String] = pa.Field(coerce=True, description="Pay Type", alias="payType")
|
|
38
|
+
amount_value: Series[Float] = pa.Field(coerce=True, description="Amount Value", alias="amount.value")
|
|
39
|
+
amount_currency: Series[String] = pa.Field(coerce=True, description="Amount Currency", alias="amount.currency")
|
|
40
|
+
change_reason: Series[String] = pa.Field(nullable=True, coerce=True, description="Change Reason", alias="change.reason")
|
|
41
|
+
change_changed_by: Series[String] = pa.Field(nullable=True, coerce=True, description="Change Changed By", alias="change.changedBy")
|
|
42
|
+
change_changed_by_id: Series[String] = pa.Field(nullable=True, coerce=True, description="Change Changed By ID", alias="change.changedById")
|
|
43
|
+
|
|
30
44
|
class Config:
|
|
31
45
|
coerce = True
|
|
@@ -16,7 +16,7 @@ def check_list(x):
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class PeopleSchema(BrynQPanderaDataFrameModel):
|
|
19
|
-
id: Optional[Series[
|
|
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")
|
|
22
22
|
email: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Email", alias="email")
|
|
@@ -63,7 +63,7 @@ class PeopleSchema(BrynQPanderaDataFrameModel):
|
|
|
63
63
|
work_active_effective_date: Optional[Series[DateTime]] = pa.Field(coerce=True, nullable=True, description="Work Active Effective Date", alias="work.activeEffectiveDate")
|
|
64
64
|
work_direct_reports: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Work Direct Reports", alias="work.directReports")
|
|
65
65
|
# work_work_change_type: Series[String] = pa.Field(coerce=True, nullable=True)
|
|
66
|
-
work_second_level_manager: Optional[Series[
|
|
66
|
+
work_second_level_manager: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Work Second Level Manager", alias="work.secondLevelManager")
|
|
67
67
|
work_days_of_previous_service: Optional[Series[pd.Int64Dtype]] = pa.Field(coerce=True, nullable=True, description="Work Days of Previous Service", alias="work.daysOfPreviousService")
|
|
68
68
|
work_years_of_service: Optional[Series[Float]] = pa.Field(coerce=True, nullable=True, description="Work Years of Service", alias="work.yearsOfService")
|
|
69
69
|
payroll_employment_contract: Optional[Series[String]] = pa.Field(coerce=True, nullable=True, description="Contract Type", alias="payroll.employment.contract")
|
|
@@ -7,7 +7,7 @@ from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class SalarySchema(BrynQPanderaDataFrameModel):
|
|
10
|
-
id: Series[
|
|
10
|
+
id: Series[String] = pa.Field(coerce=True, description="Salary ID", alias="id")
|
|
11
11
|
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
12
12
|
pay_frequency: Series[String] = pa.Field(coerce=True, nullable=True, description="Pay Frequency", alias="payFrequency") # has a list of possible values , isin=['Monthly']
|
|
13
13
|
creation_date: Series[DateTime] = pa.Field(coerce=True, nullable=True, description="Creation Date", alias="creationDate")
|
|
@@ -27,3 +27,21 @@ class TimeOffSchema(BrynQPanderaDataFrameModel):
|
|
|
27
27
|
|
|
28
28
|
class Config:
|
|
29
29
|
coerce = True
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class TimeOffBalanceSchema(BrynQPanderaDataFrameModel):
|
|
33
|
+
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
34
|
+
policy_type_name: Series[String] = pa.Field(coerce=True, description="Policy Type Name", alias="policyTypeName")
|
|
35
|
+
policy_type_display_name: Series[String] = pa.Field(coerce=True, description="Policy Type Display Name", alias="policyTypeDisplayName")
|
|
36
|
+
balance: Series[Float] = pa.Field(coerce=True, description="Current Balance", alias="balance")
|
|
37
|
+
used: Series[Float] = pa.Field(coerce=True, description="Used Balance", alias="used")
|
|
38
|
+
available: Series[Float] = pa.Field(coerce=True, description="Available Balance", alias="available")
|
|
39
|
+
approved_requests: Series[Float] = pa.Field(coerce=True, description="Approved Requests", alias="approvedRequests")
|
|
40
|
+
pending_requests: Series[Float] = pa.Field(coerce=True, description="Pending Requests", alias="pendingRequests")
|
|
41
|
+
as_of_date: Series[String] = pa.Field(coerce=True, description="As of Date", alias="asOfDate")
|
|
42
|
+
accrual_start_date: Series[String] = pa.Field(nullable=True, coerce=True, description="Accrual Start Date", alias="accrualStartDate")
|
|
43
|
+
expiry_date: Series[String] = pa.Field(nullable=True, coerce=True, description="Expiry Date", alias="expiryDate")
|
|
44
|
+
duration_unit: Series[String] = pa.Field(coerce=True, description="Duration Unit", alias="durationUnit")
|
|
45
|
+
|
|
46
|
+
class Config:
|
|
47
|
+
coerce = True
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from datetime import datetime, timezone, timedelta
|
|
2
2
|
import pandas as pd
|
|
3
3
|
from brynq_sdk_functions import Functions
|
|
4
|
-
from .schemas.timeoff import TimeOffSchema
|
|
4
|
+
from .schemas.timeoff import TimeOffSchema, TimeOffBalanceSchema
|
|
5
5
|
import warnings
|
|
6
6
|
|
|
7
7
|
|
|
@@ -9,6 +9,7 @@ class TimeOff:
|
|
|
9
9
|
def __init__(self, bob):
|
|
10
10
|
self.bob = bob
|
|
11
11
|
self.schema = TimeOffSchema
|
|
12
|
+
self.balance_schema = TimeOffBalanceSchema
|
|
12
13
|
|
|
13
14
|
def get(self, since: datetime = None) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
14
15
|
"""
|
|
@@ -49,3 +50,34 @@ class TimeOff:
|
|
|
49
50
|
valid_timeoff, invalid_timeoff = Functions.validate_data(df=df, schema=self.schema, debug=True)
|
|
50
51
|
|
|
51
52
|
return valid_timeoff, invalid_timeoff
|
|
53
|
+
|
|
54
|
+
def get_balance(self, employee_id: str, policy_type: str = None, as_of_date: str = None) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
55
|
+
"""
|
|
56
|
+
Get time off balance for a specific employee
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
employee_id (str): The ID of the employee
|
|
60
|
+
policy_type (str, optional): The policy type to filter by. Defaults to None.
|
|
61
|
+
as_of_date (str, optional): The date to get balance as of (YYYY-MM-DD format). Defaults to None.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
tuple[pd.DataFrame, pd.DataFrame]: A tuple of (valid_balance, invalid_balance) as pandas DataFrames
|
|
65
|
+
"""
|
|
66
|
+
params = {}
|
|
67
|
+
if policy_type:
|
|
68
|
+
params['policyType'] = policy_type
|
|
69
|
+
if as_of_date:
|
|
70
|
+
params['asOfDate'] = as_of_date
|
|
71
|
+
|
|
72
|
+
resp = self.bob.session.get(
|
|
73
|
+
url=f"{self.bob.base_url}timeoff/employees/{employee_id}/balance",
|
|
74
|
+
params=params,
|
|
75
|
+
timeout=self.bob.timeout
|
|
76
|
+
)
|
|
77
|
+
resp.raise_for_status()
|
|
78
|
+
data = resp.json()
|
|
79
|
+
df = pd.DataFrame(data)
|
|
80
|
+
|
|
81
|
+
valid_balance, invalid_balance = Functions.validate_data(df=df, schema=self.balance_schema, debug=True)
|
|
82
|
+
|
|
83
|
+
return valid_balance, invalid_balance
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
from datetime import datetime
|
|
2
|
-
import pandas as pd
|
|
3
|
-
from brynq_sdk_functions import Functions
|
|
4
|
-
from .schemas.payments import VariablePaymentSchema
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class Payments:
|
|
8
|
-
def __init__(self, bob):
|
|
9
|
-
self.bob = bob
|
|
10
|
-
self.schema = VariablePaymentSchema
|
|
11
|
-
|
|
12
|
-
def get(self, person_id: str) -> (pd.DataFrame, pd.DataFrame):
|
|
13
|
-
resp = self.bob.session.get(url=f"{self.bob.base_url}people/{person_id}/variable", timeout=self.bob.timeout)
|
|
14
|
-
resp.raise_for_status()
|
|
15
|
-
data = resp.json()
|
|
16
|
-
df = pd.json_normalize(
|
|
17
|
-
data,
|
|
18
|
-
record_path='values'
|
|
19
|
-
)
|
|
20
|
-
df['employee_id'] = person_id
|
|
21
|
-
valid_payments, invalid_payments = Functions.validate_data(df=df, schema=self.schema, debug=True)
|
|
22
|
-
|
|
23
|
-
return valid_payments, invalid_payments
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|