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.
Files changed (51) hide show
  1. brynq_sdk_nmbrs/__init__.py +95 -91
  2. brynq_sdk_nmbrs/absence.py +1 -4
  3. brynq_sdk_nmbrs/address.py +5 -81
  4. brynq_sdk_nmbrs/bank.py +1 -2
  5. brynq_sdk_nmbrs/companies.py +130 -39
  6. brynq_sdk_nmbrs/contract.py +0 -1
  7. brynq_sdk_nmbrs/days.py +1 -1
  8. brynq_sdk_nmbrs/debtors.py +53 -65
  9. brynq_sdk_nmbrs/department.py +23 -111
  10. brynq_sdk_nmbrs/document.py +195 -4
  11. brynq_sdk_nmbrs/employee_wage_tax_settings.py +13 -5
  12. brynq_sdk_nmbrs/employees.py +55 -21
  13. brynq_sdk_nmbrs/employment.py +0 -2
  14. brynq_sdk_nmbrs/extra_fields.py +126 -0
  15. brynq_sdk_nmbrs/function.py +35 -97
  16. brynq_sdk_nmbrs/leave.py +53 -58
  17. brynq_sdk_nmbrs/manager.py +51 -35
  18. brynq_sdk_nmbrs/salaries.py +48 -65
  19. brynq_sdk_nmbrs/salary_tables.py +1 -4
  20. brynq_sdk_nmbrs/schedules.py +5 -78
  21. brynq_sdk_nmbrs/schemas/absence.py +26 -16
  22. brynq_sdk_nmbrs/schemas/address.py +2 -29
  23. brynq_sdk_nmbrs/schemas/children.py +0 -2
  24. brynq_sdk_nmbrs/schemas/contracts.py +7 -6
  25. brynq_sdk_nmbrs/schemas/costcenter.py +2 -2
  26. brynq_sdk_nmbrs/schemas/costunit.py +2 -0
  27. brynq_sdk_nmbrs/schemas/days.py +13 -11
  28. brynq_sdk_nmbrs/schemas/debtor.py +6 -28
  29. brynq_sdk_nmbrs/schemas/department.py +5 -39
  30. brynq_sdk_nmbrs/schemas/document.py +0 -2
  31. brynq_sdk_nmbrs/schemas/employee_wage_tax_settings.py +75 -0
  32. brynq_sdk_nmbrs/schemas/employees.py +2 -0
  33. brynq_sdk_nmbrs/schemas/extra_fields.py +56 -0
  34. brynq_sdk_nmbrs/schemas/function.py +5 -32
  35. brynq_sdk_nmbrs/schemas/hours.py +5 -1
  36. brynq_sdk_nmbrs/schemas/leave.py +17 -6
  37. brynq_sdk_nmbrs/schemas/manager.py +16 -24
  38. brynq_sdk_nmbrs/schemas/salary.py +11 -1
  39. brynq_sdk_nmbrs/schemas/schedules.py +2 -54
  40. brynq_sdk_nmbrs/schemas/svw_settings.py +116 -0
  41. brynq_sdk_nmbrs/schemas/wage_tax.py +53 -21
  42. brynq_sdk_nmbrs/schemas/wagecomponents.py +6 -9
  43. brynq_sdk_nmbrs/svw_settings.py +213 -0
  44. brynq_sdk_nmbrs/wage_tax.py +120 -11
  45. {brynq_sdk_nmbrs-2.3.3.dev0.dist-info → brynq_sdk_nmbrs-2.4.5.dist-info}/METADATA +1 -1
  46. brynq_sdk_nmbrs-2.4.5.dist-info/RECORD +58 -0
  47. {brynq_sdk_nmbrs-2.3.3.dev0.dist-info → brynq_sdk_nmbrs-2.4.5.dist-info}/WHEEL +1 -1
  48. brynq_sdk_nmbrs/schemas/social_insurance.py +0 -73
  49. brynq_sdk_nmbrs/social_insurance.py +0 -130
  50. brynq_sdk_nmbrs-2.3.3.dev0.dist-info/RECORD +0 -55
  51. {brynq_sdk_nmbrs-2.3.3.dev0.dist-info → brynq_sdk_nmbrs-2.4.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,116 @@
1
+ from typing import Optional
2
+
3
+ import pandas as pd
4
+ import pandera as pa
5
+ from pydantic import BaseModel, ConfigDict, Field
6
+
7
+ from brynq_sdk_functions import BrynQPanderaDataFrameModel
8
+
9
+
10
+ # ---------------------------
11
+ # Get Schemas - Company SVW Settings
12
+ # ---------------------------
13
+ class CompanySVWSettingsGet(BrynQPanderaDataFrameModel):
14
+ """Schema for validating company SVW settings data."""
15
+ svw_settings_id: pd.StringDtype = pa.Field(coerce=True, description="SVW Settings ID", alias="SVWSettingsId")
16
+ own_risk_dif_wga: pd.BooleanDtype = pa.Field(coerce=True, nullable=True, description="Own risk DIF WGA", alias="ownRiskDifWGA")
17
+ own_risk_health_care: pd.BooleanDtype = pa.Field(coerce=True, nullable=True, description="Own risk health care", alias="ownRiskHealthCare")
18
+ aof: pd.StringDtype = pa.Field(coerce=True, nullable=True, description="AOF (Low/High)", alias="AOF")
19
+ diff_wga_wn: pd.Float64Dtype = pa.Field(coerce=True, nullable=True, description="Diff WGA Wn", alias="diffWGAWn")
20
+ diff_wga_wg: pd.Float64Dtype = pa.Field(coerce=True, nullable=True, description="Diff WGA Wg", alias="diffWGAWg")
21
+ zw_wg: pd.Float64Dtype = pa.Field(coerce=True, nullable=True, description="ZW Wg", alias="zwWg")
22
+
23
+ class _Annotation:
24
+ primary_key = "svw_settings_id"
25
+
26
+
27
+ # ---------------------------
28
+ # Get Schemas - Employee SVW Settings
29
+ # ---------------------------
30
+ class EmployeeSVWSettingsGet(BrynQPanderaDataFrameModel):
31
+ """Schema for validating employee SVW settings data."""
32
+ employee_id: pd.StringDtype = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
33
+ zw: pd.BooleanDtype = pa.Field(coerce=True, nullable=True, description="ZW (Ziektewet)", alias="ZW")
34
+ ww: pd.BooleanDtype = pa.Field(coerce=True, nullable=True, description="WW (Werkloosheidswet)", alias="WW")
35
+ wao_wia: pd.BooleanDtype = pa.Field(coerce=True, nullable=True, description="WAO/WIA", alias="waoWia")
36
+ nature_of_employment: pd.StringDtype = pa.Field(coerce=True, nullable=True, description="Nature of employment", alias="natureOfEmployment")
37
+ phase_classification: pd.StringDtype = pa.Field(coerce=True, nullable=True, description="Phase classification", alias="phaseClassification")
38
+ tax_sequence_number: pd.Int64Dtype = pa.Field(coerce=True, nullable=True, description="Tax sequence number", alias="taxSequenceNumber")
39
+ code_zvw: pd.StringDtype = pa.Field(coerce=True, nullable=True, description="Code ZVW", alias="codeZvw")
40
+ income_related_contribution_zvw: pd.StringDtype = pa.Field(coerce=True, nullable=True, description="Income related contribution ZVW", alias="incomeRelatedContributionZvw")
41
+ influence_obliged_insurance: pd.StringDtype = pa.Field(coerce=True, nullable=True, description="Influence obliged insurance", alias="influenceObligedInsurance")
42
+ wage_cost_benefit_code: pd.Int64Dtype = pa.Field(coerce=True, nullable=True, description="Wage cost benefit code", alias="wageCostBenefit.code")
43
+ wage_cost_benefit_description: pd.StringDtype = pa.Field(coerce=True, nullable=True, description="Wage cost benefit description", alias="wageCostBenefit.description")
44
+ wage_cost_benefit_end_period: pd.Int64Dtype = pa.Field(coerce=True, nullable=True, description="Wage cost benefit end period", alias="wageCostBenefit.endPeriod")
45
+ wage_cost_benefit_end_year: pd.Int64Dtype = pa.Field(coerce=True, nullable=True, description="Wage cost benefit end year", alias="wageCostBenefit.endYear")
46
+ cao_code: pd.Int64Dtype = pa.Field(coerce=True, nullable=True, description="CAO code", alias="CAO.code")
47
+ cao_description: pd.StringDtype = pa.Field(coerce=True, nullable=True, description="CAO description", alias="CAO.CAODescription")
48
+ hirer_cao_code: Optional[pd.Int64Dtype] = pa.Field(
49
+ coerce=True,
50
+ nullable=True,
51
+ description="Hirer CAO code",
52
+ alias="hirerCAO.code",
53
+ )
54
+ hirer_cao_description: Optional[pd.StringDtype] = pa.Field(
55
+ coerce=True,
56
+ nullable=True,
57
+ description="Hirer CAO description",
58
+ alias="hirerCAO.CAODescription",
59
+ )
60
+ period_year: pd.Int64Dtype = pa.Field(coerce=True, nullable=True, description="Period year", alias="period.year")
61
+ period_period: pd.Int64Dtype = pa.Field(coerce=True, nullable=True, description="Period", alias="period.period")
62
+ created_at: str = pa.Field(coerce=True, nullable=True, description="Created at", alias="createdAt")
63
+
64
+ class _Annotation:
65
+ primary_key = "employee_id"
66
+
67
+
68
+ # ---------------------------
69
+ # Create/Update Schemas
70
+ # ---------------------------
71
+ class Period(BaseModel):
72
+ """Period model for specifying year and period."""
73
+ model_config = ConfigDict(populate_by_name=True)
74
+
75
+ period_year: int = Field(..., ge=1900, le=2100, example=2021, description="Year", alias="year")
76
+ period_period: int = Field(..., ge=1, le=53, example=4, description="Period", alias="period")
77
+
78
+
79
+ class WageCostBenefit(BaseModel):
80
+ """Wage cost benefit model."""
81
+ model_config = ConfigDict(populate_by_name=True)
82
+
83
+ code: Optional[int] = Field(None, example=1234, description="Wage cost benefit code", alias="code")
84
+ end_period: Optional[int] = Field(None, ge=1, le=53, example=12, description="End period", alias="endPeriod")
85
+ end_year: Optional[int] = Field(None, ge=1900, le=2100, example=2025, description="End year", alias="endYear")
86
+
87
+
88
+ class SVWSettingsCreate(BaseModel):
89
+ """Schema for creating employee SVW settings."""
90
+ model_config = ConfigDict(populate_by_name=True)
91
+
92
+ zw: Optional[bool] = Field(None, example=True, description="ZW (Ziektewet)", alias="ZW")
93
+ ww: Optional[bool] = Field(None, example=True, description="WW (Werkloosheidswet)", alias="WW")
94
+ wao_wia: Optional[bool] = Field(None, example=True, description="WAO/WIA", alias="waoWia")
95
+ nature_of_employment: int = Field(..., example=1, description="Nature of employment code (1, 4, 6, 7, 11, 18, 21, 22, 23, 24, 79, 81, 82, 83)", alias="natureOfEmployment")
96
+ phase_classification: Optional[int] = Field(None, example=1, description="Phase classification (only for nature of employment 11)", alias="phaseClassification")
97
+ code_zvw: str = Field(
98
+ ...,
99
+ pattern=r'^[ABGHIKLMN]$',
100
+ example="A",
101
+ description="Code ZVW (A, B, G, H, I, K, L, M, N)",
102
+ alias="codeZvw",
103
+ )
104
+ tax_sequence_number: int = Field(..., ge=0, example=0, description="Tax sequence number", alias="taxSequenceNumber")
105
+ income_related_contribution_zvw: int = Field(..., ge=0, example=0, description="Income related contribution ZVW", alias="incomeRelatedContributionZvw")
106
+ influence_obliged_insurance: str = Field(
107
+ ...,
108
+ pattern=r'^[0ABDE]$',
109
+ example="0",
110
+ description="Influence obliged insurance (0, A, B, D, E)",
111
+ alias="influenceObligedInsurance",
112
+ )
113
+ wage_cost_benefit: Optional[WageCostBenefit] = Field(None, example={"code": 1234, "endPeriod": 12, "endYear": 2025}, description="Wage cost benefit", alias="wageCostBenefit")
114
+ cao: Optional[int] = Field(None, example=100, description="CAO code", alias="CAO")
115
+ hirer_cao: Optional[int] = Field(None, example=100, description="Hirer CAO code", alias="hirerCAO")
116
+ period: Period = Field(..., example={"year": 2021, "period": 4}, description="Period to apply settings")
@@ -1,17 +1,36 @@
1
- import math
2
1
  from datetime import datetime
3
- from typing import Annotated, Optional, Union
2
+ from typing import Optional
4
3
 
5
4
  import pandas as pd
6
5
  import pandera as pa
7
- import pandera.extensions as extensions
8
6
  from pandera import Bool
9
- from pandera.typing import DateTime, Float, Series, String
10
- from pydantic import BaseModel, Field, StringConstraints
7
+ from pandera.typing import DateTime, Series, String
8
+ from pydantic import BaseModel, Field
11
9
 
12
10
  from brynq_sdk_functions import BrynQPanderaDataFrameModel
13
11
 
14
12
 
13
+ # ---------------------------
14
+ # REST API Schema - Company Wage Tax Declarations
15
+ # ---------------------------
16
+ class CompanyWageTaxGet(BrynQPanderaDataFrameModel):
17
+ """Schema for validating company wage tax data from REST API."""
18
+ wage_tax_id: Series[String] = pa.Field(coerce=True, description="Wage Tax ID", alias="wageTaxId")
19
+ serial_number: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=True, description="Serial Number", alias="serialNumber")
20
+ total_general: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=True, description="Total General", alias="totalGeneral")
21
+ payment_reference: Series[String] = pa.Field(coerce=True, nullable=True, description="Payment Reference", alias="paymentReference")
22
+ period: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=True, description="Period", alias="period")
23
+ year: Series[pd.Int64Dtype] = pa.Field(coerce=True, nullable=True, description="Year", alias="year")
24
+ status: Series[String] = pa.Field(coerce=True, nullable=True, description="Status", alias="status")
25
+ sent_at: Series[DateTime] = pa.Field(coerce=True, nullable=True, description="Sent At", alias="sentAt")
26
+ period_start: Series[DateTime] = pa.Field(coerce=True, nullable=True, description="Period Start", alias="periodStart")
27
+ period_end: Series[DateTime] = pa.Field(coerce=True, nullable=True, description="Period End", alias="periodEnd")
28
+ correction_period_start: Series[DateTime] = pa.Field(nullable=True, coerce=True, description="Correction Period Start", alias="correctionPeriodStart")
29
+ correction_period_end: Series[DateTime] = pa.Field(nullable=True, coerce=True, description="Correction Period End", alias="correctionPeriodEnd")
30
+
31
+ class _Annotation:
32
+ primary_key = "wage_tax_id"
33
+
15
34
  # ---------------------------
