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.
Files changed (50) hide show
  1. brynq_sdk_nmbrs/__init__.py +226 -0
  2. brynq_sdk_nmbrs/absence.py +124 -0
  3. brynq_sdk_nmbrs/address.py +66 -0
  4. brynq_sdk_nmbrs/bank.py +125 -0
  5. brynq_sdk_nmbrs/children.py +100 -0
  6. brynq_sdk_nmbrs/companies.py +93 -0
  7. brynq_sdk_nmbrs/contract.py +132 -0
  8. brynq_sdk_nmbrs/costcenter.py +166 -0
  9. brynq_sdk_nmbrs/costunit.py +90 -0
  10. brynq_sdk_nmbrs/days.py +137 -0
  11. brynq_sdk_nmbrs/debtors.py +25 -0
  12. brynq_sdk_nmbrs/department.py +122 -0
  13. brynq_sdk_nmbrs/document.py +30 -0
  14. brynq_sdk_nmbrs/employees.py +196 -0
  15. brynq_sdk_nmbrs/employment.py +107 -0
  16. brynq_sdk_nmbrs/function.py +89 -0
  17. brynq_sdk_nmbrs/hours.py +252 -0
  18. brynq_sdk_nmbrs/leave.py +139 -0
  19. brynq_sdk_nmbrs/manager.py +294 -0
  20. brynq_sdk_nmbrs/salaries.py +85 -0
  21. brynq_sdk_nmbrs/salary_tables.py +242 -0
  22. brynq_sdk_nmbrs/schedules.py +84 -0
  23. brynq_sdk_nmbrs/schemas/__init__.py +37 -0
  24. brynq_sdk_nmbrs/schemas/absence.py +61 -0
  25. brynq_sdk_nmbrs/schemas/address.py +76 -0
  26. brynq_sdk_nmbrs/schemas/bank.py +83 -0
  27. brynq_sdk_nmbrs/schemas/contracts.py +60 -0
  28. brynq_sdk_nmbrs/schemas/costcenter.py +91 -0
  29. brynq_sdk_nmbrs/schemas/costunit.py +40 -0
  30. brynq_sdk_nmbrs/schemas/days.py +98 -0
  31. brynq_sdk_nmbrs/schemas/debtor.py +16 -0
  32. brynq_sdk_nmbrs/schemas/department.py +57 -0
  33. brynq_sdk_nmbrs/schemas/employees.py +153 -0
  34. brynq_sdk_nmbrs/schemas/employment.py +48 -0
  35. brynq_sdk_nmbrs/schemas/function.py +50 -0
  36. brynq_sdk_nmbrs/schemas/hours.py +121 -0
  37. brynq_sdk_nmbrs/schemas/leave.py +53 -0
  38. brynq_sdk_nmbrs/schemas/manager.py +126 -0
  39. brynq_sdk_nmbrs/schemas/salary.py +92 -0
  40. brynq_sdk_nmbrs/schemas/schedules.py +96 -0
  41. brynq_sdk_nmbrs/schemas/social_insurance.py +40 -0
  42. brynq_sdk_nmbrs/schemas/wage_tax.py +98 -0
  43. brynq_sdk_nmbrs/schemas/wagecomponents.py +114 -0
  44. brynq_sdk_nmbrs/social_insurance.py +52 -0
  45. brynq_sdk_nmbrs/wage_tax.py +164 -0
  46. brynq_sdk_nmbrs/wagecomponents.py +268 -0
  47. brynq_sdk_nmbrs-2.3.1.dist-info/METADATA +21 -0
  48. brynq_sdk_nmbrs-2.3.1.dist-info/RECORD +50 -0
  49. brynq_sdk_nmbrs-2.3.1.dist-info/WHEEL +5 -0
  50. brynq_sdk_nmbrs-2.3.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,252 @@
