brynq-sdk-nmbrs 2.2.2__tar.gz → 2.3.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.
Files changed (55) hide show
  1. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/PKG-INFO +1 -1
  2. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/__init__.py +22 -0
  3. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/employees.py +19 -1
  4. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/employees.py +10 -1
  5. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/wage_tax.py +42 -1
  6. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/wage_tax.py +48 -2
  7. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs.egg-info/PKG-INFO +1 -1
  8. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/setup.py +1 -1
  9. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/absence.py +0 -0
  10. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/address.py +0 -0
  11. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/bank.py +0 -0
  12. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/children.py +0 -0
  13. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/companies.py +0 -0
  14. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/contract.py +0 -0
  15. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/costcenter.py +0 -0
  16. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/costunit.py +0 -0
  17. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/days.py +0 -0
  18. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/debtors.py +0 -0
  19. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/department.py +0 -0
  20. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/document.py +0 -0
  21. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/employment.py +0 -0
  22. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/function.py +0 -0
  23. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/hours.py +0 -0
  24. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/leave.py +0 -0
  25. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/manager.py +0 -0
  26. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/salaries.py +0 -0
  27. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/salary_tables.py +0 -0
  28. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schedules.py +0 -0
  29. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/__init__.py +0 -0
  30. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/absence.py +0 -0
  31. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/address.py +0 -0
  32. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/bank.py +0 -0
  33. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/contracts.py +0 -0
  34. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/costcenter.py +0 -0
  35. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/costunit.py +0 -0
  36. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/days.py +0 -0
  37. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/debtor.py +0 -0
  38. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/department.py +0 -0
  39. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/employment.py +0 -0
  40. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/function.py +0 -0
  41. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/hours.py +0 -0
  42. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/leave.py +0 -0
  43. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/manager.py +0 -0
  44. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/salary.py +0 -0
  45. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/schedules.py +0 -0
  46. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/social_insurance.py +0 -0
  47. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/schemas/wagecomponents.py +0 -0
  48. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/social_insurance.py +0 -0
  49. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs/wagecomponents.py +0 -0
  50. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs.egg-info/SOURCES.txt +0 -0
  51. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs.egg-info/dependency_links.txt +0 -0
  52. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs.egg-info/not-zip-safe +0 -0
  53. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs.egg-info/requires.txt +0 -0
  54. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/brynq_sdk_nmbrs.egg-info/top_level.txt +0 -0
  55. {brynq_sdk_nmbrs-2.2.2 → brynq_sdk_nmbrs-2.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.0
2
2
  Name: brynq_sdk_nmbrs
3
- Version: 2.2.2
3
+ Version: 2.3.0
4
4
  Summary: Nmbrs wrapper from BrynQ
5
5
  Home-page: UNKNOWN
6
6
  Author: BrynQ
@@ -139,6 +139,28 @@ class Nmbrs(BrynQ):
139
139
 
140
140
  return auth_header
141
141
 
142
+ def _get_soap_auth_header_employees(self):
143
+ """
144
+ Creates the SOAP authentication header using credentials from initial_credentials.
145
+
146
+ Returns:
147
+ AuthHeaderWithDomainType: The authentication header for SOAP requests
148
+ """
149
+ initial_credentials = self.get_system_credential(system='nmbrs', label='bob')
150
+ config = initial_credentials.get("config", {})
151
+
152
+ # Get the AuthHeaderWithDomain type from the WSDL
153
+ AuthHeaderWithDomainType = self.soap_client_employees.get_element('ns0:AuthHeaderWithDomain')
154
+
155
+ # Create the auth header using credentials from config
156
+ auth_header = AuthHeaderWithDomainType(
157
+ Username=config.get("soap_api_username"),
158
+ Token=config.get("soap_api_token"),
159
+ Domain=config.get("soap_api_domain")
160
+ )
161
+
162
+ return auth_header
163
+
142
164
  def get_paginated_result(self, request: requests.Request) -> List:
143
165
  has_next_page = True
144
166
  result_data = []
@@ -22,7 +22,7 @@ from .days import VariableDays
22
22
  from .wagecomponents import EmployeeVariableWageComponents, EmployeeFixedWageComponents
23
23
  from .leave import Leave, LeaveBalance
24
24
  from .schemas.employees import (
25
- EmployeeGet, EmployeeCreate, EmployeeUpdate, EmployeeDelete,
25
+ BsnGet, EmployeeGet, EmployeeCreate, EmployeeUpdate, EmployeeDelete,
26
26
  BasicInfo, BirthInfo, ContactInfo, PartnerInfo, Period, AdditionalEmployeeInfo,
27
27
  CreateEmployeePersonalInfo
28
28
  )
@@ -83,6 +83,24 @@ class Employees:
83
83
 
84
84
  return df
85
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
+
86
104
  def get_default_templates(self) -> pd.DataFrame:
87
105
  default_templates = pd.DataFrame()
88
106
  for company in self.nmbrs.company_ids:
@@ -84,7 +84,7 @@ class BirthInfo(BaseModel):
84
84
  StringConstraints(
85
85
  pattern=r'^[A-Za-z]+$',
86
86
  strip_whitespace=True,
87
- min_length=2,
87
+ min_length=2,
88
88
  max_length=3
89
89
  )
90
90
  ]] = Field(None, example="PT", description="Nationality Code ISO", alias="nationalityCodeISO")