16
35
  # REST API Get Schema (Wage Tax Settings History)
17
36
  # ---------------------------
@@ -70,7 +89,7 @@ class WageTaxSettingsCreate(BaseModel):
70
89
  # ---------------------------
71
90
  # SOAP API Get Schema (Company Wage Tax List)
72
91
  # ---------------------------
73
- class CompanyWageTaxGet(BrynQPanderaDataFrameModel):
92
+ class CompanyWageTaxGetSOAP(BrynQPanderaDataFrameModel):
74
93
  wagetax_id: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Loonaangifte ID", alias="LoonaangifteID")
75
94
  serial_number: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Serial Number", alias="SerialNumber")
76
95
  payment_reference: Series[String] = pa.Field(coerce=True, description="Payment Reference", alias="PaymentReference")
@@ -84,6 +103,9 @@ class CompanyWageTaxGet(BrynQPanderaDataFrameModel):
84
103
  correction_period_start: Series[DateTime] = pa.Field(nullable=True, coerce=True, description="Correction Tijdvak Start", alias="CorrectionTijdvakStart")
85
104
  correction_period_end: Series[DateTime] = pa.Field(nullable=True, coerce=True, description="Correction Tijdvak End", alias="CorrectionTijdvakEnd")
86
105
 
106
+ class _Annotation:
107
+ primary_key = "wagetax_id"
108
+
87
109
  # <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">