1
+ import pandas as pd
2
+ import requests
3
+ from typing import Dict, Any
4
+ from .schemas.hours import (
5
+ VariableHoursCreate, VariableHoursUpdate, HoursDelete,
6
+ FixedHoursCreate, FixedHoursUpdate, VariableHoursGet, FixedHoursGet
7
+ )
8
+ from brynq_sdk_functions import Functions
9
+
10
+
11
+ class Hours:
12
+ def __init__(self, nmbrs):
13
+ self.nmbrs = nmbrs
14
+
15
+ def get_types(self,
16
+ company_id: str) -> pd.DataFrame:
17
+ request = requests.Request(method='GET',
18
+ url=f"{self.nmbrs.base_url}companies/{company_id}/hourcodes")
19
+
20
+ df = self.nmbrs.get_paginated_result(request)
21
+
22
+ return df
23
+
24
+
25
+ class VariableHours:
26
+ def __init__(self, nmbrs):
27
+ self.nmbrs = nmbrs
28
+
29
+ def get(self,
30
+ employee_id: str,
31
+ created_from: str = None,
32
+ period: int = None,
33
+ year: int = None) -> tuple[pd.DataFrame, pd.DataFrame]:
34
+ params = {}
35
+ if created_from:
36
+ params['createdFrom'] = created_from
37
+ if period:
38
+ params['period'] = period
39
+ if year:
40
+ params['year'] = year
41
+ request = requests.Request(method='GET',
42
+ url=f"{self.nmbrs.base_url}employees/{employee_id}/variablehours",
43
+ params=params)
44
+
45
+ data = self.nmbrs.get_paginated_result(request)
46
+
47
+ df = pd.DataFrame(data)
48
+
49
+ df['employeeId'] = employee_id # Add employee_id for tracking
50
+ df['period'] = period
51
+ df['year'] = year
52
+
53
+ # Validate data using the schema
54
+ valid_hours, invalid_hours = Functions.validate_data(df=df, schema=VariableHoursGet, debug=True)
55
+
56
+ return valid_hours, invalid_hours
57
+
58
+ def create(self, employee_id: str, data: Dict[str, Any]):
59
+ """
60
+ Create variable hours for an employee using Pydantic validation.
61
+
62
+ Args:
63
+ employee_id: The ID of the employee
64
+ data: Dictionary containing hours data with fields matching
65
+ the VariableHoursCreate schema (using camelCase field names)
66
+
67
+ Returns:
68
+ Response from the API
69
+ """
70
+ # Validate with Pydantic model
71
+ nested_data = self.nmbrs.flat_dict_to_nested_dict(data, VariableHoursCreate)
72
+ hours_model = VariableHoursCreate(**nested_data)
73
+
74
+ if self.nmbrs.mock_mode:
75
+ return hours_model
76
+
77
+ # Convert validated model to dict for API payload
78
+ payload = hours_model.model_dump(exclude_none=True, by_alias=True)
79
+
80
+ # Send request
81
+ resp = self.nmbrs.session.post(
82
+ url=f"{self.nmbrs.base_url}employees/{employee_id}/variablehours",
83
+ json=payload,
84
+ timeout=self.nmbrs.timeout
85
+ )
86
+ return resp
87
+
88
+ def update(self, employee_id: str, data: Dict[str, Any]):
89
+ """
90
+ Update variable hours for an employee using Pydantic validation.
91
+
92
+ Args:
93
+ employee_id: The ID of the employee
94
+ data: Dictionary containing hours data with fields matching
95
+ the VariableHoursUpdate schema (using camelCase field names)
96
+
97
+ Returns:
98
+ Response from the API
99
+ """
100
+ # Validate with Pydantic model
101
+ nested_data = self.nmbrs.flat_dict_to_nested_dict(data, VariableHoursUpdate)
102
+ hours_model = VariableHoursUpdate(**nested_data)
103
+
104
+ if self.nmbrs.mock_mode:
105
+ return hours_model
106
+
107
+ # Convert validated model to dict for API payload
108
+ payload = hours_model.model_dump(exclude_none=True, by_alias=True)
109
+
110
+ # Send request
111
+ resp = self.nmbrs.session.put(
112
+ url=f"{self.nmbrs.base_url}employees/{employee_id}/variablehours",
113
+ json=payload,
114
+ timeout=self.nmbrs.timeout
115
+ )
116
+ return resp
117
+
118
+ def delete(self, employee_id: str, hourcomponent_id: str):
119
+ """
120
+ Delete hours for an employee.
121
+
122
+ Args:
123
+ employee_id: The ID of the employee
124
+ hourcomponent_id: The ID of the hour component to delete
125
+
126
+ Returns:
127
+ Response from the API
128
+ """
129
+ # Create and validate a HoursDelete model
130
+ hours_model = HoursDelete(hourComponentId=hourcomponent_id)
131
+
132
+ if self.nmbrs.mock_mode:
133
+ return hours_model
134
+
135
+ # Send request
136
+ resp = self.nmbrs.session.delete(
137
+ url=f"{self.nmbrs.base_url}employees/{employee_id}/hours/{hourcomponent_id}",
138
+ timeout=self.nmbrs.timeout
139
+ )
140
+ return resp
141
+
142
+
143
+ class FixedHours:
144
+ def __init__(self, nmbrs):
145
+ self.nmbrs = nmbrs
146
+
147
+ def get(self,
148
+ company_id: str,
149
+ created_from: str = None,
150
+ employee_id: str = None,
151
+ period: int = None,
152
+ year: int = None) -> tuple[pd.DataFrame, pd.DataFrame]:
153
+ params = {}
154
+ if created_from:
155
+ params['createdFrom'] = created_from
156
+ if employee_id:
157
+ params['employeeId'] = employee_id
158
+ if period:
159
+ params['period'] = period
160
+ if year:
161
+ params['year'] = year
162
+ request = requests.Request(method='GET',
163
+ url=f"{self.nmbrs.base_url}employees/{employee_id}/fixedhours",
164
+ params=params)
165
+
166
+ df = self.nmbrs.get_paginated_result(request)
167
+
168
+ return df
169
+
170
+ def create(self, employee_id: str, data: Dict[str, Any]):
171
+ """
172
+ Create fixed hours for an employee using Pydantic validation.
173
+
174
+ Args:
175
+ employee_id: The ID of the employee
176
+ data: Dictionary containing hours data with fields matching
177
+ the FixedHoursCreate schema (using camelCase field names)
178
+
179
+ Returns:
180
+ Response from the API
181
+ """
182
+ # Validate with Pydantic model
183
+ nested_data = self.nmbrs.flat_dict_to_nested_dict(data, FixedHoursCreate)
184
+ hours_model = FixedHoursCreate(**nested_data)
185
+
186
+ if self.nmbrs.mock_mode:
187
+ return hours_model
188
+
189
+ # Convert validated model to dict for API payload
190
+ payload = hours_model.model_dump(exclude_none=True, by_alias=True)
191
+
192
+ # Send request
193
+ resp = self.nmbrs.session.post(
194
+ url=f"{self.nmbrs.base_url}employees/{employee_id}/fixedhours",
195
+ json=payload,
196
+ timeout=self.nmbrs.timeout
197
+ )
198
+ return resp
199
+
200
+ def update(self, employee_id: str, data: Dict[str, Any]):
201
+ """
202
+ Update fixed hours for an employee using Pydantic validation.
203
+
204
+ Args:
205
+ employee_id: The ID of the employee
206
+ data: Dictionary containing hours data with fields matching
207
+ the FixedHoursUpdate schema (using camelCase field names)
208
+
209
+ Returns:
210
+ Response from the API
211
+ """
212
+ # Validate with Pydantic model
213
+ nested_data = self.nmbrs.flat_dict_to_nested_dict(data, FixedHoursUpdate)
214
+ hours_model = FixedHoursUpdate(**nested_data)
215
+
216
+ if self.nmbrs.mock_mode:
217
+ return hours_model
218
+
219
+ # Convert validated model to dict for API payload
220
+ payload = hours_model.model_dump(exclude_none=True, by_alias=True)
221
+
222
+ # Send request
223
+ resp = self.nmbrs.session.put(
224
+ url=f"{self.nmbrs.base_url}employees/{employee_id}/fixedhours",
225
+ json=payload,
226
+ timeout=self.nmbrs.timeout
227
+ )
228
+ return resp
229
+
230
+ def delete(self, employee_id: str, hourcomponent_id: str):
231
+ """
232
+ Delete hours for an employee.
233
+
234
+ Args:
235
+ employee_id: The ID of the employee
236
+ hourcomponent_id: The ID of the hour component to delete
237
+
238
+ Returns:
239
+ Response from the API
240
+ """
241
+ # Create and validate a HoursDelete model
242
+ hours_model = HoursDelete(hourComponentId=hourcomponent_id)
243
+
244
+ if self.nmbrs.mock_mode:
245
+ return hours_model
246
+
247
+ # Send request
248
+ resp = self.nmbrs.session.delete(
249
+ url=f"{self.nmbrs.base_url}employees/{employee_id}/hours/{hourcomponent_id}",
250
+ timeout=self.nmbrs.timeout
251
+ )
252
+ return resp
@@ -0,0 +1,139 @@
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.leave import LeaveBalanceGet, LeaveGet, LeaveCreate
7
+
8
+
9
+ class Leave:
10
+ def __init__(self, nmbrs):
11
+ self.nmbrs = nmbrs
12
+
13
+ def get(self,
14
+ changed_from: str = None) -> tuple[pd.DataFrame, pd.DataFrame]:
15
+ leave = pd.DataFrame()
16
+ for company in self.nmbrs.company_ids:
17
+ leave = pd.concat([leave, self._get(company, changed_from)])
18
+
19
+ valid_leave, invalid_leave = Functions.validate_data(df=leave, schema=LeaveGet, debug=True)
20
+
21
+ return valid_leave, invalid_leave
22
+
23
+ def _get(self,
24
+ company_id: str,
25
+ changed_from: str = None) -> pd.DataFrame:
26
+ params = {}
27
+ if changed_from:
28
+ params['changed_from'] = changed_from
29
+ try:
30
+ request = requests.Request(method='GET',
31
+ url=f"{self.nmbrs.base_url}companies/{company_id}/employees/leaverequests",
32
+ params=params)
33
+
34
+ data = self.nmbrs.get_paginated_result(request)
35
+ df = pd.json_normalize(
36
+ data,
37
+ record_path='EmployeeLeaveRequests',
38
+ meta=['employeeId']
39
+ )
40
+ except requests.HTTPError as e:
41
+ df = pd.DataFrame()
42
+
43
+ return df
44
+
45
+ def create(self, employee_id: str, data: Dict[str, Any]):
46
+ """
47
+ Create a new leave request for an employee using Pydantic validation.
48
+
49
+ Args:
50
+ employee_id: The ID of the employee
51
+ data: Dictionary containing leave request data in the format matching LeaveCreate schema
52
+
53
+ Returns:
54
+ Response from the API
55
+ """
56
+ # Validate with Pydantic model - this will raise an error if required fields are missing
57
+ nested_data = self.nmbrs.flat_dict_to_nested_dict(data, LeaveCreate)
58
+ leave_model = LeaveCreate(**nested_data)
59
+
60
+ if self.nmbrs.mock_mode:
61
+ return leave_model
62
+
63
+ # Convert validated model to dict for API payload
64
+ payload = leave_model.model_dump(exclude_none=True, by_alias=True)
65
+
66
+ # Send request
67
+ resp = self.nmbrs.session.post(
68
+ url=f"{self.nmbrs.base_url}employees/{employee_id}/leaverequest",
69
+ json=payload,
70
+ timeout=self.nmbrs.timeout
71
+ )
72
+ return resp
73
+
74
+ def delete(self, employee_id: str, leave_request_id: str):
75
+ """
76
+ Delete a leave request for an employee.
77
+
78
+ Args:
79
+ employee_id: The ID of the employee
80
+ leave_request_id: The ID of the leave request to delete
81
+
82
+ Returns:
83
+ Response from the API
84
+ """
85
+ # Create and validate a BankDelete model
86
+ leave_model = LeaveDelete(leave_request_id=leave_request_id)
87
+
88
+ if self.nmbrs.mock_mode:
89
+ return leave_model
90
+
91
+ # Send request
92
+ resp = self.nmbrs.session.delete(
93
+ url=f"{self.nmbrs.base_url}employees/{employee_id}/leave/{leave_request_id}",
94
+ timeout=self.nmbrs.timeout
95
+ )
96
+ return resp
97
+
98
+
99
+ class LeaveBalance:
100
+ def __init__(self, nmbrs):
101
+ self.nmbrs = nmbrs
102
+
103
+ def get(self,
104
+ changed_from: str = None) -> tuple[pd.DataFrame, pd.DataFrame]:
105
+ leave = pd.DataFrame()
106
+ for company in self.nmbrs.company_ids:
107
+ leave = pd.concat([leave, self._get(company, changed_from)])
108
+
109
+ valid_leave, invalid_leave = Functions.validate_data(df=leave, schema=LeaveBalanceGet, debug=True)
110
+
111
+ return valid_leave, invalid_leave
112
+
113
+ def _get(self,
114
+ company_id: str) -> pd.DataFrame:
115
+ try:
116
+ request = requests.Request(method='GET',
117
+ url=f"{self.nmbrs.base_url}companies/{company_id}/employees/leaveBalances")
118
+
119
+ data = self.nmbrs.get_paginated_result(request)
120
+ df = pd.json_normalize(
121
+ data,
122
+ record_path='leaveBalances',
123
+ meta=['employeeId']
124
+ )
125
+ except requests.HTTPError as e:
126
+ df = pd.DataFrame()
127
+
128
+ return df
129
+
130
+
131
+ class LeaveGroup:
132
+ def __init__(self, nmbrs):
133
+ self.nmbrs = nmbrs
134
+
135
+ def get(self,
136
+ changed_from: str = None) -> tuple[pd.DataFrame, pd.DataFrame]:
137
+ leave = pd.DataFrame()
138
+ for company in self.nmbrs.company_ids:
139
+ leave = pd.concat([leave, self._get(company, changed_from)])
@@ -0,0 +1,294 @@
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.manager import (
7
+ ManagerGet, ManagerBasicGet, EmployeeManagerGet, ManagerHistoricBasicGet,
8
+ ManagerCreate, ManagerUpdate, ManagerDelete, UpdateEmployeeManager
9
+ )
10
+
11
+
12
+ class EmployeeManager:
13
+ def __init__(self, nmbrs):
14
+ self.nmbrs = nmbrs
15
+
16
+ def get(self, created_from: str = None) -> tuple[pd.DataFrame, pd.DataFrame]:
17
+ """
18
+ Get employee manager history for all companies.
19
+
20
+ Args:
21
+ created_from: Optional filter to get managers created from a specific date
22
+
23
+ Returns:
24
+ Tuple of (valid_managers, invalid_managers) DataFrames
25
+ """
26
+ managers = pd.DataFrame()
27
+ for company in self.nmbrs.company_ids:
28
+ managers = pd.concat([managers, self._get(company, created_from)])
29
+
30
+ valid_managers, invalid_managers = BrynQFunctions.validate_data(df=managers, schema=EmployeeManagerGet, debug=True)
31
+
32
+ return valid_managers, invalid_managers
33
+
34
+ def _get(self, company_id: str, created_from: str = None) -> pd.DataFrame:
35
+ """
36
+ Get employee manager history for a specific company.
37
+
38
+ Args:
39
+ company_id: The ID of the company
40
+ created_from: Optional filter to get managers created from a specific date
41
+
42
+ Returns:
43
+ DataFrame containing employee manager data
44
+ """
45
+ params = {}
46
+ if created_from:
47
+ params['createdFrom'] = created_from
48
+
49
+ try:
50
+ request = requests.Request(
51
+ method='GET',
52
+ url=f"{self.nmbrs.base_url}companies/{company_id}/employees/managers",
53
+ params=params
54
+ )
55
+ data = self.nmbrs.get_paginated_result(request)
56
+ df = pd.json_normalize(
57
+ data,
58
+ record_path='managers',
59
+ meta=['employeeId']
60
+ )
61
+ df['companyId'] = company_id
62
+ except requests.HTTPError as e:
63
+ df = pd.DataFrame()
64
+
65
+ return df
66
+
67
+ def get_historic_basic(self, created_from: str = None) -> tuple[pd.DataFrame, pd.DataFrame]:
68
+ """
69
+ Get historic basic manager information for employees.
70
+
71
+ Args:
72
+ created_from: Optional filter to get managers created from a specific date
73
+
74
+ Returns:
75
+ Tuple of (valid_managers, invalid_managers) DataFrames
76
+ """
77
+ managers = pd.DataFrame()
78
+ for company in self.nmbrs.company_ids:
79
+ managers = pd.concat([managers, self._get_historic_basic(company, created_from)])
80
+
81
+ valid_managers, invalid_managers = BrynQFunctions.validate_data(df=managers, schema=ManagerHistoricBasicGet, debug=True)
82
+
83
+ return valid_managers, invalid_managers
84
+
85
+ def _get_historic_basic(self, company_id: str, created_from: str = None) -> pd.DataFrame:
86
+ """
87
+ Get historic basic manager information for a specific company.
88
+
89
+ Args:
90
+ company_id: The ID of the company
91
+ created_from: Optional filter to get managers created from a specific date
92
+
93
+ Returns:
94
+ DataFrame containing historic basic manager data
95
+ """
96
+ params = {}
97
+ if created_from:
98
+ params['createdFrom'] = created_from
99
+
100
+ try:
101
+ request = requests.Request(
102
+ method='GET',
103
+ url=f"{self.nmbrs.base_url}companies/{company_id}/employees/managers",
104
+ params=params
105
+ )
106
+ data = self.nmbrs.get_paginated_result(request)
107
+ df = pd.json_normalize(
108
+ data,
109
+ record_path='managers',
110
+ meta=['employeeId']
111
+ )
112
+ df['companyId'] = company_id
113
+ except requests.HTTPError as e:
114
+ df = pd.DataFrame()
115
+
116
+ return df
117
+
118
+ def update(self, employee_id: str, data: Dict[str, Any]):
119
+ """
120
+ Update the manager of a specific employee using Pydantic validation.
121
+
122
+ Args:
123
+ employee_id: The ID of the employee
124
+ data: Dictionary containing manager data with fields matching
125
+ the UpdateEmployeeManager schema (using camelCase field names)
126
+
127
+ Returns:
128
+ Response from the API
129
+ """
130
+ # Validate with Pydantic model
131
+ manager_model = UpdateEmployeeManager(**data)
132
+
133
+ if self.nmbrs.mock_mode:
134
+ return manager_model
135
+
136
+ # Convert validated model to dict for API payload
137
+ payload = manager_model.dict(exclude_none=True)
138
+
139
+ # Send request
140
+ resp = self.nmbrs.session.put(
141
+ url=f"{self.nmbrs.base_url}employees/{employee_id}/manager",
142
+ json=payload,
143
+ timeout=self.nmbrs.timeout
144
+ )
145
+ return resp
146
+
147
+
148
+ class Manager:
149
+ def __init__(self, nmbrs):
150
+ self.nmbrs = nmbrs
151
+
152
+ def get(self, debtor_id: str) -> tuple[pd.DataFrame, pd.DataFrame]:
153
+ """
154
+ Get all managers for a specific debtor.
155
+
156
+ Args:
157
+ debtor_id: The ID of the debtor
158
+
159
+ Returns:
160
+ Tuple of (valid_managers, invalid_managers) DataFrames
161
+ """
162
+ try:
163
+ request = requests.Request(
164
+ method='GET',
165
+ url=f"{self.nmbrs.base_url}debtors/{debtor_id}/managers"
166
+ )
167
+
168
+ data = self.nmbrs.get_paginated_result(request)
169
+ df = pd.DataFrame(data)
170
+ df['debtorId'] = debtor_id
171
+
172
+ valid_managers, invalid_managers = BrynQFunctions.validate_data(df=df, schema=ManagerGet, debug=True)
173
+
174
+ except requests.HTTPError as e:
175
+ df = pd.DataFrame()
176
+ valid_managers = df
177
+ invalid_managers = df
178
+
179
+ return valid_managers, invalid_managers
180
+
181
+ def get_basic(self, debtor_id: str) -> tuple[pd.DataFrame, pd.DataFrame]:
182
+ """
183
+ Get basic manager information for a specific debtor.
184
+
185
+ Args:
186
+ debtor_id: The ID of the debtor
187
+
188
+ Returns:
189
+ Tuple of (valid_managers, invalid_managers) DataFrames
190
+ """
191
+ try:
192
+ request = requests.Request(
193
+ method='GET',
194
+ url=f"{self.nmbrs.base_url}debtors/{debtor_id}/managers"
195
+ )
196
+
197
+ data = self.nmbrs.get_paginated_result(request)
198
+ df = pd.DataFrame(data)
199
+ df['debtorId'] = debtor_id
200
+
201
+ valid_managers, invalid_managers = BrynQFunctions.validate_data(df=df, schema=ManagerBasicGet, debug=True)
202
+
203
+ except requests.HTTPError as e:
204
+ df = pd.DataFrame()
205
+ valid_managers = df
206
+ invalid_managers = df
207
+
208
+ return valid_managers, invalid_managers
209
+
210
+ def create(self, debtor_id: str, data: Dict[str, Any]):
211
+ """
212
+ Create a new manager using Pydantic validation.
213
+
214
+ Args:
215
+ debtor_id: The ID of the debtor
216
+ data: Dictionary containing manager data with fields matching
217
+ the ManagerCreate schema (using camelCase field names)
218
+
219
+ Returns:
220
+ Response from the API
221
+ """
222
+ # Validate with Pydantic model
223
+ manager_model = ManagerCreate(**data)
224
+
225
+ if self.nmbrs.mock_mode:
226
+ return manager_model
227
+
228
+ # Convert validated model to dict for API payload
229
+ payload = manager_model.dict(exclude_none=True)
230
+
231
+ # Send request
232
+ resp = self.nmbrs.session.post(
233
+ url=f"{self.nmbrs.base_url}debtors/{debtor_id}/managers",
234
+ json=payload,
235
+ timeout=self.nmbrs.timeout
236
+ )
237
+ return resp
238
+
239
+ def update(self, debtor_id: str, data: Dict[str, Any]):
240
+ """
241
+ Update a manager using Pydantic validation.
242
+
243
+ Args:
244
+ debtor_id: The ID of the debtor
245
+ data: Dictionary containing manager data with fields matching
246
+ the ManagerUpdate schema (using camelCase field names)
247
+
248
+ Returns:
249
+ Response from the API
250
+ """
251
+ # Validate with Pydantic model
252
+ manager_model = ManagerUpdate(**data)
253
+
254
+ if self.nmbrs.mock_mode:
255
+ return manager_model
256
+
257
+ # Convert validated model to dict for API payload
258
+ payload = manager_model.dict(exclude_none=True)
259
+
260
+ # Send request
261
+ resp = self.nmbrs.session.put(
262
+ url=f"{self.nmbrs.base_url}debtors/{debtor_id}/managers/{payload['managerId']}",
263
+ json=payload,
264
+ timeout=self.nmbrs.timeout
265
+ )
266
+ return resp
267
+
268
+ def delete(self, debtor_id: str, data: Dict[str, Any]):
269
+ """
270
+ Delete a manager using Pydantic validation.
271
+
272
+ Args:
273
+ debtor_id: The ID of the debtor
274
+ data: Dictionary containing manager data with fields matching
275
+ the ManagerDelete schema (using camelCase field names)
276
+
277
+ Returns:
278
+ Response from the API
279
+ """
280
+ # Validate with Pydantic model
281
+ manager_model = ManagerDelete(**data)
282
+
283
+ if self.nmbrs.mock_mode:
284
+ return manager_model
285
+
286
+ # Convert validated model to dict for API payload
287
+ payload = manager_model.dict(exclude_none=True)
288
+
289
+ # Send request
290
+ resp = self.nmbrs.session.delete(
291
+ url=f"{self.nmbrs.base_url}debtors/{debtor_id}/managers/{payload['managerId']}",
292
+ timeout=self.nmbrs.timeout
293
+ )
294
+ return resp