brynq-sdk-nmbrs 2.3.3.dev0__py3-none-any.whl → 2.4.5__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_nmbrs/__init__.py +95 -91
- brynq_sdk_nmbrs/absence.py +1 -4
- brynq_sdk_nmbrs/address.py +5 -81
- brynq_sdk_nmbrs/bank.py +1 -2
- brynq_sdk_nmbrs/companies.py +130 -39
- brynq_sdk_nmbrs/contract.py +0 -1
- brynq_sdk_nmbrs/days.py +1 -1
- brynq_sdk_nmbrs/debtors.py +53 -65
- brynq_sdk_nmbrs/department.py +23 -111
- brynq_sdk_nmbrs/document.py +195 -4
- brynq_sdk_nmbrs/employee_wage_tax_settings.py +13 -5
- brynq_sdk_nmbrs/employees.py +55 -21
- brynq_sdk_nmbrs/employment.py +0 -2
- brynq_sdk_nmbrs/extra_fields.py +126 -0
- brynq_sdk_nmbrs/function.py +35 -97
- brynq_sdk_nmbrs/leave.py +53 -58
- brynq_sdk_nmbrs/manager.py +51 -35
- brynq_sdk_nmbrs/salaries.py +48 -65
- brynq_sdk_nmbrs/salary_tables.py +1 -4
- brynq_sdk_nmbrs/schedules.py +5 -78
- brynq_sdk_nmbrs/schemas/absence.py +26 -16
- brynq_sdk_nmbrs/schemas/address.py +2 -29
- brynq_sdk_nmbrs/schemas/children.py +0 -2
- brynq_sdk_nmbrs/schemas/contracts.py +7 -6
- brynq_sdk_nmbrs/schemas/costcenter.py +2 -2
- brynq_sdk_nmbrs/schemas/costunit.py +2 -0
- brynq_sdk_nmbrs/schemas/days.py +13 -11
- brynq_sdk_nmbrs/schemas/debtor.py +6 -28
- brynq_sdk_nmbrs/schemas/department.py +5 -39
- brynq_sdk_nmbrs/schemas/document.py +0 -2
- brynq_sdk_nmbrs/schemas/employee_wage_tax_settings.py +75 -0
- brynq_sdk_nmbrs/schemas/employees.py +2 -0
- brynq_sdk_nmbrs/schemas/extra_fields.py +56 -0
- brynq_sdk_nmbrs/schemas/function.py +5 -32
- brynq_sdk_nmbrs/schemas/hours.py +5 -1
- brynq_sdk_nmbrs/schemas/leave.py +17 -6
- brynq_sdk_nmbrs/schemas/manager.py +16 -24
- brynq_sdk_nmbrs/schemas/salary.py +11 -1
- brynq_sdk_nmbrs/schemas/schedules.py +2 -54
- brynq_sdk_nmbrs/schemas/svw_settings.py +116 -0
- brynq_sdk_nmbrs/schemas/wage_tax.py +53 -21
- brynq_sdk_nmbrs/schemas/wagecomponents.py +6 -9
- brynq_sdk_nmbrs/svw_settings.py +213 -0
- brynq_sdk_nmbrs/wage_tax.py +120 -11
- {brynq_sdk_nmbrs-2.3.3.dev0.dist-info → brynq_sdk_nmbrs-2.4.5.dist-info}/METADATA +1 -1
- brynq_sdk_nmbrs-2.4.5.dist-info/RECORD +58 -0
- {brynq_sdk_nmbrs-2.3.3.dev0.dist-info → brynq_sdk_nmbrs-2.4.5.dist-info}/WHEEL +1 -1
- brynq_sdk_nmbrs/schemas/social_insurance.py +0 -73
- brynq_sdk_nmbrs/social_insurance.py +0 -130
- brynq_sdk_nmbrs-2.3.3.dev0.dist-info/RECORD +0 -55
- {brynq_sdk_nmbrs-2.3.3.dev0.dist-info → brynq_sdk_nmbrs-2.4.5.dist-info}/top_level.txt +0 -0
brynq_sdk_nmbrs/employees.py
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import Any, Dict,
|
|
2
|
+
from typing import Any, Dict, Tuple
|
|
3
3
|
|
|
4
4
|
import pandas as pd
|
|
5
5
|
import requests
|
|
6
|
-
from pydantic import BaseModel
|
|
7
6
|
from zeep.exceptions import Fault
|
|
8
7
|
from zeep.helpers import serialize_object
|
|
9
8
|
|
|
@@ -23,19 +22,11 @@ from .leave import Leave, LeaveBalance
|
|
|
23
22
|
from .salaries import Salaries
|
|
24
23
|
from .schedules import Schedule
|
|
25
24
|
from .schemas.employees import (
|
|
26
|
-
AdditionalEmployeeInfo,
|
|
27
|
-
BasicInfo,
|
|
28
|
-
BirthInfo,
|
|
29
25
|
BsnGet,
|
|
30
|
-
ContactInfo,
|
|
31
|
-
CreateEmployeePersonalInfo,
|
|
32
26
|
DefaultEmployeeTemplates,
|
|
33
27
|
EmployeeCreate,
|
|
34
|
-
EmployeeDelete,
|
|
35
28
|
EmployeeGet,
|
|
36
29
|
EmployeeUpdate,
|
|
37
|
-
PartnerInfo,
|
|
38
|
-
Period,
|
|
39
30
|
)
|
|
40
31
|
from .wage_tax import WageTax
|
|
41
32
|
from .wagecomponents import EmployeeFixedWageComponents, EmployeeVariableWageComponents
|
|
@@ -66,7 +57,7 @@ class Employees:
|
|
|
66
57
|
|
|
67
58
|
def get(self,
|
|
68
59
|
employee_type: str = None
|
|
69
|
-
) ->
|
|
60
|
+
) -> Tuple[pd.DataFrame, pd.DataFrame]:
|
|
70
61
|
employees = pd.DataFrame()
|
|
71
62
|
for company in self.nmbrs.company_ids:
|
|
72
63
|
company_employees = self._get(company, employee_type)
|
|
@@ -172,6 +163,11 @@ class Employees:
|
|
|
172
163
|
timeout=self.nmbrs.timeout
|
|
173
164
|
)
|
|
174
165
|
|
|
166
|
+
# Handle social security number update if present
|
|
167
|
+
if 'social_security_number' in data and resp.ok:
|
|
168
|
+
employee_id = resp.json().get('employeeId')
|
|
169
|
+
if employee_id:
|
|
170
|
+
self._update_social_security_number(employee_id, data['social_security_number'])
|
|
175
171
|
|
|
176
172
|
return resp
|
|
177
173
|
|
|
@@ -206,17 +202,55 @@ class Employees:
|
|
|
206
202
|
)
|
|
207
203
|
|
|
208
204
|
# Handle social security number update if present
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
205
|
+
if 'socialSecurityNumber' in data:
|
|
206
|
+
self._update_social_security_number(employee_id, data['socialSecurityNumber'])
|
|
207
|
+
|
|
208
|
+
return resp
|
|
209
|
+
|
|
210
|
+
def get_by_id(self, employee_id: str) -> pd.DataFrame:
|
|
211
|
+
"""
|
|
212
|
+
Get detailed information about a specific employee.
|
|
213
|
+
|
|
214
|
+
The data returned is detailed and refers to the latest entry on the
|
|
215
|
+
current period of the company.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
employee_id: The ID of the employee
|
|
219
|
+
|
|
220
|
+
Returns:
|
|
221
|
+
DataFrame containing employee details
|
|
222
|
+
"""
|
|
223
|
+
request = requests.Request(
|
|
224
|
+
method='GET',
|
|
225
|
+
url=f"{self.nmbrs.base_url}employees/{employee_id}"
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
data = self.nmbrs.get_paginated_result(request)
|
|
229
|
+
df = pd.json_normalize(data)
|
|
230
|
+
|
|
231
|
+
return df
|
|
232
|
+
|
|
233
|
+
def _update_social_security_number(self, employee_id: str, social_security_number: str):
|
|
234
|
+
"""
|
|
235
|
+
Internal method to update an employee's social security number (BSN).
|
|
219
236
|
|
|
237
|
+
Args:
|
|
238
|
+
employee_id: The ID of the employee
|
|
239
|
+
social_security_number: The new social security number
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
Response from the API
|
|
243
|
+
"""
|
|
244
|
+
payload = {
|
|
245
|
+
"socialSecurityNumber": social_security_number
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
resp = self.nmbrs.session.put(
|
|
249
|
+
url=f"{self.nmbrs.base_url}employees/{employee_id}/socialsecuritynumber",
|
|
250
|
+
json=payload,
|
|
251
|
+
timeout=self.nmbrs.timeout
|
|
252
|
+
)
|
|
253
|
+
resp.raise_for_status()
|
|
220
254
|
return resp
|
|
221
255
|
|
|
222
256
|
def get_soap_ids(self) -> pd.DataFrame:
|
brynq_sdk_nmbrs/employment.py
CHANGED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import requests
|
|
3
|
+
from typing import Optional
|
|
4
|
+
from .schemas.extra_fields import ExtraFieldSettingsGet, EmployeeExtraFieldsGet
|
|
5
|
+
from brynq_sdk_functions import Functions
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ExtraFieldSettings:
|
|
9
|
+
"""
|
|
10
|
+
Class for handling company-level extra field settings.
|
|
11
|
+
|
|
12
|
+
Endpoints:
|
|
13
|
+
- GET /api/companies/{companyId}/extrafieldSettings
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, nmbrs):
|
|
17
|
+
self.nmbrs = nmbrs
|
|
18
|
+
|
|
19
|
+
def get(self, company_id: Optional[str] = None) -> tuple:
|
|
20
|
+
"""
|
|
21
|
+
Get extra field settings for a company.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
company_id: Optional company ID. If not provided, fetches for all companies.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
Tuple of (valid_data, invalid_data) DataFrames
|
|
28
|
+
"""
|
|
29
|
+
if company_id:
|
|
30
|
+
df = self._get(company_id)
|
|
31
|
+
else:
|
|
32
|
+
df = pd.DataFrame()
|
|
33
|
+
for company in self.nmbrs.company_ids:
|
|
34
|
+
df = pd.concat([df, self._get(company)])
|
|
35
|
+
|
|
36
|
+
if df.empty:
|
|
37
|
+
return df, pd.DataFrame()
|
|
38
|
+
|
|
39
|
+
valid_data, invalid_data = Functions.validate_data(df=df, schema=ExtraFieldSettingsGet, debug=self.nmbrs.debug)
|
|
40
|
+
return valid_data, invalid_data
|
|
41
|
+
|
|
42
|
+
def _get(self, company_id: str) -> pd.DataFrame:
|
|
43
|
+
"""
|
|
44
|
+
Internal method to get extra field settings for a single company.
|
|
45
|
+
"""
|
|
46
|
+
request = requests.Request(
|
|
47
|
+
method='GET',
|
|
48
|
+
url=f"{self.nmbrs.base_url}companies/{company_id}/extrafieldSettings"
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
data = self.nmbrs.get_paginated_result(request)
|
|
52
|
+
df = pd.DataFrame(data)
|
|
53
|
+
|
|
54
|
+
if not df.empty:
|
|
55
|
+
df['companyId'] = company_id
|
|
56
|
+
|
|
57
|
+
return df
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class EmployeeExtraFields:
|
|
61
|
+
"""
|
|
62
|
+
Class for handling employee extra fields.
|
|
63
|
+
|
|
64
|
+
Endpoints:
|
|
65
|
+
- GET /api/companies/{companyId}/employees/extraFields
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
def __init__(self, nmbrs):
|
|
69
|
+
self.nmbrs = nmbrs
|
|
70
|
+
|
|
71
|
+
def get(self,
|
|
72
|
+
company_id: Optional[str] = None,
|
|
73
|
+
extra_field_type: Optional[str] = None) -> tuple:
|
|
74
|
+
"""
|
|
75
|
+
Get extra fields for employees of a company.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
company_id: Optional company ID. If not provided, fetches for all companies.
|
|
79
|
+
extra_field_type: Optional filter by extra field type
|
|
80
|
+
(text, decimal, number, date, yesNo, textDate)
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Tuple of (valid_data, invalid_data) DataFrames
|
|
84
|
+
"""
|
|
85
|
+
if company_id:
|
|
86
|
+
df = self._get(company_id, extra_field_type)
|
|
87
|
+
else:
|
|
88
|
+
df = pd.DataFrame()
|
|
89
|
+
for company in self.nmbrs.company_ids:
|
|
90
|
+
df = pd.concat([df, self._get(company, extra_field_type)])
|
|
91
|
+
|
|
92
|
+
if df.empty:
|
|
93
|
+
return df, pd.DataFrame()
|
|
94
|
+
|
|
95
|
+
valid_data, invalid_data = Functions.validate_data(df=df, schema=EmployeeExtraFieldsGet, debug=self.nmbrs.debug)
|
|
96
|
+
return valid_data, invalid_data
|
|
97
|
+
|
|
98
|
+
def _get(self,
|
|
99
|
+
company_id: str,
|
|
100
|
+
extra_field_type: Optional[str] = None) -> pd.DataFrame:
|
|
101
|
+
"""
|
|
102
|
+
Internal method to get employee extra fields for a single company.
|
|
103
|
+
"""
|
|
104
|
+
params = {}
|
|
105
|
+
if extra_field_type is not None:
|
|
106
|
+
params['extraFieldType'] = extra_field_type
|
|
107
|
+
|
|
108
|
+
request = requests.Request(
|
|
109
|
+
method='GET',
|
|
110
|
+
url=f"{self.nmbrs.base_url}companies/{company_id}/employees/extraFields",
|
|
111
|
+
params=params
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
data = self.nmbrs.get_paginated_result(request)
|
|
115
|
+
|
|
116
|
+
# Normalize nested data structure
|
|
117
|
+
df = pd.json_normalize(
|
|
118
|
+
data,
|
|
119
|
+
record_path='extraFields',
|
|
120
|
+
meta=['employeeId']
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
if not df.empty:
|
|
124
|
+
df['companyId'] = company_id
|
|
125
|
+
|
|
126
|
+
return df
|
brynq_sdk_nmbrs/function.py
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
+
from typing import Any, Dict, Union
|
|
2
|
+
|
|
1
3
|
import pandas as pd
|
|
2
4
|
import requests
|
|
5
|
+
from zeep.exceptions import Fault
|
|
6
|
+
from zeep.helpers import serialize_object
|
|
7
|
+
|
|
3
8
|
from brynq_sdk_functions import Functions as BrynQFunctions
|
|
4
|
-
|
|
5
|
-
from typing import Dict, Any, Union
|
|
9
|
+
|
|
6
10
|
from .schemas.function import (
|
|
7
|
-
EmployeeFunctionGet,
|
|
8
|
-
|
|
11
|
+
EmployeeFunctionGet,
|
|
12
|
+
FunctionGet,
|
|
13
|
+
FunctionUpdate,
|
|
9
14
|
)
|
|
10
|
-
from zeep.exceptions import Fault
|
|
11
|
-
from zeep.helpers import serialize_object
|
|
12
15
|
|
|
13
16
|
|
|
14
17
|
class EmployeeFunction:
|
|
@@ -39,7 +42,7 @@ class EmployeeFunction:
|
|
|
39
42
|
record_path='functions',
|
|
40
43
|
meta=['employeeId']
|
|
41
44
|
)
|
|
42
|
-
except requests.HTTPError
|
|
45
|
+
except requests.HTTPError:
|
|
43
46
|
df = pd.DataFrame()
|
|
44
47
|
return df
|
|
45
48
|
|
|
@@ -59,9 +62,6 @@ class EmployeeFunction:
|
|
|
59
62
|
nested_data = self.nmbrs.flat_dict_to_nested_dict(data, FunctionUpdate)
|
|
60
63
|
function_model = FunctionUpdate(**nested_data)
|
|
61
64
|
|
|
62
|
-
if self.nmbrs.mock_mode:
|
|
63
|
-
return function_model
|
|
64
|
-
|
|
65
65
|
# Convert validated model to dict for API payload
|
|
66
66
|
payload = function_model.model_dump(exclude_none=True, by_alias=True)
|
|
67
67
|
|
|
@@ -83,9 +83,6 @@ class EmployeeFunction:
|
|
|
83
83
|
Returns:
|
|
84
84
|
DataFrame with current function
|
|
85
85
|
"""
|
|
86
|
-
if self.nmbrs.mock_mode:
|
|
87
|
-
return pd.DataFrame()
|
|
88
|
-
|
|
89
86
|
try:
|
|
90
87
|
response = self.nmbrs.soap_client_employees.service.Function_GetCurrent(
|
|
91
88
|
EmployeeId=int(employee_id),
|
|
@@ -114,102 +111,43 @@ class Functions:
|
|
|
114
111
|
def __init__(self, nmbrs):
|
|
115
112
|
self.nmbrs = nmbrs
|
|
116
113
|
|
|
117
|
-
def get(self, debtor_id: str) ->
|
|
118
|
-
try:
|
|
119
|
-
request = requests.Request(method='GET',
|
|
120
|
-
url=f"{self.nmbrs.base_url}debtors/{debtor_id}/functions")
|
|
121
|
-
|
|
122
|
-
data = self.nmbrs.get_paginated_result(request)
|
|
123
|
-
df = pd.DataFrame(data)
|
|
124
|
-
valid_functions, invalid_functions = BrynQFunctions.validate_data(df=df, schema=FunctionGet, debug=True)
|
|
125
|
-
|
|
126
|
-
except requests.HTTPError as e:
|
|
127
|
-
df = pd.DataFrame()
|
|
128
|
-
|
|
129
|
-
return valid_functions, invalid_functions
|
|
130
|
-
|
|
131
|
-
def create(self, debtor_id: Union[int, str], data: Dict[str, Any]):
|
|
114
|
+
def get(self, debtor_id: str = None) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
132
115
|
"""
|
|
133
|
-
|
|
116
|
+
Get all functions for debtor(s).
|
|
134
117
|
|
|
135
118
|
Args:
|
|
136
|
-
debtor_id:
|
|
137
|
-
data: Dictionary containing function data with fields matching FunctionCreate schema
|
|
119
|
+
debtor_id: Optional debtor ID. If not provided, fetches for all debtors.
|
|
138
120
|
|
|
139
121
|
Returns:
|
|
140
|
-
|
|
122
|
+
Tuple of (valid_functions, invalid_functions) DataFrames
|
|
141
123
|
"""
|
|
142
|
-
|
|
124
|
+
if debtor_id:
|
|
125
|
+
df = self._get(debtor_id)
|
|
126
|
+
else:
|
|
127
|
+
df = pd.DataFrame()
|
|
128
|
+
for debtor in self.nmbrs.debtor_ids:
|
|
129
|
+
df = pd.concat([df, self._get(debtor)])
|
|
143
130
|
|
|
144
|
-
if
|
|
145
|
-
return
|
|
131
|
+
if df.empty:
|
|
132
|
+
return df, pd.DataFrame()
|
|
146
133
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
DebtorId=int(debtor_id),
|
|
150
|
-
function={
|
|
151
|
-
'Id': 0, # 0 for new function
|
|
152
|
-
'Code': function_model.code,
|
|
153
|
-
'Description': function_model.description
|
|
154
|
-
},
|
|
155
|
-
_soapheaders={'AuthHeaderWithDomain': self.nmbrs.soap_auth_header_debtors}
|
|
156
|
-
)
|
|
157
|
-
return response
|
|
158
|
-
except Fault as e:
|
|
159
|
-
raise Exception(f"SOAP request failed: {str(e)}")
|
|
134
|
+
valid_functions, invalid_functions = BrynQFunctions.validate_data(df=df, schema=FunctionGet, debug=self.nmbrs.debug)
|
|
135
|
+
return valid_functions, invalid_functions
|
|
160
136
|
|
|
161
|
-
def
|
|
137
|
+
def _get(self, debtor_id: str) -> pd.DataFrame:
|
|
162
138
|
"""
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
Args:
|
|
166
|
-
debtor_id: The ID of the debtor
|
|
167
|
-
function_id: The ID of the function to delete
|
|
168
|
-
|
|
169
|
-
Returns:
|
|
170
|
-
Response from the API
|
|
139
|
+
Internal method to get functions for a single debtor.
|
|
171
140
|
"""
|
|
172
|
-
delete_model = FunctionDelete(function_id=int(function_id))
|
|
173
|
-
|
|
174
|
-
if self.nmbrs.mock_mode:
|
|
175
|
-
return delete_model
|
|
176
|
-
|
|
177
141
|
try:
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
_soapheaders={'AuthHeaderWithDomain': self.nmbrs.soap_auth_header_debtors}
|
|
182
|
-
)
|
|
183
|
-
return response
|
|
184
|
-
except Fault as e:
|
|
185
|
-
raise Exception(f"SOAP request failed: {str(e)}")
|
|
186
|
-
|
|
187
|
-
def update(self, debtor_id: Union[int, str], data: Dict[str, Any]):
|
|
188
|
-
"""
|
|
189
|
-
Update a master function using SOAP API.
|
|
190
|
-
|
|
191
|
-
Args:
|
|
192
|
-
debtor_id: The ID of the debtor
|
|
193
|
-
data: Dictionary containing function data with fields matching FunctionMasterUpdate schema
|
|
142
|
+
request = requests.Request(method='GET',
|
|
143
|
+
url=f"{self.nmbrs.base_url}debtors/{debtor_id}/functions",
|
|
144
|
+
params={"includeArchived": "true"})
|
|
194
145
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
function_model = FunctionMasterUpdate(**data)
|
|
146
|
+
data = self.nmbrs.get_paginated_result(request)
|
|
147
|
+
df = pd.DataFrame(data)
|
|
148
|
+
df['debtorId'] = debtor_id
|
|
199
149
|
|
|
200
|
-
|
|
201
|
-
|
|
150
|
+
except requests.HTTPError:
|
|
151
|
+
df = pd.DataFrame()
|
|
202
152
|
|
|
203
|
-
|
|
204
|
-
response = self.nmbrs.soap_client_debtors.service.Function_Update(
|
|
205
|
-
DebtorId=int(debtor_id),
|
|
206
|
-
function={
|
|
207
|
-
'Id': function_model.function_id,
|
|
208
|
-
'Code': function_model.code,
|
|
209
|
-
'Description': function_model.description
|
|
210
|
-
},
|
|
211
|
-
_soapheaders={'AuthHeaderWithDomain': self.nmbrs.soap_auth_header_debtors}
|
|
212
|
-
)
|
|
213
|
-
return response
|
|
214
|
-
except Fault as e:
|
|
215
|
-
raise Exception(f"SOAP request failed: {str(e)}")
|
|
153
|
+
return df
|
brynq_sdk_nmbrs/leave.py
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
|
-
import
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
|
|
2
3
|
import pandas as pd
|
|
3
4
|
import requests
|
|
4
|
-
from brynq_sdk_functions import Functions
|
|
5
|
-
from typing import Dict, Any, Union
|
|
6
|
-
from .schemas.leave import LeaveBalanceGet, LeaveGet, LeaveCreate, LeaveDelete, LeaveUpdate
|
|
7
5
|
from zeep.exceptions import Fault
|
|
8
6
|
|
|
7
|
+
from brynq_sdk_functions import Functions
|
|
8
|
+
|
|
9
|
+
from .schemas.leave import (
|
|
10
|
+
LeaveBalanceGet,
|
|
11
|
+
LeaveCreate,
|
|
12
|
+
LeaveDelete,
|
|
13
|
+
LeaveGet,
|
|
14
|
+
LeaveUpdate,
|
|
15
|
+
)
|
|
16
|
+
|
|
9
17
|
|
|
10
18
|
class Leave:
|
|
11
19
|
def __init__(self, nmbrs):
|
|
@@ -38,7 +46,7 @@ class Leave:
|
|
|
38
46
|
record_path='EmployeeLeaveRequests',
|
|
39
47
|
meta=['employeeId']
|
|
40
48
|
)
|
|
41
|
-
except requests.HTTPError
|
|
49
|
+
except requests.HTTPError:
|
|
42
50
|
df = pd.DataFrame()
|
|
43
51
|
|
|
44
52
|
return df
|
|
@@ -164,7 +172,7 @@ class LeaveBalance:
|
|
|
164
172
|
record_path='leaveBalances',
|
|
165
173
|
meta=['employeeId']
|
|
166
174
|
)
|
|
167
|
-
except requests.HTTPError
|
|
175
|
+
except requests.HTTPError:
|
|
168
176
|
df = pd.DataFrame()
|
|
169
177
|
|
|
170
178
|
return df
|
|
@@ -172,65 +180,52 @@ class LeaveBalance:
|
|
|
172
180
|
|
|
173
181
|
class LeaveGroup:
|
|
174
182
|
"""
|
|
175
|
-
|
|
183
|
+
Class for handling company leave groups.
|
|
184
|
+
|
|
185
|
+
Endpoints:
|
|
186
|
+
- GET /api/companies/{companyId}/leaveGroups
|
|
176
187
|
"""
|
|
188
|
+
|
|
177
189
|
def __init__(self, nmbrs):
|
|
178
190
|
self.nmbrs = nmbrs
|
|
179
191
|
|
|
180
|
-
def get(self, company_id:
|
|
192
|
+
def get(self, company_id: str = None) -> pd.DataFrame:
|
|
181
193
|
"""
|
|
182
|
-
Get leave
|
|
183
|
-
|
|
194
|
+
Get leave groups available in a company.
|
|
195
|
+
|
|
196
|
+
A company can have up to 4 leave groups defined.
|
|
197
|
+
|
|
184
198
|
Args:
|
|
185
|
-
company_id: Optional. If provided,
|
|
186
|
-
|
|
187
|
-
|
|
199
|
+
company_id: Optional company ID. If not provided, fetches for all companies.
|
|
200
|
+
|
|
188
201
|
Returns:
|
|
189
|
-
DataFrame
|
|
202
|
+
DataFrame containing leave groups
|
|
190
203
|
"""
|
|
191
|
-
if
|
|
192
|
-
return
|
|
204
|
+
if company_id:
|
|
205
|
+
return self._get(company_id)
|
|
193
206
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
207
|
+
leave_groups = pd.DataFrame()
|
|
208
|
+
for company in self.nmbrs.company_ids:
|
|
209
|
+
leave_groups = pd.concat([leave_groups, self._get(company)])
|
|
210
|
+
|
|
211
|
+
return leave_groups
|
|
212
|
+
|
|
213
|
+
def _get(self, company_id: str) -> pd.DataFrame:
|
|
214
|
+
"""
|
|
215
|
+
Internal method to get leave groups for a single company.
|
|
216
|
+
"""
|
|
197
217
|
try:
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
elif isinstance(companies_response, list):
|
|
213
|
-
companies = companies_response
|
|
214
|
-
|
|
215
|
-
company_ids = [c.ID for c in companies]
|
|
216
|
-
|
|
217
|
-
for cid in company_ids:
|
|
218
|
-
try:
|
|
219
|
-
response = self.nmbrs.soap_client_companies.service.CompanyLeaveTypeGroups_Get(
|
|
220
|
-
CompanyId=cid,
|
|
221
|
-
_soapheaders={'AuthHeaderWithDomain': self.nmbrs.soap_auth_header}
|
|
222
|
-
)
|
|
223
|
-
if response and response.LeaveTypeGroup:
|
|
224
|
-
groups = serialize_object(response.LeaveTypeGroup)
|
|
225
|
-
if not isinstance(groups, list):
|
|
226
|
-
groups = [groups]
|
|
227
|
-
for group in groups:
|
|
228
|
-
group['company_id'] = str(cid)
|
|
229
|
-
all_groups.extend(groups)
|
|
230
|
-
except Exception:
|
|
231
|
-
continue
|
|
232
|
-
|
|
233
|
-
return pd.DataFrame(all_groups)
|
|
234
|
-
|
|
235
|
-
except Fault as e:
|
|
236
|
-
raise Exception(f"SOAP request failed: {str(e)}")
|
|
218
|
+
request = requests.Request(
|
|
219
|
+
method='GET',
|
|
220
|
+
url=f"{self.nmbrs.base_url}companies/{company_id}/leaveGroups"
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
data = self.nmbrs.get_paginated_result(request)
|
|
224
|
+
df = pd.DataFrame(data)
|
|
225
|
+
|
|
226
|
+
if not df.empty:
|
|
227
|
+
df['companyId'] = company_id
|
|
228
|
+
|
|
229
|
+
return df
|
|
230
|
+
except requests.HTTPError:
|
|
231
|
+
return pd.DataFrame()
|