88
110
  # <soap:Body>
89
111
  # <WageTax_GetListResponse xmlns="https://api.nmbrs.nl/soap/v3/EmployeeService">
@@ -126,22 +148,32 @@ class WageTaxGet(BrynQPanderaDataFrameModel):
126
148
  holiday_vouchers: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Vakantie Bonnen", alias="VakantieBonnen")
127
149
  code_calculate_30_percent_rule: Series[pd.Int64Dtype] = pa.Field(coerce=True, description="Code Calc 30% Rule", alias="CodeCalc30PercRule")
128
150
 
151
+ class _Annotation:
152
+ primary_key = "wage_tax_id"
153
+ foreign_keys = {
154
+ "employee_id": {
155
+ "parent_schema": "EmployeeSchema",
156
+ "parent_column": "employee_id",
157
+ "cardinality": "N:1"
158
+ }
159
+ }
160
+
129
161
  class WageTaxUpdate(BaseModel):
130
- employee_id: Optional[int] = Field(None, example="1234567890", description="Employee ID", alias="EmployeeId")
131
- wage_tax_id: Optional[int] = Field(None, example="1234567890", description="Wage Tax Settings ID", alias="Id")
132
- yearly_salary: Optional[float] = Field(None, example="1234567890", description="Yearly Salary", alias="JaarloonBT")
133
- deviation_special_rate_payroll_tax_deduction: Optional[float] = Field(None, example="1234567890", description="Afw Bijz Tarief LH", alias="AfwBijzTariefLH")
134
- auto_small_jobs: Optional[bool] = Field(None, example="1234567890", description="Auto Kleine Banen Regeling", alias="AutoKleineBanenRegeling")
135
- payroll_tax_deduction: Optional[bool] = Field(None, example="1234567890", description="Loonheffingkorting", alias="Loonheffingkorting")
136
- benefit_scheme: Optional[bool] = Field(None, example="1234567890", description="Voordeelreg", alias="Voordeelreg")
137
- payroll_tax: Optional[bool] = Field(None, example="1234567890", description="Loonheffing", alias="Loonheffing")
138
- code_tax_reduction: Optional[int] = Field(None, example="1234567890", description="Code Afdrachtvermindering", alias="CodeAfdrachtvermindering")
139
- color_table: Optional[int] = Field(None, example="1234567890", description="Kleur Tabel", alias="KleurTabel")
140
- type_of_income: Optional[int] = Field(None, example="1234567890", description="Soort Inkomen", alias="SoortInkomen")
141
- special_table: Optional[int] = Field(None, example="1234567890", description="Speciale Tabel", alias="SpecialeTabel")
142
- period_table: Optional[int] = Field(None, example="1234567890", description="Tijdvak Tabel", alias="TijdvakTabel")
143
- holiday_vouchers: Optional[int] = Field(None, example="1234567890", description="Vakantie Bonnen", alias="VakantieBonnen")
144
- code_calculate_30_percent_rule: Optional[int] = Field(None, example="1234567890", description="Code Calc 30% Rule", alias="CodeCalc30PercRule")
162
+ employee_id: Optional[int] = Field(None, example=1234567890, description="Employee ID", alias="EmployeeId")
163
+ wage_tax_id: Optional[int] = Field(None, example=2998190, description="Wage Tax Settings ID", alias="Id")
164
+ yearly_salary: Optional[float] = Field(None, example=12144.00, description="Yearly Salary", alias="JaarloonBT")
165
+ deviation_special_rate_payroll_tax_deduction: Optional[float] = Field(None, example=0, description="Afw Bijz Tarief LH", alias="AfwBijzTariefLH")
166
+ auto_small_jobs: Optional[bool] = Field(None, example=True, description="Auto Kleine Banen Regeling", alias="AutoKleineBanenRegeling")
167
+ payroll_tax_deduction: Optional[bool] = Field(None, example=True, description="Loonheffingkorting", alias="Loonheffingkorting")
168
+ benefit_scheme: Optional[bool] = Field(None, example=True, description="Voordeelreg", alias="Voordeelreg")
169
+ payroll_tax: Optional[bool] = Field(None, example=True, description="Loonheffing", alias="Loonheffing")
170
+ code_tax_reduction: Optional[int] = Field(None, example=0, description="Code Afdrachtvermindering", alias="CodeAfdrachtvermindering")
171
+ color_table: Optional[int] = Field(None, example=1, description="Kleur Tabel", alias="KleurTabel")
172
+ type_of_income: Optional[int] = Field(None, example=15, description="Soort Inkomen", alias="SoortInkomen")
173
+ special_table: Optional[int] = Field(None, example=0, description="Speciale Tabel", alias="SpecialeTabel")
174
+ period_table: Optional[int] = Field(None, example=2, description="Tijdvak Tabel", alias="TijdvakTabel")
175
+ holiday_vouchers: Optional[int] = Field(None, example=0, description="Vakantie Bonnen", alias="VakantieBonnen")
176
+ code_calculate_30_percent_rule: Optional[int] = Field(None, example=0, description="Code Calc 30% Rule", alias="CodeCalc30PercRule")
145
177
 