@@ -140,3 +140,12 @@ class EmployeeUpdate(BaseModel):
140
140
 
141
141
  class EmployeeDelete(BaseModel):
142
142
  employee_id: str = Field(..., example="3054d4cf-b449-489d-8d2e-5dd30e5ab994", description="Employee ID", alias="employeeId")
143
+
144
+ class BsnGet(BrynQPanderaDataFrameModel):
145
+ employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
146
+ social_security_number: Series[String] = pa.Field(coerce=True, description="Social Security Number", alias="BSN")
147
+ company_id: Series[String] = pa.Field(coerce=True, description="Company ID", alias="companyId")
148
+ created_at: Series[DateTime] = pa.Field(coerce=True, description="Created At", alias="createdAt")
149
+
150
+ class _Annotation:
151
+ primary_key = "employee_id"
@@ -10,7 +10,7 @@ from pydantic import BaseModel, Field, StringConstraints
10
10
  from datetime import datetime
11
11
 
12
12
 
13
- class WageTaxGet(BrynQPanderaDataFrameModel):
13
+ class WageTaxSettingsGet(BrynQPanderaDataFrameModel):
14
14
  wagetax_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Loonaangifte ID", alias="LoonaangifteID")
15
15
  serial_number: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Serial Number", alias="SerialNumber")
16
16
  payment_reference: Series[String] = pa.Field(coerce=True, description="Payment Reference", alias="PaymentReference")
@@ -24,6 +24,47 @@ class WageTaxGet(BrynQPanderaDataFrameModel):
24
24
  correction_period_start: Series[DateTime] = pa.Field(nullable=True, coerce=True, description="Correction Tijdvak Start", alias="CorrectionTijdvakStart")
25
25
  correction_period_end: Series[DateTime] = pa.Field(nullable=True, coerce=True, description="Correction Tijdvak End", alias="CorrectionTijdvakEnd")
26
26
 
27
+ # <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
28
+ # <soap:Body>
29
+ # <WageTax_GetListResponse xmlns="https://api.nmbrs.nl/soap/v3/EmployeeService">
30
+ # <WageTax_GetListResult>
31
+ # <WageTaxSettings>
32
+ # <Id>2998190</Id>
33
+ # <JaarloonBT>12144.00</JaarloonBT>
34
+ # <AfwBijzTariefLH>0</AfwBijzTariefLH>
35
+ # <AutoKleineBanenRegeling>true</AutoKleineBanenRegeling>
36
+ # <Loonheffingkorting>true</Loonheffingkorting>
37
+ # <Voordeelreg>true</Voordeelreg>
38
+ # <Loonheffing>true</Loonheffing>
39
+ # <CodeAfdrachtvermindering>0</CodeAfdrachtvermindering>
40
+ # <KleurTabel>1</KleurTabel>
41
+ # <SoortInkomen>15</SoortInkomen>
42
+ # <SpecialeTabel>0</SpecialeTabel>
43
+ # <TijdvakTabel>2</TijdvakTabel>
44
+ # <VakantieBonnen>0</VakantieBonnen>
45
+ # <CodeCalc30PercRule>0</CodeCalc30PercRule>
46
+ # </WageTaxSettings>
47
+ # </WageTax_GetListResult>
48
+ # </WageTax_GetListResponse>
49
+ # </soap:Body>
50
+ # </soap:Envelope>
51
+
52
+ class WageTaxGet(BrynQPanderaDataFrameModel):
53
+ wage_tax_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Wage Tax ID", alias="Id")
54
+ employee_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Employee ID", alias="EmployeeId")
55
+ yearly_salary: Series[pd.Float64Dtype] = pa.Field(coerce=True, description="Yearly Salary", alias="JaarloonBT")
56
+ deviation_special_rate_payroll_tax_deduction: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Afw Bijz Tarief LH", alias="AfwBijzTariefLH")
57
+ auto_small_jobs: Series[Bool] = pa.Field(coerce=True, description="Auto Kleine Banen Regeling", alias="AutoKleineBanenRegeling")
58
+ payroll_tax_deduction: Series[Bool] = pa.Field(coerce=True, description="Loonheffingkorting", alias="Loonheffingkorting")
59
+ benefit_scheme: Series[Bool] = pa.Field(coerce=True, description="Voordeelreg", alias="Voordeelreg")
60
+ payroll_tax: Series[Bool] = pa.Field(coerce=True, description="Loonheffing", alias="Loonheffing")
61
+ code_tax_reduction: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Code Afdrachtvermindering", alias="CodeAfdrachtvermindering")
62
+ color_table: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Kleur Tabel", alias="KleurTabel")
63
+ type_of_income: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Soort Inkomen", alias="SoortInkomen")
64
+ special_table: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Speciale Tabel", alias="SpecialeTabel")
65
+ period_table: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Tijdvak Tabel", alias="TijdvakTabel")
66
+ holiday_vouchers: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Vakantie Bonnen", alias="VakantieBonnen")
67
+ code_calculate_30_percent_rule: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Code Calc 30% Rule", alias="CodeCalc30PercRule")
27
68
 
