brynq-sdk-nmbrs 2.3.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_nmbrs/__init__.py +226 -0
- brynq_sdk_nmbrs/absence.py +124 -0
- brynq_sdk_nmbrs/address.py +66 -0
- brynq_sdk_nmbrs/bank.py +125 -0
- brynq_sdk_nmbrs/children.py +100 -0
- brynq_sdk_nmbrs/companies.py +93 -0
- brynq_sdk_nmbrs/contract.py +132 -0
- brynq_sdk_nmbrs/costcenter.py +166 -0
- brynq_sdk_nmbrs/costunit.py +90 -0
- brynq_sdk_nmbrs/days.py +137 -0
- brynq_sdk_nmbrs/debtors.py +25 -0
- brynq_sdk_nmbrs/department.py +122 -0
- brynq_sdk_nmbrs/document.py +30 -0
- brynq_sdk_nmbrs/employees.py +196 -0
- brynq_sdk_nmbrs/employment.py +107 -0
- brynq_sdk_nmbrs/function.py +89 -0
- brynq_sdk_nmbrs/hours.py +252 -0
- brynq_sdk_nmbrs/leave.py +139 -0
- brynq_sdk_nmbrs/manager.py +294 -0
- brynq_sdk_nmbrs/salaries.py +85 -0
- brynq_sdk_nmbrs/salary_tables.py +242 -0
- brynq_sdk_nmbrs/schedules.py +84 -0
- brynq_sdk_nmbrs/schemas/__init__.py +37 -0
- brynq_sdk_nmbrs/schemas/absence.py +61 -0
- brynq_sdk_nmbrs/schemas/address.py +76 -0
- brynq_sdk_nmbrs/schemas/bank.py +83 -0
- brynq_sdk_nmbrs/schemas/contracts.py +60 -0
- brynq_sdk_nmbrs/schemas/costcenter.py +91 -0
- brynq_sdk_nmbrs/schemas/costunit.py +40 -0
- brynq_sdk_nmbrs/schemas/days.py +98 -0
- brynq_sdk_nmbrs/schemas/debtor.py +16 -0
- brynq_sdk_nmbrs/schemas/department.py +57 -0
- brynq_sdk_nmbrs/schemas/employees.py +153 -0
- brynq_sdk_nmbrs/schemas/employment.py +48 -0
- brynq_sdk_nmbrs/schemas/function.py +50 -0
- brynq_sdk_nmbrs/schemas/hours.py +121 -0
- brynq_sdk_nmbrs/schemas/leave.py +53 -0
- brynq_sdk_nmbrs/schemas/manager.py +126 -0
- brynq_sdk_nmbrs/schemas/salary.py +92 -0
- brynq_sdk_nmbrs/schemas/schedules.py +96 -0
- brynq_sdk_nmbrs/schemas/social_insurance.py +40 -0
- brynq_sdk_nmbrs/schemas/wage_tax.py +98 -0
- brynq_sdk_nmbrs/schemas/wagecomponents.py +114 -0
- brynq_sdk_nmbrs/social_insurance.py +52 -0
- brynq_sdk_nmbrs/wage_tax.py +164 -0
- brynq_sdk_nmbrs/wagecomponents.py +268 -0
- brynq_sdk_nmbrs-2.3.1.dist-info/METADATA +21 -0
- brynq_sdk_nmbrs-2.3.1.dist-info/RECORD +50 -0
- brynq_sdk_nmbrs-2.3.1.dist-info/WHEEL +5 -0
- brynq_sdk_nmbrs-2.3.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import requests
|
|
4
|
+
from typing import Dict, Any
|
|
5
|
+
from .schemas.department import DepartmentCreate, EmployeeDepartmentUpdate, Period, EmployeeDepartmentGet, DepartmentGet
|
|
6
|
+
from brynq_sdk_functions import Functions
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class EmployeeDepartment:
|
|
10
|
+
def __init__(self, nmbrs):
|
|
11
|
+
self.nmbrs = nmbrs
|
|
12
|
+
|
|
13
|
+
def get(self,
|
|
14
|
+
created_from: str = None,
|
|
15
|
+
employee_id: str = None) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
16
|
+
departments = pd.DataFrame()
|
|
17
|
+
for company in self.nmbrs.company_ids:
|
|
18
|
+
departments = pd.concat([departments, self._get(company, created_from, employee_id)])
|
|
19
|
+
|
|
20
|
+
valid_departments, invalid_departments = Functions.validate_data(df=departments, schema=EmployeeDepartmentGet, debug=True)
|
|
21
|
+
|
|
22
|
+
return valid_departments, invalid_departments
|
|
23
|
+
|
|
24
|
+
def _get(self,
|
|
25
|
+
company_id: str,
|
|
26
|
+
created_from: str = None,
|
|
27
|
+
employee_id: str = None) -> pd.DataFrame:
|
|
28
|
+
params = {}
|
|
29
|
+
if created_from:
|
|
30
|
+
params['createdFrom'] = created_from
|
|
31
|
+
if employee_id:
|
|
32
|
+
params['employeeId'] = employee_id
|
|
33
|
+
request = requests.Request(method='GET',
|
|
34
|
+
url=f"{self.nmbrs.base_url}companies/{company_id}/employees/departments",
|
|
35
|
+
params=params)
|
|
36
|
+
|
|
37
|
+
data = self.nmbrs.get_paginated_result(request)
|
|
38
|
+
df = pd.json_normalize(
|
|
39
|
+
data,
|
|
40
|
+
record_path='departments',
|
|
41
|
+
meta=['employeeId']
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
return df
|
|
45
|
+
|
|
46
|
+
def create(self, employee_id: str, data: Dict[str, Any]):
|
|
47
|
+
"""
|
|
48
|
+
Create a new department for an employee using Pydantic validation.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
employee_id: The ID of the employee
|
|
52
|
+
data: Dictionary containing department data with fields matching
|
|
53
|
+
the DepartmentCreate schema (using camelCase field names)
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
Response from the API
|
|
57
|
+
"""
|
|
58
|
+
# Validate with Pydantic model
|
|
59
|
+
nested_data = self.nmbrs.flat_dict_to_nested_dict(data, DepartmentCreate)
|
|
60
|
+
department_model = DepartmentCreate(**nested_data)
|
|
61
|
+
|
|
62
|
+
if self.nmbrs.mock_mode:
|
|
63
|
+
return department_model
|
|
64
|
+
|
|
65
|
+
# Convert validated model to dict for API payload
|
|
66
|
+
payload = department_model.model_dump(exclude_none=True, by_alias=True)
|
|
67
|
+
|
|
68
|
+
# Send request
|
|
69
|
+
resp = self.nmbrs.session.post(
|
|
70
|
+
url=f"{self.nmbrs.base_url}employees/{employee_id}/department",
|
|
71
|
+
json=payload,
|
|
72
|
+
timeout=self.nmbrs.timeout
|
|
73
|
+
)
|
|
74
|
+
return resp
|
|
75
|
+
|
|
76
|
+
def update(self, employee_id: str, data: Dict[str, Any]):
|
|
77
|
+
"""
|
|
78
|
+
Update a department for an employee using Pydantic validation.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
employee_id: The ID of the employee
|
|
82
|
+
data: Dictionary containing department data with fields matching
|
|
83
|
+
the DepartmentUpdate schema (using camelCase field names)
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Response from the API
|
|
87
|
+
"""
|
|
88
|
+
# Validate with Pydantic model
|
|
89
|
+
nested_data = self.nmbrs.flat_dict_to_nested_dict(data, EmployeeDepartmentUpdate)
|
|
90
|
+
department_model = EmployeeDepartmentUpdate(**nested_data)
|
|
91
|
+
|
|
92
|
+
if self.nmbrs.mock_mode:
|
|
93
|
+
return department_model
|
|
94
|
+
|
|
95
|
+
# Convert validated model to dict for API payload
|
|
96
|
+
payload = department_model.model_dump(exclude_none=True, by_alias=True)
|
|
97
|
+
|
|
98
|
+
# Send request
|
|
99
|
+
resp = self.nmbrs.session.put(
|
|
100
|
+
url=f"{self.nmbrs.base_url}employees/{employee_id}/department",
|
|
101
|
+
json=payload,
|
|
102
|
+
timeout=self.nmbrs.timeout
|
|
103
|
+
)
|
|
104
|
+
return resp
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class Departments:
|
|
109
|
+
def __init__(self, nmbrs):
|
|
110
|
+
self.nmbrs = nmbrs
|
|
111
|
+
|
|
112
|
+
def get(self,
|
|
113
|
+
debtor_id: str) -> pd.DataFrame:
|
|
114
|
+
request = requests.Request(method='GET',
|
|
115
|
+
url=f"{self.nmbrs.base_url}debtors/{debtor_id}/departments")
|
|
116
|
+
|
|
117
|
+
data = self.nmbrs.get_paginated_result(request)
|
|
118
|
+
|
|
119
|
+
df = pd.DataFrame(data)
|
|
120
|
+
valid_departments, invalid_departments = Functions.validate_data(df=df, schema=DepartmentGet, debug=True)
|
|
121
|
+
|
|
122
|
+
return valid_departments, invalid_departments
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from io import BytesIO
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
import requests
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Payslip:
|
|
8
|
+
def __init__(self, nmbrs):
|
|
9
|
+
self.nmbrs = nmbrs
|
|
10
|
+
|
|
11
|
+
def get(self,
|
|
12
|
+
employee_id: str,
|
|
13
|
+
period: int = None,
|
|
14
|
+
year: int = None) -> pd.DataFrame:
|
|
15
|
+
params = {}
|
|
16
|
+
if period:
|
|
17
|
+
params['period'] = period
|
|
18
|
+
if year:
|
|
19
|
+
params['year'] = year
|
|
20
|
+
resp = self.nmbrs.session.get(f"{self.nmbrs.base_url}employees/{employee_id}/payslipperperiod/",
|
|
21
|
+
params=params,
|
|
22
|
+
timeout=self.nmbrs.timeout)
|
|
23
|
+
resp.raise_for_status()
|
|
24
|
+
task_id = resp.json()['taskId']
|
|
25
|
+
|
|
26
|
+
resp = self.nmbrs.session.get(f"{self.nmbrs.base_url}documents/{task_id}", timeout=self.nmbrs.timeout)
|
|
27
|
+
|
|
28
|
+
return BytesIO(resp.content)
|
|
29
|
+
|
|
30
|
+
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import requests
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
|
|
5
|
+
from brynq_sdk_functions import Functions
|
|
6
|
+
from typing import Dict, Any, Optional
|
|
7
|
+
|
|
8
|
+
from .wage_tax import WageTax
|
|
9
|
+
|
|
10
|
+
from .document import Payslip
|
|
11
|
+
from .address import Address
|
|
12
|
+
from .contract import Contract
|
|
13
|
+
from .costcenter import EmployeeCostcenter
|
|
14
|
+
from .department import EmployeeDepartment
|
|
15
|
+
from .employment import Employment
|
|
16
|
+
from .function import EmployeeFunction
|
|
17
|
+
from .hours import VariableHours, FixedHours
|
|
18
|
+
from .schedules import Schedule
|
|
19
|
+
from .salaries import Salaries
|
|
20
|
+
from .bank import Bank
|
|
21
|
+
from .days import VariableDays
|
|
22
|
+
from .wagecomponents import EmployeeVariableWageComponents, EmployeeFixedWageComponents
|
|
23
|
+
from .leave import Leave, LeaveBalance
|
|
24
|
+
from .schemas.employees import (
|
|
25
|
+
BsnGet, EmployeeGet, EmployeeCreate, EmployeeUpdate, EmployeeDelete,
|
|
26
|
+
BasicInfo, BirthInfo, ContactInfo, PartnerInfo, Period, AdditionalEmployeeInfo,
|
|
27
|
+
CreateEmployeePersonalInfo
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class Employees:
|
|
32
|
+
def __init__(self, nmbrs):
|
|
33
|
+
self.nmbrs = nmbrs
|
|
34
|
+
self.address = Address(nmbrs)
|
|
35
|
+
self.functions = EmployeeFunction(nmbrs)
|
|
36
|
+
self.contract = Contract(nmbrs)
|
|
37
|
+
self.departments = EmployeeDepartment(nmbrs)
|
|
38
|
+
self.costcenter = EmployeeCostcenter(nmbrs)
|
|
39
|
+
self.schedule = Schedule(nmbrs)
|
|
40
|
+
self.employment = Employment(nmbrs)
|
|
41
|
+
self.variable_hours = VariableHours(nmbrs)
|
|
42
|
+
self.fixed_hours = FixedHours(nmbrs)
|
|
43
|
+
self.variable_days = VariableDays(nmbrs)
|
|
44
|
+
self.salaries = Salaries(nmbrs)
|
|
45
|
+
self.variable_wagecomponents = EmployeeVariableWageComponents(nmbrs)
|
|
46
|
+
self.fixed_wagecomponents = EmployeeFixedWageComponents(nmbrs)
|
|
47
|
+
self.banks = Bank(nmbrs)
|
|
48
|
+
self.payslips = Payslip(nmbrs)
|
|
49
|
+
self.wage_tax = WageTax(nmbrs)
|
|
50
|
+
self.leave = Leave(nmbrs)
|
|
51
|
+
self.leave_balance = LeaveBalance(nmbrs)
|
|
52
|
+
|
|
53
|
+
def get(self,
|
|
54
|
+
employee_type: str = None
|
|
55
|
+
) -> (pd.DataFrame, pd.DataFrame):
|
|
56
|
+
employees = pd.DataFrame()
|
|
57
|
+
for company in self.nmbrs.company_ids:
|
|
58
|
+
employees = pd.concat([employees, self._get(company, employee_type)])
|
|
59
|
+
|
|
60
|
+
valid_employees, invalid_employees = Functions.validate_data(df=employees, schema=EmployeeGet, debug=True)
|
|
61
|
+
|
|
62
|
+
return valid_employees, invalid_employees
|
|
63
|
+
|
|
64
|
+
def _get(self,
|
|
65
|
+
company_id: str,
|
|
66
|
+
employee_type: str = None) -> pd.DataFrame:
|
|
67
|
+
params = {} if employee_type is None else {'employeeType': employee_type}
|
|
68
|
+
request = requests.Request(method='GET',
|
|
69
|
+
url=f"{self.nmbrs.base_url}companies/{company_id}/employees/personalinfo",
|
|
70
|
+
params=params)
|
|
71
|
+
|
|
72
|
+
data = self.nmbrs.get_paginated_result(request)
|
|
73
|
+
df = pd.json_normalize(
|
|
74
|
+
data,
|
|
75
|
+
record_path='info',
|
|
76
|
+
meta=['employeeId']
|
|
77
|
+
)
|
|
78
|
+
df['companyId'] = company_id
|
|
79
|
+
|
|
80
|
+
df['createdAt'] = pd.to_datetime(df['createdAt'])
|
|
81
|
+
df = df.loc[df.groupby('employeeId')['createdAt'].idxmax()]
|
|
82
|
+
df = df.reset_index(drop=True)
|
|
83
|
+
|
|
84
|
+
return df
|
|
85
|
+
|
|
86
|
+
def get_private_info(self) -> str:
|
|
87
|
+
combined = []
|
|
88
|
+
for company_id in self.nmbrs.company_ids:
|
|
89
|
+
request = requests.Request(method='GET',
|
|
90
|
+
url=f"{self.nmbrs.base_url}companies/{company_id}/employees/privateInfos")
|
|
91
|
+
data = self.nmbrs.get_paginated_result(request)
|
|
92
|
+
df = pd.json_normalize(
|
|
93
|
+
data,
|
|
94
|
+
record_path='privateInfos',
|
|
95
|
+
meta=['employeeId']
|
|
96
|
+
)
|
|
97
|
+
df['companyId'] = company_id
|
|
98
|
+
combined.append(df)
|
|
99
|
+
df = pd.concat(combined, ignore_index=True)
|
|
100
|
+
valid_bsn, invalid_bsn = Functions.validate_data(df, BsnGet)
|
|
101
|
+
|
|
102
|
+
return valid_bsn, invalid_bsn
|
|
103
|
+
|
|
104
|
+
def get_default_templates(self) -> pd.DataFrame:
|
|
105
|
+
default_templates = pd.DataFrame()
|
|
106
|
+
for company in self.nmbrs.company_ids:
|
|
107
|
+
default_templates_temp = self._get_default_templates(company)
|
|
108
|
+
default_templates_temp['companyId'] = company
|
|
109
|
+
default_templates = pd.concat([default_templates, default_templates_temp])
|
|
110
|
+
|
|
111
|
+
# valid_default_templates, invalid_default_templates = Functions.validate_data(df=default_templates, schema=EmployeeGet, debug=True)
|
|
112
|
+
|
|
113
|
+
return default_templates
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _get_default_templates(self, company_id: str, employee_type: str = None) -> pd.DataFrame:
|
|
117
|
+
params = {} if employee_type is None else {'employeeType': employee_type}
|
|
118
|
+
request = requests.Request(method='GET',
|
|
119
|
+
url=f"{self.nmbrs.base_url}companies/{company_id}/defaulttemplates",
|
|
120
|
+
params=params)
|
|
121
|
+
data = self.nmbrs.get_paginated_result(request)
|
|
122
|
+
return pd.DataFrame(data)
|
|
123
|
+
|
|
124
|
+
def create(self, company_id: str, data: Dict[str, Any]):
|
|
125
|
+
"""
|
|
126
|
+
Create a new employee using Pydantic validation.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
company_id: The ID of the company
|
|
130
|
+
data: Dictionary structured according to the EmployeeCreate schema with:
|
|
131
|
+
- PersonalInfo: containing basicInfo, birthInfo, contactInfo, etc.
|
|
132
|
+
- AdditionalEmployeeInfo: containing service date, etc.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
Response from the API
|
|
136
|
+
"""
|
|
137
|
+
# Validate with Pydantic model
|
|
138
|
+
nested_data = self.nmbrs.flat_dict_to_nested_dict(data, EmployeeCreate)
|
|
139
|
+
employee_model = EmployeeCreate(**nested_data)
|
|
140
|
+
|
|
141
|
+
if self.nmbrs.mock_mode:
|
|
142
|
+
return employee_model
|
|
143
|
+
|
|
144
|
+
# Convert validated model to dict for API payload
|
|
145
|
+
payload = employee_model.model_dump(exclude_none=True, by_alias=True)
|
|
146
|
+
|
|
147
|
+
# Send request
|
|
148
|
+
resp = self.nmbrs.session.post(
|
|
149
|
+
url=f"{self.nmbrs.base_url}companies/{company_id}/employees",
|
|
150
|
+
json=payload,
|
|
151
|
+
timeout=self.nmbrs.timeout
|
|
152
|
+
)
|
|
153
|
+
return resp
|
|
154
|
+
|
|
155
|
+
def update(self, employee_id: str, data: Dict[str, Any]):
|
|
156
|
+
"""
|
|
157
|
+
Update an employee using Pydantic validation.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
employee_id: The ID of the employee
|
|
161
|
+
data: Dictionary structured according to the EmployeeUpdate schema with:
|
|
162
|
+
- employeeId: The ID of the employee to update
|
|
163
|
+
- personalInfo: containing any of basicInfo, birthInfo, contactInfo, etc.
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
Response from the API
|
|
167
|
+
"""
|
|
168
|
+
# Validate with Pydantic model
|
|
169
|
+
nested_data = self.nmbrs.flat_dict_to_nested_dict(data, EmployeeUpdate)
|
|
170
|
+
employee_model = EmployeeUpdate(**nested_data)
|
|
171
|
+
|
|
172
|
+
if self.nmbrs.mock_mode:
|
|
173
|
+
return employee_model
|
|
174
|
+
|
|
175
|
+
# Convert validated model to dict for API payload
|
|
176
|
+
payload = employee_model.model_dump(exclude_none=True, by_alias=True)
|
|
177
|
+
|
|
178
|
+
# Send request
|
|
179
|
+
resp = self.nmbrs.session.put(
|
|
180
|
+
url=f"{self.nmbrs.base_url}employees/{employee_id}/personalInfo",
|
|
181
|
+
json=payload,
|
|
182
|
+
timeout=self.nmbrs.timeout
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# Handle social security number update if present
|
|
186
|
+
if 'socialSecurityNumber' in data:
|
|
187
|
+
social_security_payload = {
|
|
188
|
+
"socialSecurityNumber": data['socialSecurityNumber']
|
|
189
|
+
}
|
|
190
|
+
resp = self.nmbrs.session.put(
|
|
191
|
+
url=f"{self.nmbrs.base_url}employees/{employee_id}/social_security_number",
|
|
192
|
+
json=social_security_payload,
|
|
193
|
+
timeout=self.nmbrs.timeout
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
return resp
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import requests
|
|
4
|
+
from brynq_sdk_functions import Functions
|
|
5
|
+
from typing import Dict, Any
|
|
6
|
+
from .schemas.employment import EmploymentGet, EmploymentCreate, EmploymentUpdate, EmploymentDelete
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Employment:
|
|
10
|
+
def __init__(self, nmbrs):
|
|
11
|
+
self.nmbrs = nmbrs
|
|
12
|
+
|
|
13
|
+
def get(self,
|
|
14
|
+
changed_from: str = None,
|
|
15
|
+
created_from: str = None,
|
|
16
|
+
employee_id: str = None) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
17
|
+
employments = pd.DataFrame()
|
|
18
|
+
for company in self.nmbrs.company_ids:
|
|
19
|
+
employments = pd.concat([employments, self._get(company, changed_from, created_from, employee_id)])
|
|
20
|
+
|
|
21
|
+
valid_employments, invalid_employments = Functions.validate_data(df=employments, schema=EmploymentGet, debug=True)
|
|
22
|
+
|
|
23
|
+
return valid_employments, invalid_employments
|
|
24
|
+
|
|
25
|
+
def _get(self,
|
|
26
|
+
company_id: str,
|
|
27
|
+
changed_from: str = None,
|
|
28
|
+
created_from: str = None,
|
|
29
|
+
employee_id: str = None) -> pd.DataFrame:
|
|
30
|
+
params = {}
|
|
31
|
+
if created_from:
|
|
32
|
+
params['createdFrom'] = created_from
|
|
33
|
+
if employee_id:
|
|
34
|
+
params['changedFrom'] = changed_from
|
|
35
|
+
if employee_id:
|
|
36
|
+
params['employeeId'] = employee_id
|
|
37
|
+
request = requests.Request(method='GET',
|
|
38
|
+
url=f"{self.nmbrs.base_url}companies/{company_id}/employees/employments",
|
|
39
|
+
params=params)
|
|
40
|
+
data = self.nmbrs.get_paginated_result(request)
|
|
41
|
+
df = pd.json_normalize(
|
|
42
|
+
data,
|
|
43
|
+
record_path='employments',
|
|
44
|
+
meta=['employeeId']
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
return df
|
|
48
|
+
|
|
49
|
+
def create(self, employee_id: str, data: Dict[str, Any]):
|
|
50
|
+
"""
|
|
51
|
+
Create a new employment record for an employee using Pydantic validation.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
employee_id: The ID of the employee
|
|
55
|
+
data: Dictionary containing employment data with fields matching
|
|
56
|
+
the EmploymentCreate schema (using camelCase field names)
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
Response from the API
|
|
60
|
+
"""
|
|
61
|
+
# Validate with Pydantic model
|
|
62
|
+
nested_data = self.nmbrs.flat_dict_to_nested_dict(data, EmploymentCreate)
|
|
63
|
+
employment_model = EmploymentCreate(**nested_data)
|
|
64
|
+
|
|
65
|
+
if self.nmbrs.mock_mode:
|
|
66
|
+
return employment_model
|
|
67
|
+
|
|
68
|
+
# Convert validated model to dict for API payload
|
|
69
|
+
payload = employment_model.model_dump(exclude_none=True, by_alias=True)
|
|
70
|
+
|
|
71
|
+
# Send request
|
|
72
|
+
resp = self.nmbrs.session.post(
|
|
73
|
+
url=f"{self.nmbrs.base_url}employees/{employee_id}/employment",
|
|
74
|
+
json=payload,
|
|
75
|
+
timeout=self.nmbrs.timeout
|
|
76
|
+
)
|
|
77
|
+
return resp
|
|
78
|
+
|
|
79
|
+
def update(self, employee_id: str, data: Dict[str, Any]):
|
|
80
|
+
"""
|
|
81
|
+
Update an employment record for an employee using Pydantic validation.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
employee_id: The ID of the employee
|
|
85
|
+
data: Dictionary containing employment data with fields matching
|
|
86
|
+
the EmploymentUpdate schema (using camelCase field names)
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
Response from the API
|
|
90
|
+
"""
|
|
91
|
+
# Validate with Pydantic model
|
|
92
|
+
nested_data = self.nmbrs.flat_dict_to_nested_dict(data, EmploymentUpdate)
|
|
93
|
+
employment_model = EmploymentUpdate(**nested_data)
|
|
94
|
+
|
|
95
|
+
if self.nmbrs.mock_mode:
|
|
96
|
+
return employment_model
|
|
97
|
+
|
|
98
|
+
# Convert validated model to dict for API payload
|
|
99
|
+
payload = employment_model.model_dump(exclude_none=True, by_alias=True)
|
|
100
|
+
|
|
101
|
+
# Send request
|
|
102
|
+
resp = self.nmbrs.session.put(
|
|
103
|
+
url=f"{self.nmbrs.base_url}employees/{employee_id}/employment",
|
|
104
|
+
json=payload,
|
|
105
|
+
timeout=self.nmbrs.timeout
|
|
106
|
+
)
|
|
107
|
+
return resp
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import requests
|
|
3
|
+
from brynq_sdk_functions import Functions as BrynQFunctions
|
|
4
|
+
import math
|
|
5
|
+
from typing import Dict, Any
|
|
6
|
+
from .schemas.function import EmployeeFunctionGet, FunctionUpdate, FunctionGet
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class EmployeeFunction:
|
|
10
|
+
def __init__(self, nmbrs):
|
|
11
|
+
self.nmbrs = nmbrs
|
|
12
|
+
|
|
13
|
+
def get(self,
|
|
14
|
+
created_from: str = None) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
15
|
+
functions = pd.DataFrame()
|
|
16
|
+
for company in self.nmbrs.company_ids:
|
|
17
|
+
functions = pd.concat([functions, self._get(company, created_from)])
|
|
18
|
+
|
|
19
|
+
valid_functions, invalid_functions = BrynQFunctions.validate_data(df=functions, schema=EmployeeFunctionGet, debug=True)
|
|
20
|
+
|
|
21
|
+
return valid_functions, invalid_functions
|
|
22
|
+
|
|
23
|
+
def _get(self,
|
|
24
|
+
company_id: str,
|
|
25
|
+
created_from: str = None) -> pd.DataFrame:
|
|
26
|
+
params = {}
|
|
27
|
+
if created_from:
|
|
28
|
+
params['createdFrom'] = created_from
|
|
29
|
+
try:
|
|
30
|
+
request = requests.Request(method='GET', url=f"{self.nmbrs.base_url}companies/{company_id}/employees/functions", params=params)
|
|
31
|
+
data = self.nmbrs.get_paginated_result(request)
|
|
32
|
+
df = pd.json_normalize(
|
|
33
|
+
data,
|
|
34
|
+
record_path='functions',
|
|
35
|
+
meta=['employeeId']
|
|
36
|
+
)
|
|
37
|
+
except requests.HTTPError as e:
|
|
38
|
+
df = pd.DataFrame()
|
|
39
|
+
return df
|
|
40
|
+
|
|
41
|
+
def update(self, employee_id: str, data: Dict[str, Any]):
|
|
42
|
+
"""
|
|
43
|
+
Update a function for an employee using Pydantic validation.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
employee_id: The ID of the employee
|
|
47
|
+
data: Dictionary containing function data with fields matching
|
|
48
|
+
the FunctionUpdate schema (using camelCase field names)
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
Response from the API
|
|
52
|
+
"""
|
|
53
|
+
# Validate with Pydantic model
|
|
54
|
+
nested_data = self.nmbrs.flat_dict_to_nested_dict(data, FunctionUpdate)
|
|
55
|
+
function_model = FunctionUpdate(**nested_data)
|
|
56
|
+
|
|
57
|
+
if self.nmbrs.mock_mode:
|
|
58
|
+
return function_model
|
|
59
|
+
|
|
60
|
+
# Convert validated model to dict for API payload
|
|
61
|
+
payload = function_model.model_dump(exclude_none=True, by_alias=True)
|
|
62
|
+
|
|
63
|
+
# Send request
|
|
64
|
+
resp = self.nmbrs.session.put(
|
|
65
|
+
url=f"{self.nmbrs.base_url}employees/{employee_id}/function",
|
|
66
|
+
json=payload,
|
|
67
|
+
timeout=self.nmbrs.timeout
|
|
68
|
+
)
|
|
69
|
+
return resp
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class Functions:
|
|
74
|
+
def __init__(self, nmbrs):
|
|
75
|
+
self.nmbrs = nmbrs
|
|
76
|
+
|
|
77
|
+
def get(self, debtor_id: str) -> (pd.DataFrame, pd.DataFrame):
|
|
78
|
+
try:
|
|
79
|
+
request = requests.Request(method='GET',
|
|
80
|
+
url=f"{self.nmbrs.base_url}debtors/{debtor_id}/functions")
|
|
81
|
+
|
|
82
|
+
data = self.nmbrs.get_paginated_result(request)
|
|
83
|
+
df = pd.DataFrame(data)
|
|
84
|
+
valid_functions, invalid_functions = BrynQFunctions.validate_data(df=df, schema=FunctionGet, debug=True)
|
|
85
|
+
|
|
86
|
+
except requests.HTTPError as e:
|
|
87
|
+
df = pd.DataFrame()
|
|
88
|
+
|
|
89
|
+
return valid_functions, invalid_functions
|