146
178
  def to_soap_settings(self, soap_client):
147
179
  """Convert to SOAP WageTaxSettings object"""
@@ -1,4 +1,3 @@
1
- import math
2
1
  from typing import Optional
3
2
 
4
3
  import pandas as pd
@@ -7,8 +6,6 @@ from pandera.typing import Float, Series, String
7
6
  from pydantic import (
8
7
  BaseModel,
9
8
  Field,
10
- confloat,
11
- conint,
12
9
  field_validator,
13
10
  model_serializer,
14
11
  )
@@ -69,12 +66,12 @@ class VariableWageComponentGet(BrynQPanderaDataFrameModel):
69
66
  # Upload Schemas
70
67
  # ---------------------------
71
68
  class PeriodPost(BaseModel):
72
- period_details_year: int = Field(..., ge=1900, le=2100, example=2021, description="Year", alias="year")
73
- period_details_period: int = Field(..., ge=1, le=53, example=4, description="Period", alias="period")
69
+ period_details_year: Optional[int] = Field(None, ge=1900, le=2100, example=2021, description="Year", alias="year")
70
+ period_details_period: Optional[int] = Field(None, ge=1, le=53, example=4, description="Period", alias="period")
74
71
 
75
72
  class FixedWageComponentCreate(BaseModel):