28
69
  class WageTaxUpdate(BaseModel):
29
70
  employee_id: Optional[int] = Field(None, example="1234567890", description="Employee ID", alias="EmployeeId")
@@ -1,6 +1,6 @@
1
1
  from typing import Any, Dict, List, Union, Tuple
2
2
  import pandas as pd
3
- from .schemas.wage_tax import WageTaxGet, WageTaxUpdate
3
+ from .schemas.wage_tax import WageTaxGet, WageTaxUpdate, WageTaxSettingsGet
4
4
  from zeep.exceptions import Fault
5
5
  from zeep.ns import WSDL, SOAP_ENV_11
6
6
  from zeep.xsd import ComplexType, Element, String
@@ -33,7 +33,7 @@ class WageTax:
33
33
  wagetax_settings_temp['companyId'] = company['number']
34
34
  wagetax_settings = pd.concat([wagetax_settings, wagetax_settings_temp])
35
35
 
36
- valid_wagetax_settings, invalid_wagetax_settings = Functions.validate_data(df=wagetax_settings, schema=WageTaxGet, debug=True)
36
+ valid_wagetax_settings, invalid_wagetax_settings = Functions.validate_data(df=wagetax_settings, schema=WageTaxSettingsGet, debug=True)
37
37
 
38
38
  # No validation schema for now, but could be added later
39
39
  return valid_wagetax_settings, invalid_wagetax_settings
@@ -79,6 +79,49 @@ class WageTax:
79
79
  except Exception as e:
80
80
  raise Exception(f"Failed to get salary tables: {str(e)}")
81
81
 
82
+ def get(self, employee_id: int) -> Tuple[pd.DataFrame, pd.DataFrame]:
83
+ """
84
+ Get wage tax settings for a specific employee.
85
+
86
+ Args:
87
+ employee_id (int): The ID of the employee
88
+
89
+ Returns:
90
+ pd.DataFrame: DataFrame containing the wage tax settings
91
+ """
92
+ try:
93
+ # Get the auth header using the centralized method
94
+ auth_header = self.nmbrs._get_soap_auth_header_employees()
95
+
96
+ # Make SOAP request with the proper header structure
97
+ response = self.soap_client_employees.service.WageTax_GetCurrent(
98
+ EmployeeId=employee_id,
99
+ _soapheaders=[auth_header]
100
+ )
101
+
102
+ # Convert response to DataFrame
103
+ if response:
104
+ # Convert Zeep objects to Python dictionaries
105
+ serialized_response = serialize_object(response)
106
+
107
+ # Convert to list if it's not already
108
+ if not isinstance(serialized_response, list):
109
+ serialized_response = [serialized_response]
110
+
111
+ # Convert to DataFrame
112
+ df = pd.DataFrame(serialized_response)
113
+ df['EmployeeId'] = employee_id
114
+ valid_wage_tax, invalid_wage_tax = Functions.validate_data(df=df, schema=WageTaxGet, debug=True)
115
+
116
+ return valid_wage_tax, invalid_wage_tax
117
+ else:
118
+ return pd.DataFrame(), pd.DataFrame()
119
+
120
+ except Fault as e:
121
+ raise Exception(f"SOAP request failed: {str(e)}")
122
+ except Exception as e:
123
+ raise Exception(f"Failed to get wage tax settings: {str(e)}")
124
+
82
125
  def update(self, data: Dict[str, Any]) -> pd.DataFrame:
83
126
  try:
84
127
  wage_tax_model = WageTaxUpdate(**data)
@@ -86,6 +129,9 @@ class WageTax:
86
129
  if self.nmbrs.mock_mode:
87
130
  return wage_tax_model
88
131
 
132
+ # Get the auth header using the centralized method
133
+ auth_header = self.nmbrs._get_soap_auth_header_employees()
134
+
89
135
  # Use the model's built-in SOAP conversion method
90
136
  wage_tax_settings = wage_tax_model.to_soap_settings(self.nmbrs.soap_client_employees)
91
137
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 1.0
2
2
  Name: brynq-sdk-nmbrs
3
- Version: 2.2.2
3
+ Version: 2.3.0
4
4
  Summary: Nmbrs wrapper from BrynQ
5
5
  Home-page: UNKNOWN
6
6
  Author: BrynQ
@@ -2,7 +2,7 @@ from setuptools import setup, find_namespace_packages
2
2
 
3
3
  setup(
4
4
  name='brynq_sdk_nmbrs',
5
- version='2.2.2',
5
+ version='2.3.0',
6
6
  description='Nmbrs wrapper from BrynQ',
7
7
  long_description='Nmbrs wrapper from BrynQ',
8
8
  author='BrynQ',