76
73
  code: int = Field(..., ge=1, example=1100, description="Wage Component Code", alias="code")
77
- value: float = Field(..., ge=0, example=500, description="Wage Component Value", alias="value")
74
+ value: float = Field(..., example=500, description="Wage Component Value", alias="value")
78
75
  end_year: Optional[int] = Field(None, ge=1900, le=2100, example=2023, description="End Year", alias="endYear")
79
76
  end_period: Optional[int] = Field(None, ge=1, le=53, example=6, description="End Period", alias="endPeriod")
80
77
  comment: Optional[str] = Field(None, example="some comment", description="Comment", alias="comment")
@@ -113,7 +110,7 @@ class FixedWageComponentCreate(BaseModel):
113
110
  class FixedWageComponentUpdate(BaseModel):
114
111
  fixed_wage_component_id: str = Field(..., example="643c6b90-57c6-4199-9e4e-ded553572d78", description="Fixed Wage Component ID", alias="fixedWageComponentId")
115
112
  code: Optional[int] = Field(None, ge=1, example=1100, description="Wage Component Code", alias="code")
116
- value: Optional[float] = Field(None, ge=0, example=500, description="Wage Component Value", alias="value")
113
+ value: Optional[float] = Field(None, example=500, description="Wage Component Value", alias="value")
117
114
  end_year: Optional[int] = Field(None, ge=1900, le=2100, example=2023, description="End Year", alias="endYear")
118
115
  end_period: Optional[int] = Field(None, ge=1, le=53, example=6, description="End Period", alias="endPeriod")
119
116
  comment: Optional[str] = Field(None, example="string", description="Comment", alias="comment")
@@ -124,7 +121,7 @@ class FixedWageComponentUpdate(BaseModel):
124
121
 
125
122
  class VariableWageComponentCreate(BaseModel):
126
123
  code: int = Field(..., ge=1, example=3045, description="Wage Component Code", alias="code")
127
- value: float = Field(..., ge=0, example=200, description="Wage Component Value", alias="value")
124
+ value: float = Field(..., example=200, description="Wage Component Value", alias="value")
128
125
  comment: Optional[str] = Field(None, example="comment", description="Comment", alias="comment")
129
126
  cost_center_id: Optional[str] = Field(None, example="aa506564-d1db-4fa8-83dc-d68db4cfcd82", description="Cost Center ID", alias="costCenterId")
130
127
  cost_unit_id: Optional[str] = Field(None, example="d8ac6afb-2ac6-43bf-9880-2d382cdace43", description="Cost Unit ID", alias="costUnitId")
@@ -153,7 +150,7 @@ class VariableWageComponentCreate(BaseModel):
153
150
  class VariableWageComponentUpdate(BaseModel):
154
151
  variable_wage_component_id: str = Field(..., example="7fc59095-daed-4746-a7f8-a454e38e3683", description="Variable Wage Component ID", alias="variableWageComponentId")
155
152
  code: Optional[int] = Field(None, ge=1, example=3045, description="Wage Component Code", alias="code")
156
- value: Optional[float] = Field(None, ge=0, example=2200, description="Wage Component Value", alias="value")
153
+ value: Optional[float] = Field(None, example=2200, description="Wage Component Value", alias="value")
157
154
  comment: Optional[str] = Field(None, example="comment", description="Comment", alias="comment")
158
155
  cost_center_id: Optional[str] = Field(None, example="aa506564-d1db-4fa8-83dc-d68db4cfcd82", description="Cost Center ID", alias="costCenterId")
159
156
  cost_unit_id: Optional[str] = Field(None, example="d8ac6afb-2ac6-43bf-9880-2d382cdace43", description="Cost Unit ID", alias="costUnitId")
@@ -0,0 +1,213 @@
1
+ from typing import Any, Dict, Optional
2
+
3
+ import pandas as pd
4
+ import requests
5
+
6
+ from brynq_sdk_functions import Functions
7
+
8
+ from .schemas.svw_settings import (
9
+ CompanySVWSettingsGet,
10
+ EmployeeSVWSettingsGet,
11
+ SVWSettingsCreate,
12
+ )
13
+
14
+
15
+ class CompanySVWSettings:
16
+ """
17
+ Class for handling company-level SVW (Social Insurance) settings.
18
+
19
+ Endpoints:
20
+ - GET /api/companies/{companyId}/svwsettings
21
+ """
22
+
23
+ def __init__(self, nmbrs):
24
+ self.nmbrs = nmbrs
25
+
26
+ def get(self,
27
+ company_id: Optional[str] = None,
28
+ year: Optional[int] = None,
29
+ period: Optional[int] = None,
30
+ created_from: Optional[str] = None) -> tuple:
31
+ """
32
+ Get company SVW settings (SVW table).
33
+
34
+ Args:
35
+ company_id: Optional company ID. If not provided, fetches for all companies.
36
+ year: Optional year filter
37
+ period: Optional period filter
38
+ created_from: Optional datetime filter for records created after this date
39
+
40
+ Returns:
41
+ Tuple of (valid_data, invalid_data) DataFrames
42
+ """
43
+ if company_id:
44
+ df = self._get(company_id, year, period, created_from)
45
+ else:
46
+ df = pd.DataFrame()
47
+ for company in self.nmbrs.company_ids:
48
+ df = pd.concat([df, self._get(company, year, period, created_from)])
49
+
50
+ if df.empty:
51
+ return df, pd.DataFrame()
52
+
53
+ valid_data, invalid_data = Functions.validate_data(df=df, schema=CompanySVWSettingsGet, debug=self.nmbrs.debug)
54
+ return valid_data, invalid_data
55
+
56
+ def _get(self,
57
+ company_id: str,
58
+ year: Optional[int] = None,
59
+ period: Optional[int] = None,
60
+ created_from: Optional[str] = None) -> pd.DataFrame:
61
+ """
62
+ Internal method to get SVW settings for a single company.
63
+ """
64
+ params = {}
65
+ if year is not None:
66
+ params['year'] = year
67
+ if period is not None:
68
+ params['period'] = period
69
+ if created_from is not None:
70
+ params['createdFrom'] = created_from
71
+
72
+ request = requests.Request(
73
+ method='GET',
74
+ url=f"{self.nmbrs.base_url}companies/{company_id}/svwsettings",
75
+ params=params
76
+ )
77
+
78
+ data = self.nmbrs.get_paginated_result(request)
79
+ df = pd.DataFrame(data)
80
+
81
+ if not df.empty:
82
+ df['companyId'] = company_id
83
+
84
+ return df
85
+
86
+
87
+ class EmployeeSVWSettings:
88
+ """
89
+ Class for handling employee-level SVW (Social Insurance) settings.
90
+
91
+ Endpoints:
92
+ - GET /api/companies/{companyId}/employees/svwsettings
93
+ - POST /api/employees/{employeeId}/SVWSettings
94
+ """
95
+
96
+ def __init__(self, nmbrs):
97
+ self.nmbrs = nmbrs
98
+
99
+ def get(self,
100
+ company_id: Optional[str] = None,
101
+ employee_id: Optional[str] = None,
102
+ created_from: Optional[str] = None) -> tuple:
103
+ """
104
+ Get SVW settings history for employees of a company.
105
+
106
+ Args:
107
+ company_id: Optional company ID. If not provided, fetches for all companies.
108
+ employee_id: Optional employee ID filter
109
+ created_from: Optional datetime filter for records created after this date
110
+
111
+ Returns:
112
+ Tuple of (valid_data, invalid_data) DataFrames
113
+ """
114
+ if company_id:
115
+ df = self._get(company_id, employee_id, created_from)
116
+ else:
117
+ df = pd.DataFrame()
118
+ for company in self.nmbrs.company_ids:
119
+ df = pd.concat([df, self._get(company, employee_id, created_from)])
120
+
121
+ if df.empty:
122
+ return df, pd.DataFrame()
123
+
124
+ valid_data, invalid_data = Functions.validate_data(df=df, schema=EmployeeSVWSettingsGet, debug=self.nmbrs.debug)
125
+ return valid_data, invalid_data
126
+
127
+ def _get(self,
128
+ company_id: str,
129
+ employee_id: Optional[str] = None,
130
+ created_from: Optional[str] = None) -> pd.DataFrame:
131
+ """
132
+ Internal method to get employee SVW settings for a single company.
133
+ """
134
+ params = {}
135
+ if employee_id is not None:
136
+ params['employeeId'] = employee_id
137
+ if created_from is not None:
138
+ params['createdFrom'] = created_from
139
+
140
+ request = requests.Request(
141
+ method='GET',
142
+ url=f"{self.nmbrs.base_url}companies/{company_id}/employees/svwsettings",
143
+ params=params
144
+ )
145
+
146
+ data = self.nmbrs.get_paginated_result(request)
147
+
148
+ # Normalize nested data structure without meta key conflicts
149
+ records = []
150
+ for item in data:
151
+ parent_employee_id = item.get("employeeId")
152
+ for record in item.get("employeeSVWSettings", []) or []:
153
+ if "employeeId" not in record:
154
+ record["employeeId"] = parent_employee_id
155
+ records.append(record)
156
+ df = pd.json_normalize(records)
157
+ if 'hirerCAO' in df.columns:
158
+ hirer_cao_df = pd.json_normalize(df['hirerCAO']).add_prefix('hirerCAO.')
159
+ if not hirer_cao_df.empty:
160
+ hirer_cao_df = hirer_cao_df.reindex(df.index)
161
+ df = pd.concat([df.drop(columns=['hirerCAO']), hirer_cao_df], axis=1)
162
+ else:
163
+ df = df.drop(columns=['hirerCAO'])
164
+
165
+ if not df.empty:
166
+ df['companyId'] = company_id
167
+
168
+ return df
169
+
170
+ def create(self, employee_id: str, data: Dict[str, Any]):
171
+ """
172
+ Create SVW settings for a specific employee.
173
+
174
+ A new SVW settings entry will be created in Nmbrs, starting from the
175
+ applied start period.
176
+
177
+ Args:
178
+ employee_id: The ID of the employee
179
+ data: Dictionary containing SVW settings data matching SVWSettingsCreate schema:
180
+ - ZW: bool (optional) - Ziektewet
181
+ - WW: bool (optional) - Werkloosheidswet
182
+ - waoWia: bool (optional) - WAO/WIA
183
+ - natureOfEmployment: int (required) - Nature of employment code
184
+ - phaseClassification: int (optional) - Phase classification
185
+ - codeZvw: str (required) - Code ZVW (A, B, G, H)
186
+ - taxSequenceNumber: int (required)
187
+ - incomeRelatedContributionZvw: int (required)
188
+ - influenceObligedInsurance: int (required)
189
+ - wageCostBenefit: dict (optional)
190
+ - CAO: int (optional)
191
+ - hirerCAO: int (optional)
192
+ - period: dict (required) with year and period
193
+
194
+ Returns:
195
+ Response from the API or validated model in mock mode
196
+ """
197
+ # Validate with Pydantic model
198
+ nested_data = self.nmbrs.flat_dict_to_nested_dict(data, SVWSettingsCreate)
199
+ svw_model = SVWSettingsCreate(**nested_data)
200
+
201
+ if self.nmbrs.mock_mode:
202
+ return svw_model
203
+
204
+ # Convert validated model to dict for API payload
205
+ payload = svw_model.model_dump(exclude_none=True, by_alias=True)
206
+
207
+ # Send request
208
+ resp = self.nmbrs.session.post(
209
+ url=f"{self.nmbrs.base_url}employees/{employee_id}/SVWSettings",
210
+ json=payload,
211
+ timeout=self.nmbrs.timeout
212
+ )
213
+ return resp
@@ -1,16 +1,128 @@
1
- from typing import Any, Dict, List, Union, Tuple
1
+ from typing import Any, Dict, Optional, Tuple
2
+
2
3
  import pandas as pd
3
4
  import requests
4
- from .schemas.wage_tax import (
5
- WageTaxGet, WageTaxUpdate, CompanyWageTaxGet,
6
- WageTaxSettingsGet, WageTaxSettingsCreate
7
- )
8
5
  from zeep.exceptions import Fault
9
- from zeep.ns import WSDL, SOAP_ENV_11
10
- from zeep.xsd import ComplexType, Element, String
11
6
  from zeep.helpers import serialize_object
7
+
12
8
  from brynq_sdk_functions import Functions
13
9
 
10
+ from .schemas.wage_tax import (
11
+ CompanyWageTaxGet,
12
+ CompanyWageTaxGetSOAP,
13
+ WageTaxGet,
14
+ WageTaxSettingsCreate,
15
+ WageTaxSettingsGet,
16
+ WageTaxUpdate,
17
+ )
18
+
19
+
20
+ class CompanyWageTax:
21
+ """
22
+ Class for handling company-level wage tax data via REST API.
23
+
24
+ Endpoints:
25
+ - GET /api/companies/{companyId}/wagetaxes
26
+ - GET /api/companies/{companyId}/wagetaxes/{wageTaxId}/xml
27
+ - GET /api/companies/{companyId}/wagetaxes/{wageTaxId}/sepa
28
+ """
29
+
30
+ def __init__(self, nmbrs):
31
+ self.nmbrs = nmbrs
32
+
33
+ def get(self,
34
+ company_id: Optional[str] = None,
35
+ year: Optional[int] = None) -> tuple:
36
+ """
37
+ Get wage tax declarations for a company.
38
+
39
+ Args:
40
+ company_id: Optional company ID. If not provided, fetches for all companies.
41
+ year: Optional year filter. If not provided, returns current year.
42
+
43
+ Returns:
44
+ Tuple of (valid_data, invalid_data) DataFrames
45
+ """
46
+ if company_id:
47
+ df = self._get(company_id, year)
48
+ else:
49
+ df = pd.DataFrame()
50
+ for company in self.nmbrs.company_ids:
51
+ df = pd.concat([df, self._get(company, year)])
52
+
53
+ if df.empty:
54
+ return df, pd.DataFrame()
55
+
56
+ valid_data, invalid_data = Functions.validate_data(df=df, schema=CompanyWageTaxGet, debug=True)
57
+ return valid_data, invalid_data
58
+
59
+ def _get(self,
60
+ company_id: str,
61
+ year: Optional[int] = None) -> pd.DataFrame:
62
+ """
63
+ Internal method to get wage tax declarations for a single company.
64
+ """
65
+ params = {}
66
+ if year is not None:
67
+ params['year'] = year
68
+
69
+ request = requests.Request(
70
+ method='GET',
71
+ url=f"{self.nmbrs.base_url}companies/{company_id}/wagetaxes",
72
+ params=params
73
+ )
74
+
75
+ data = self.nmbrs.get_paginated_result(request)
76
+ df = pd.DataFrame(data)
77
+
78
+ if not df.empty:
79
+ df['companyId'] = company_id
80
+
81
+ return df
82
+
83
+ def get_xml(self, company_id: str, wage_tax_id: str):
84
+ """
85
+ Get the XML file of a wage tax declaration.
86
+
87
+ Args:
88
+ company_id: The ID of the company
89
+ wage_tax_id: The ID of the wage tax declaration
90
+
91
+ Returns:
92
+ Response containing the task ID for retrieving the XML file
93
+ """
94
+ resp = self.nmbrs.session.get(
95
+ url=f"{self.nmbrs.base_url}companies/{company_id}/wagetaxes/{wage_tax_id}/xml",
96
+ timeout=self.nmbrs.timeout
97
+ )
98
+ resp.raise_for_status()
99
+ return resp.json()
100
+
101
+ def get_sepa(self, company_id: str, wage_tax_id: str, year: int, payment_date: Optional[str] = None):
102
+ """
103
+ Get the SEPA (payment file) of a wage tax declaration.
104
+
105
+ Args:
106
+ company_id: The ID of the company
107
+ wage_tax_id: The ID of the wage tax declaration
108
+ year: The year of the search (required)
109
+ payment_date: Optional payment date to be added to the payment file (ISO format)
110
+
111
+ Returns:
112
+ Response containing the task ID for retrieving the SEPA file
113
+ """
114
+ params = {'year': year}
115
+ if payment_date is not None:
116
+ params['paymentDate'] = payment_date
117
+
118
+ resp = self.nmbrs.session.get(
119
+ url=f"{self.nmbrs.base_url}companies/{company_id}/wagetaxes/{wage_tax_id}/sepa",
120
+ params=params,
121
+ timeout=self.nmbrs.timeout
122
+ )
123
+ resp.raise_for_status()
124
+ return resp.json()
125
+
14
126
 
15
127
  class WageTaxSettings:
16
128
  """Wage Tax Settings History - uses REST API."""
@@ -134,7 +246,7 @@ class WageTax:
134
246
  wagetax_settings_temp['companyId'] = company['number']
135
247
  wagetax_settings = pd.concat([wagetax_settings, wagetax_settings_temp])
136
248
 
137
- valid_wagetax_settings, invalid_wagetax_settings = Functions.validate_data(df=wagetax_settings, schema=CompanyWageTaxGet, debug=True)
249
+ valid_wagetax_settings, invalid_wagetax_settings = Functions.validate_data(df=wagetax_settings, schema=CompanyWageTaxGetSOAP, debug=True)
138
250
 
139
251
  # No validation schema for now, but could be added later
140
252
  return valid_wagetax_settings, invalid_wagetax_settings
@@ -230,9 +342,6 @@ class WageTax:
230
342
  if self.nmbrs.mock_mode:
231
343
  return wage_tax_model
232
344
 
233
- # Get the auth header using the centralized method
234
- auth_header = self.nmbrs._get_soap_auth_header_employees()
235
-
236
345
  # Use the model's built-in SOAP conversion method
237
346
  wage_tax_settings = wage_tax_model.to_soap_settings(self.nmbrs.soap_client_employees)
238
347
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: brynq_sdk_nmbrs
3
- Version: 2.3.3.dev0
3
+ Version: 2.4.5
4
4
  Summary: Nmbrs wrapper from BrynQ
5
5
  Author: BrynQ
6
6
  Author-email: support@brynq.com