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,114 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import pandera as pa
|
|
4
|
+
from pandera.typing import Series, String, Float
|
|
5
|
+
from brynq_sdk_functions import BrynQPanderaDataFrameModel
|
|
6
|
+
|
|
7
|
+
from typing import Optional
|
|
8
|
+
from pydantic import BaseModel, Field, conint, confloat
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# ---------------------------
|
|
12
|
+
# Get Schemas
|
|
13
|
+
# ---------------------------
|
|
14
|
+
class FixedWageComponentGet(BrynQPanderaDataFrameModel):
|
|
15
|
+
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
16
|
+
fixed_wage_component_id: Series[String] = pa.Field(coerce=True, description="Fixed Wage Component ID", alias="fixedWageComponentId")
|
|
17
|
+
code: Series[String] = pa.Field(coerce=True, description="Wage Component Code", alias="code")
|
|
18
|
+
value: Series[Float] = pa.Field(coerce=True, description="Wage Component Value", alias="value")
|
|
19
|
+
end_year: Series[pd.Int64Dtype] = pa.Field(nullable=True, coerce=True, description="End Year", alias="endYear")
|
|
20
|
+
end_period: Series[pd.Int64Dtype] = pa.Field(nullable=True, coerce=True, description="End Period", alias="endPeriod")
|
|
21
|
+
comment: Series[String] = pa.Field(nullable=True, coerce=True, description="Comment", alias="comment")
|
|
22
|
+
cost_center_id: Series[String] = pa.Field(nullable=True, coerce=True, description="Cost Center ID", alias="costCenterId")
|
|
23
|
+
cost_unit_id: Series[String] = pa.Field(nullable=True, coerce=True, description="Cost Unit ID", alias="costUnitId")
|
|
24
|
+
|
|
25
|
+
class Config:
|
|
26
|
+
coerce = True
|
|
27
|
+
|
|
28
|
+
class _Annotation:
|
|
29
|
+
primary_key = "fixed_wage_component_id"
|
|
30
|
+
foreign_keys = {
|
|
31
|
+
"employee_id": {
|
|
32
|
+
"parent_schema": "EmployeeSchema",
|
|
33
|
+
"parent_column": "employee_id",
|
|
34
|
+
"cardinality": "N:1"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
class VariableWageComponentGet(BrynQPanderaDataFrameModel):
|
|
39
|
+
employee_id: Series[String] = pa.Field(coerce=True, description="Employee ID", alias="employeeId")
|
|
40
|
+
variable_wage_component_id: Series[String] = pa.Field(coerce=True, description="Variable Wage Component ID", alias="variableWageComponentId")
|
|
41
|
+
code: Series[String] = pa.Field(coerce=True, description="Wage Component Code", alias="code")
|
|
42
|
+
value: Series[Float] = pa.Field(coerce=True, description="Wage Component Value", alias="value")
|
|
43
|
+
comment: Series[String] = pa.Field(nullable=True, coerce=True, description="Comment", alias="comment")
|
|
44
|
+
cost_center_id: Series[String] = pa.Field(nullable=True, coerce=True, description="Cost Center ID", alias="costCenterId")
|
|
45
|
+
cost_unit_id: Series[String] = pa.Field(nullable=True, coerce=True, description="Cost Unit ID", alias="costUnitId")
|
|
46
|
+
|
|
47
|
+
class Config:
|
|
48
|
+
coerce = True
|
|
49
|
+
|
|
50
|
+
class _Annotation:
|
|
51
|
+
primary_key = "variable_wage_component_id"
|
|
52
|
+
foreign_keys = {
|
|
53
|
+
"employee_id": {
|
|
54
|
+
"parent_schema": "EmployeeSchema",
|
|
55
|
+
"parent_column": "employee_id",
|
|
56
|
+
"cardinality": "N:1"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# ---------------------------
|
|
61
|
+
# Upload Schemas
|
|
62
|
+
# ---------------------------
|
|
63
|
+
class PeriodPost(BaseModel):
|
|
64
|
+
year: int = Field(..., ge=1900, le=2100, example=2021, description="Year", alias="year")
|
|
65
|
+
period: int = Field(..., ge=1, le=53, example=4, description="Period", alias="period")
|
|
66
|
+
|
|
67
|
+
class FixedWageComponentCreate(BaseModel):
|
|
68
|
+
employee_id: str = Field(..., description="Employee identifier", alias="employeeId")
|
|
69
|
+
code: int = Field(..., ge=1, example=1100, description="Wage Component Code", alias="code")
|
|
70
|
+
value: float = Field(..., ge=0, example=500, description="Wage Component Value", alias="value")
|
|
71
|
+
end_year: Optional[int] = Field(None, ge=1900, le=2100, example=2023, description="End Year", alias="endYear")
|
|
72
|
+
end_period: Optional[int] = Field(None, ge=1, le=53, example=6, description="End Period", alias="endPeriod")
|
|
73
|
+
comment: Optional[str] = Field(None, example="some comment", description="Comment", alias="comment")
|
|
74
|
+
cost_center_id: Optional[str] = Field(None, example="aa506564-d1db-4fa8-83dc-d68db4cfcd82", description="Cost Center ID", alias="costCenterId")
|
|
75
|
+
cost_unit_id: Optional[str] = Field(None, example="d8ac6afb-2ac6-43bf-9880-2d382cdace43", description="Cost Unit ID", alias="costUnitId")
|
|
76
|
+
period_details: PeriodPost
|
|
77
|
+
unprotected_mode: Optional[bool] = Field(None, example=True, description="Unprotected Mode", alias="unprotectedMode")
|
|
78
|
+
|
|
79
|
+
class FixedWageComponentUpdate(BaseModel):
|
|
80
|
+
employee_id: str = Field(..., description="Employee identifier", alias="employeeId")
|
|
81
|
+
fixed_wage_component_id: str = Field(..., example="643c6b90-57c6-4199-9e4e-ded553572d78", description="Fixed Wage Component ID", alias="fixedWageComponentId")
|
|
82
|
+
code: Optional[int] = Field(None, ge=1, example=1100, description="Wage Component Code", alias="code")
|
|
83
|
+
value: Optional[float] = Field(None, ge=0, example=500, description="Wage Component Value", alias="value")
|
|
84
|
+
end_year: Optional[int] = Field(None, ge=1900, le=2100, example=2023, description="End Year", alias="endYear")
|
|
85
|
+
end_period: Optional[int] = Field(None, ge=1, le=53, example=6, description="End Period", alias="endPeriod")
|
|
86
|
+
comment: Optional[str] = Field(None, example="string", description="Comment", alias="comment")
|
|
87
|
+
cost_center_id: Optional[str] = Field(None, example="aa506564-d1db-4fa8-83dc-d68db4cfcd82", description="Cost Center ID", alias="costCenterId")
|
|
88
|
+
cost_unit_id: Optional[str] = Field(None, example="d8ac6afb-2ac6-43bf-9880-2d382cdace43", description="Cost Unit ID", alias="costUnitId")
|
|
89
|
+
period_details: Optional[PeriodPost] = None
|
|
90
|
+
unprotected_mode: Optional[bool] = Field(None, example=True, description="Unprotected Mode", alias="unprotectedMode")
|
|
91
|
+
|
|
92
|
+
class VariableWageComponentCreate(BaseModel):
|
|
93
|
+
employee_id: str = Field(..., description="Employee identifier", alias="employeeId")
|
|
94
|
+
code: int = Field(..., ge=1, example=3045, description="Wage Component Code", alias="code")
|
|
95
|
+
value: float = Field(..., ge=0, example=200, description="Wage Component Value", alias="value")
|
|
96
|
+
comment: Optional[str] = Field(None, example="comment", description="Comment", alias="comment")
|
|
97
|
+
cost_center_id: Optional[str] = Field(None, example="aa506564-d1db-4fa8-83dc-d68db4cfcd82", description="Cost Center ID", alias="costCenterId")
|
|
98
|
+
cost_unit_id: Optional[str] = Field(None, example="d8ac6afb-2ac6-43bf-9880-2d382cdace43", description="Cost Unit ID", alias="costUnitId")
|
|
99
|
+
period_details: PeriodPost
|
|
100
|
+
unprotected_mode: Optional[bool] = Field(None, example=True, description="Unprotected Mode", alias="unprotectedMode")
|
|
101
|
+
|
|
102
|
+
class VariableWageComponentUpdate(BaseModel):
|
|
103
|
+
employee_id: str = Field(..., description="Employee identifier", alias="employeeId")
|
|
104
|
+
variable_wage_component_id: str = Field(..., example="7fc59095-daed-4746-a7f8-a454e38e3683", description="Variable Wage Component ID", alias="variableWageComponentId")
|
|
105
|
+
code: Optional[int] = Field(None, ge=1, example=3045, description="Wage Component Code", alias="code")
|
|
106
|
+
value: Optional[float] = Field(None, ge=0, example=2200, description="Wage Component Value", alias="value")
|
|
107
|
+
comment: Optional[str] = Field(None, example="comment", description="Comment", alias="comment")
|
|
108
|
+
cost_center_id: Optional[str] = Field(None, example="aa506564-d1db-4fa8-83dc-d68db4cfcd82", description="Cost Center ID", alias="costCenterId")
|
|
109
|
+
cost_unit_id: Optional[str] = Field(None, example="d8ac6afb-2ac6-43bf-9880-2d382cdace43", description="Cost Unit ID", alias="costUnitId")
|
|
110
|
+
period_details: Optional[PeriodPost] = None
|
|
111
|
+
unprotected_mode: Optional[bool] = Field(None, example=True, description="Unprotected Mode", alias="unprotectedMode")
|
|
112
|
+
|
|
113
|
+
class WageComponentDelete(BaseModel):
|
|
114
|
+
wage_component_id: str = Field(..., example="7fc59095-daed-4746-a7f8-a454e38e3683", description="Wage Component ID", alias="wageComponentId")
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from typing import Any, Dict, List, Union, Tuple
|
|
2
|
+
import pandas as pd
|
|
3
|
+
|
|
4
|
+
from .schemas.social_insurance import SocialInsuranceUpdate
|
|
5
|
+
from zeep.exceptions import Fault
|
|
6
|
+
from zeep.helpers import serialize_object
|
|
7
|
+
# import logging
|
|
8
|
+
from brynq_sdk_functions import Functions
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SocialInsurance:
|
|
12
|
+
def __init__(self, nmbrs):
|
|
13
|
+
self.nmbrs = nmbrs
|
|
14
|
+
self.soap_client_employees = nmbrs.soap_client_employees
|
|
15
|
+
|
|
16
|
+
def update(self, data: Dict[str, Any]) -> pd.DataFrame:
|
|
17
|
+
try:
|
|
18
|
+
social_insurance_model = SocialInsuranceUpdate(**data)
|
|
19
|
+
|
|
20
|
+
if self.nmbrs.mock_mode:
|
|
21
|
+
return social_insurance_model
|
|
22
|
+
|
|
23
|
+
# Use the model's built-in SOAP conversion method
|
|
24
|
+
social_insurance_settings = social_insurance_model.to_soap_settings(self.nmbrs.soap_client_employees)
|
|
25
|
+
|
|
26
|
+
# Make SOAP request with clean, simple call
|
|
27
|
+
response = self.nmbrs.soap_client_employees.service.SVW_UpdateCurrent(
|
|
28
|
+
EmployeeId=social_insurance_model.employee_id,
|
|
29
|
+
SVWSettings=social_insurance_settings,
|
|
30
|
+
_soapheaders=[self.nmbrs.soap_auth_header]
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# Convert response to DataFrame
|
|
34
|
+
if response:
|
|
35
|
+
# Convert Zeep objects to Python dictionaries
|
|
36
|
+
serialized_response = serialize_object(response)
|
|
37
|
+
|
|
38
|
+
# Convert to list if it's not already
|
|
39
|
+
if not isinstance(serialized_response, list):
|
|
40
|
+
serialized_response = [serialized_response]
|
|
41
|
+
|
|
42
|
+
# Convert to DataFrame
|
|
43
|
+
df = pd.DataFrame(serialized_response)
|
|
44
|
+
|
|
45
|
+
return df
|
|
46
|
+
else:
|
|
47
|
+
return pd.DataFrame()
|
|
48
|
+
|
|
49
|
+
except Fault as e:
|
|
50
|
+
raise Exception(f"SOAP request failed: {str(e)}")
|
|
51
|
+
except Exception as e:
|
|
52
|
+
raise Exception(f"Failed to update Social Insurance: {str(e)}")
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
from typing import Any, Dict, List, Union, Tuple
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from .schemas.wage_tax import WageTaxGet, WageTaxUpdate, WageTaxSettingsGet
|
|
4
|
+
from zeep.exceptions import Fault
|
|
5
|
+
from zeep.ns import WSDL, SOAP_ENV_11
|
|
6
|
+
from zeep.xsd import ComplexType, Element, String
|
|
7
|
+
from zeep.helpers import serialize_object
|
|
8
|
+
# import logging
|
|
9
|
+
from brynq_sdk_functions import Functions
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class WageTax:
|
|
13
|
+
def __init__(self, nmbrs):
|
|
14
|
+
self.nmbrs = nmbrs
|
|
15
|
+
self.soap_client_companies = nmbrs.soap_client_companies
|
|
16
|
+
self.soap_client_employees = nmbrs.soap_client_employees
|
|
17
|
+
|
|
18
|
+
def get_settings(self, year: int) -> Tuple[pd.DataFrame, pd.DataFrame]:
|
|
19
|
+
"""
|
|
20
|
+
Get salary tables for all companies for a specific period and year.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
period (int): The period number
|
|
24
|
+
year (int): The year
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
pd.DataFrame: DataFrame containing the salary tables
|
|
28
|
+
"""
|
|
29
|
+
wagetax_settings = pd.DataFrame()
|
|
30
|
+
for company in self.nmbrs.soap_company_ids.to_dict(orient='records'):
|
|
31
|
+
wagetax_settings_temp = self._get(company['i_d'], year)
|
|
32
|
+
if not wagetax_settings_temp.empty:
|
|
33
|
+
wagetax_settings_temp['companyId'] = company['number']
|
|
34
|
+
wagetax_settings = pd.concat([wagetax_settings, wagetax_settings_temp])
|
|
35
|
+
|
|
36
|
+
valid_wagetax_settings, invalid_wagetax_settings = Functions.validate_data(df=wagetax_settings, schema=WageTaxSettingsGet, debug=True)
|
|
37
|
+
|
|
38
|
+
# No validation schema for now, but could be added later
|
|
39
|
+
return valid_wagetax_settings, invalid_wagetax_settings
|
|
40
|
+
|
|
41
|
+
def _get(self, company_id: int, year: int) -> pd.DataFrame:
|
|
42
|
+
"""
|
|
43
|
+
Get salary tables for a specific company, period and year.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
company_id (int): The ID of the company
|
|
47
|
+
period (int): The period number
|
|
48
|
+
year (int): The year
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
pd.DataFrame: DataFrame containing the salary tables
|
|
52
|
+
"""
|
|
53
|
+
try:
|
|
54
|
+
# Make SOAP request with the proper header structure
|
|
55
|
+
response = self.soap_client_companies.service.WageTax_GetList(
|
|
56
|
+
CompanyId=company_id,
|
|
57
|
+
intYear=year,
|
|
58
|
+
_soapheaders=[self.nmbrs.soap_auth_header]
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# Convert response to DataFrame
|
|
62
|
+
if response:
|
|
63
|
+
# Convert Zeep objects to Python dictionaries
|
|
64
|
+
serialized_response = serialize_object(response)
|
|
65
|
+
|
|
66
|
+
# Convert to list if it's not already
|
|
67
|
+
if not isinstance(serialized_response, list):
|
|
68
|
+
serialized_response = [serialized_response]
|
|
69
|
+
|
|
70
|
+
# Convert to DataFrame
|
|
71
|
+
df = pd.DataFrame(serialized_response)
|
|
72
|
+
|
|
73
|
+
return df
|
|
74
|
+
else:
|
|
75
|
+
return pd.DataFrame()
|
|
76
|
+
|
|
77
|
+
except Fault as e:
|
|
78
|
+
raise Exception(f"SOAP request failed: {str(e)}")
|
|
79
|
+
except Exception as e:
|
|
80
|
+
raise Exception(f"Failed to get salary tables: {str(e)}")
|
|
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
|
+
|
|
125
|
+
def update(self, data: Dict[str, Any]) -> pd.DataFrame:
|
|
126
|
+
try:
|
|
127
|
+
wage_tax_model = WageTaxUpdate(**data)
|
|
128
|
+
|
|
129
|
+
if self.nmbrs.mock_mode:
|
|
130
|
+
return wage_tax_model
|
|
131
|
+
|
|
132
|
+
# Get the auth header using the centralized method
|
|
133
|
+
auth_header = self.nmbrs._get_soap_auth_header_employees()
|
|
134
|
+
|
|
135
|
+
# Use the model's built-in SOAP conversion method
|
|
136
|
+
wage_tax_settings = wage_tax_model.to_soap_settings(self.nmbrs.soap_client_employees)
|
|
137
|
+
|
|
138
|
+
# Make SOAP request with clean, simple call
|
|
139
|
+
response = self.nmbrs.soap_client_employees.service.WageTax_UpdateCurrent(
|
|
140
|
+
EmployeeId=wage_tax_model.employee_id,
|
|
141
|
+
LoonheffingSettings=wage_tax_settings,
|
|
142
|
+
_soapheaders=[self.nmbrs.soap_auth_header]
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Convert response to DataFrame
|
|
146
|
+
if response:
|
|
147
|
+
# Convert Zeep objects to Python dictionaries
|
|
148
|
+
serialized_response = serialize_object(response)
|
|
149
|
+
|
|
150
|
+
# Convert to list if it's not already
|
|
151
|
+
if not isinstance(serialized_response, list):
|
|
152
|
+
serialized_response = [serialized_response]
|
|
153
|
+
|
|
154
|
+
# Convert to DataFrame
|
|
155
|
+
df = pd.DataFrame(serialized_response)
|
|
156
|
+
|
|
157
|
+
return df
|
|
158
|
+
else:
|
|
159
|
+
return pd.DataFrame()
|
|
160
|
+
|
|
161
|
+
except Fault as e:
|
|
162
|
+
raise Exception(f"SOAP request failed: {str(e)}")
|
|
163
|
+
except Exception as e:
|
|
164
|
+
raise Exception(f"Failed to update WageTax: {str(e)}")
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import math
|
|
2
|
+
import pandas as pd
|
|
3
|
+
import requests
|
|
4
|
+
from typing import Dict, Any
|
|
5
|
+
from .schemas.wagecomponents import (
|
|
6
|
+
FixedWageComponentGet,
|
|
7
|
+
VariableWageComponentGet,
|
|
8
|
+
FixedWageComponentCreate,
|
|
9
|
+
FixedWageComponentUpdate,
|
|
10
|
+
VariableWageComponentCreate,
|
|
11
|
+
VariableWageComponentUpdate,
|
|
12
|
+
WageComponentDelete
|
|
13
|
+
)
|
|
14
|
+
from brynq_sdk_functions import Functions
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class EmployeeFixedWageComponents:
|
|
18
|
+
def __init__(self, nmbrs):
|
|
19
|
+
self.nmbrs = nmbrs
|
|
20
|
+
|
|
21
|
+
def get(self,
|
|
22
|
+
created_from: str = None,
|
|
23
|
+
employee_id: str = None,
|
|
24
|
+
period: int = None,
|
|
25
|
+
year: int = None) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
26
|
+
wagecomponents = pd.DataFrame()
|
|
27
|
+
for company in self.nmbrs.company_ids:
|
|
28
|
+
wagecomponents = pd.concat([wagecomponents, self._get(company, created_from, employee_id, period, year)])
|
|
29
|
+
|
|
30
|
+
valid_wagecomponents, invalid_wagecomponents = Functions.validate_data(df=wagecomponents, schema=FixedWageComponentGet, debug=True)
|
|
31
|
+
|
|
32
|
+
return valid_wagecomponents, invalid_wagecomponents
|
|
33
|
+
|
|
34
|
+
def _get(self,
|
|
35
|
+
company_id: str,
|
|
36
|
+
created_from: str = None,
|
|
37
|
+
employee_id: str = None,
|
|
38
|
+
period: int = None,
|
|
39
|
+
year: int = None) -> pd.DataFrame:
|
|
40
|
+
params = {}
|
|
41
|
+
if created_from:
|
|
42
|
+
params['createdFrom'] = created_from
|
|
43
|
+
if employee_id:
|
|
44
|
+
params['employeeId'] = employee_id
|
|
45
|
+
if year:
|
|
46
|
+
params['year'] = year
|
|
47
|
+
if period:
|
|
48
|
+
params['period'] = period
|
|
49
|
+
request = requests.Request(method='GET',
|
|
50
|
+
url=f"{self.nmbrs.base_url}companies/{company_id}/employees/fixedwagecomponents",
|
|
51
|
+
params=params)
|
|
52
|
+
|
|
53
|
+
data = self.nmbrs.get_paginated_result(request)
|
|
54
|
+
df = pd.json_normalize(
|
|
55
|
+
data,
|
|
56
|
+
record_path='fixedWageComponents',
|
|
57
|
+
meta=['employeeId']
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
return df
|
|
61
|
+
|
|
62
|
+
def create(self, employee_id: str, data: Dict[str, Any]):
|
|
63
|
+
"""
|
|
64
|
+
Create a new fixed wage component for an employee using Pydantic validation.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
employee_id: The ID of the employee
|
|
68
|
+
data: Dictionary containing fixed wage component data with fields matching
|
|
69
|
+
the FixedWageComponentCreate schema (using camelCase field names)
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Response from the API
|
|
73
|
+
"""
|
|
74
|
+
# Validate with Pydantic model - this will raise an error if required fields are missing
|
|
75
|
+
wage_component_model = FixedWageComponentCreate(**data)
|
|
76
|
+
|
|
77
|
+
if self.nmbrs.mock_mode:
|
|
78
|
+
return wage_component_model
|
|
79
|
+
|
|
80
|
+
# Convert validated model to dict for API payload
|
|
81
|
+
payload = wage_component_model.dict(exclude_none=True)
|
|
82
|
+
|
|
83
|
+
# Send request
|
|
84
|
+
resp = self.nmbrs.session.post(
|
|
85
|
+
url=f"{self.nmbrs.base_url}employees/{employee_id}/fixedwagecomponent",
|
|
86
|
+
json=payload,
|
|
87
|
+
timeout=self.nmbrs.timeout
|
|
88
|
+
)
|
|
89
|
+
return resp
|
|
90
|
+
|
|
91
|
+
def update(self, employee_id: str, data: Dict[str, Any]):
|
|
92
|
+
"""
|
|
93
|
+
Update an existing fixed wage component for an employee using Pydantic validation.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
employee_id: The ID of the employee
|
|
97
|
+
data: Dictionary containing fixed wage component data with fields matching
|
|
98
|
+
the FixedWageComponentUpdate schema (using camelCase field names)
|
|
99
|
+
|
|
100
|
+
Returns:
|
|
101
|
+
Response from the API
|
|
102
|
+
"""
|
|
103
|
+
# Validate with Pydantic model - this will raise an error if required fields are missing
|
|
104
|
+
wage_component_model = FixedWageComponentUpdate(**data)
|
|
105
|
+
|
|
106
|
+
if self.nmbrs.mock_mode:
|
|
107
|
+
return wage_component_model
|
|
108
|
+
|
|
109
|
+
# Convert validated model to dict for API payload
|
|
110
|
+
payload = wage_component_model.dict(exclude_none=True)
|
|
111
|
+
|
|
112
|
+
# Send request
|
|
113
|
+
resp = self.nmbrs.session.put(
|
|
114
|
+
url=f"{self.nmbrs.base_url}employees/{employee_id}/fixedwagecomponent",
|
|
115
|
+
json=payload,
|
|
116
|
+
timeout=self.nmbrs.timeout
|
|
117
|
+
)
|
|
118
|
+
return resp
|
|
119
|
+
|
|
120
|
+
def delete(self, employee_id: str, wagecomponent_id: str):
|
|
121
|
+
"""
|
|
122
|
+
Delete a wage component for an employee.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
employee_id: The ID of the employee
|
|
126
|
+
wagecomponent_id: The ID of the wage component to delete
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
Response from the API
|
|
130
|
+
"""
|
|
131
|
+
# Validate with Pydantic model
|
|
132
|
+
delete_model = WageComponentDelete(wagecomponentId=wagecomponent_id)
|
|
133
|
+
|
|
134
|
+
if self.nmbrs.mock_mode:
|
|
135
|
+
return delete_model
|
|
136
|
+
|
|
137
|
+
resp = self.nmbrs.session.delete(
|
|
138
|
+
url=f"{self.nmbrs.base_url}employees/{employee_id}/wagecomponents/{wagecomponent_id}",
|
|
139
|
+
timeout=self.nmbrs.timeout
|
|
140
|
+
)
|
|
141
|
+
return resp
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class EmployeeVariableWageComponents:
|
|
145
|
+
def __init__(self, nmbrs):
|
|
146
|
+
self.nmbrs = nmbrs
|
|
147
|
+
|
|
148
|
+
def get(self,
|
|
149
|
+
created_from: str = None,
|
|
150
|
+
employee_id: str = None,
|
|
151
|
+
period: int = None,
|
|
152
|
+
year: int = None) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
153
|
+
wagecomponents = pd.DataFrame()
|
|
154
|
+
for company in self.nmbrs.company_ids:
|
|
155
|
+
wagecomponents = pd.concat([wagecomponents, self._get(company, created_from, employee_id, period, year)])
|
|
156
|
+
|
|
157
|
+
valid_wagecomponents, invalid_wagecomponents = Functions.validate_data(df=wagecomponents, schema=VariableWageComponentGet, debug=True)
|
|
158
|
+
|
|
159
|
+
return valid_wagecomponents, invalid_wagecomponents
|
|
160
|
+
|
|
161
|
+
def _get(self,
|
|
162
|
+
company_id: str,
|
|
163
|
+
created_from: str = None,
|
|
164
|
+
employee_id: str = None,
|
|
165
|
+
period: int = None,
|
|
166
|
+
year: int = None) -> pd.DataFrame:
|
|
167
|
+
params = {}
|
|
168
|
+
if created_from:
|
|
169
|
+
params['createdFrom'] = created_from
|
|
170
|
+
if employee_id:
|
|
171
|
+
params['employeeId'] = employee_id
|
|
172
|
+
if year:
|
|
173
|
+
params['year'] = year
|
|
174
|
+
if period:
|
|
175
|
+
params['period'] = period
|
|
176
|
+
request = requests.Request(method='GET',
|
|
177
|
+
url=f"{self.nmbrs.base_url}companies/{company_id}/employees/variablewagecomponents",
|
|
178
|
+
params=params)
|
|
179
|
+
|
|
180
|
+
data = self.nmbrs.get_paginated_result(request)
|
|
181
|
+
df = pd.json_normalize(
|
|
182
|
+
data,
|
|
183
|
+
record_path='variablewagecomponents',
|
|
184
|
+
meta=['employeeId']
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
return df
|
|
188
|
+
|
|
189
|
+
def create(self, employee_id: str, data: Dict[str, Any]):
|
|
190
|
+
"""
|
|
191
|
+
Create a new variable wage component for an employee using Pydantic validation.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
employee_id: The ID of the employee
|
|
195
|
+
data: Dictionary containing variable wage component data with fields matching
|
|
196
|
+
the VariableWageComponentCreate schema (using camelCase field names)
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
Response from the API
|
|
200
|
+
"""
|
|
201
|
+
# Validate with Pydantic model - this will raise an error if required fields are missing
|
|
202
|
+
wage_component_model = VariableWageComponentCreate(**data)
|
|
203
|
+
|
|
204
|
+
if self.nmbrs.mock_mode:
|
|
205
|
+
return wage_component_model
|
|
206
|
+
|
|
207
|
+
# Convert validated model to dict for API payload
|
|
208
|
+
payload = wage_component_model.dict(exclude_none=True)
|
|
209
|
+
|
|
210
|
+
# Send request
|
|
211
|
+
resp = self.nmbrs.session.post(
|
|
212
|
+
url=f"{self.nmbrs.base_url}employees/{employee_id}/variablewagecomponent",
|
|
213
|
+
json=payload,
|
|
214
|
+
timeout=self.nmbrs.timeout
|
|
215
|
+
)
|
|
216
|
+
return resp
|
|
217
|
+
|
|
218
|
+
def update(self, employee_id: str, data: Dict[str, Any]):
|
|
219
|
+
"""
|
|
220
|
+
Update an existing variable wage component for an employee using Pydantic validation.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
employee_id: The ID of the employee
|
|
224
|
+
data: Dictionary containing variable wage component data with fields matching
|
|
225
|
+
the VariableWageComponentUpdate schema (using camelCase field names)
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
Response from the API
|
|
229
|
+
"""
|
|
230
|
+
# Validate with Pydantic model - this will raise an error if required fields are missing
|
|
231
|
+
wage_component_model = VariableWageComponentUpdate(**data)
|
|
232
|
+
|
|
233
|
+
if self.nmbrs.mock_mode:
|
|
234
|
+
return wage_component_model
|
|
235
|
+
|
|
236
|
+
# Convert validated model to dict for API payload
|
|
237
|
+
payload = wage_component_model.dict(exclude_none=True)
|
|
238
|
+
|
|
239
|
+
# Send request
|
|
240
|
+
resp = self.nmbrs.session.put(
|
|
241
|
+
url=f"{self.nmbrs.base_url}employees/{employee_id}/variablewagecomponent",
|
|
242
|
+
json=payload,
|
|
243
|
+
timeout=self.nmbrs.timeout
|
|
244
|
+
)
|
|
245
|
+
return resp
|
|
246
|
+
|
|
247
|
+
def delete(self, employee_id: str, wagecomponent_id: str):
|
|
248
|
+
"""
|
|
249
|
+
Delete a wage component for an employee.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
employee_id: The ID of the employee
|
|
253
|
+
wagecomponent_id: The ID of the wage component to delete
|
|
254
|
+
|
|
255
|
+
Returns:
|
|
256
|
+
Response from the API
|
|
257
|
+
"""
|
|
258
|
+
# Validate with Pydantic model
|
|
259
|
+
delete_model = WageComponentDelete(wagecomponentId=wagecomponent_id)
|
|
260
|
+
|
|
261
|
+
if self.nmbrs.mock_mode:
|
|
262
|
+
return delete_model
|
|
263
|
+
|
|
264
|
+
resp = self.nmbrs.session.delete(
|
|
265
|
+
url=f"{self.nmbrs.base_url}employees/{employee_id}/wagecomponents/{wagecomponent_id}",
|
|
266
|
+
timeout=self.nmbrs.timeout
|
|
267
|
+
)
|
|
268
|
+
return resp
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: brynq_sdk_nmbrs
|
|
3
|
+
Version: 2.3.1
|
|
4
|
+
Summary: Nmbrs wrapper from BrynQ
|
|
5
|
+
Author: BrynQ
|
|
6
|
+
Author-email: support@brynq.com
|
|
7
|
+
License: BrynQ License
|
|
8
|
+
Requires-Dist: brynq-sdk-brynq<5,>=4
|
|
9
|
+
Requires-Dist: pandas<3.0.0,>=2.2.0
|
|
10
|
+
Requires-Dist: pydantic<3.0.0,>=2.5.0
|
|
11
|
+
Requires-Dist: pandera<1.0.0,>=0.16.0
|
|
12
|
+
Requires-Dist: zeep<5.0.0,>=4.0.0
|
|
13
|
+
Requires-Dist: brynq-sdk-functions>=2.0.5
|
|
14
|
+
Dynamic: author
|
|
15
|
+
Dynamic: author-email
|
|
16
|
+
Dynamic: description
|
|
17
|
+
Dynamic: license
|
|
18
|
+
Dynamic: requires-dist
|
|
19
|
+
Dynamic: summary
|
|
20
|
+
|
|
21
|
+
Nmbrs wrapper from BrynQ
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
brynq_sdk_nmbrs/__init__.py,sha256=O6SxqypTQcyz-CpgFu23RZWR5SekYirLn8iEydp9bAE,9836
|
|
2
|
+
brynq_sdk_nmbrs/absence.py,sha256=xNzoDgw0Jj-JYS68lpwNzbrDy3BKsR-Iz-anlJW7YS0,4658
|
|
3
|
+
brynq_sdk_nmbrs/address.py,sha256=FTzzs04tyNZNoysQ18lei137JXhvZUjYH8vS3Z5Nnk4,2325
|
|
4
|
+
brynq_sdk_nmbrs/bank.py,sha256=2zZ9pCEdPkxvjqyyo0bfZw0JpJpzDBXZVNmO3lHjHGQ,4165
|
|
5
|
+
brynq_sdk_nmbrs/children.py,sha256=hwgh3RKTs6oK6ztZ-TADXXK4Ekq_svo81D9aytCzkE4,3479
|
|
6
|
+
brynq_sdk_nmbrs/companies.py,sha256=fqG9JERkaatkfzLFO3vC37rHr_W6pZ2DOeWS68b-TGc,3426
|
|
7
|
+
brynq_sdk_nmbrs/contract.py,sha256=lccpAbhNjj4x45WOnF7h2LlBG5XCXelnis7WyPvJJrE,4527
|
|
8
|
+
brynq_sdk_nmbrs/costcenter.py,sha256=gz7e486E9NqFXkqt50CctQ8DERC3pI2SPWsQWpIkHos,6087
|
|
9
|
+
brynq_sdk_nmbrs/costunit.py,sha256=GGLwdCOYGU96Zr-zyG86rggzdsccH0IojfrPn5GanTI,3092
|
|
10
|
+
brynq_sdk_nmbrs/days.py,sha256=T2ZdMCN1iE6WseX40Hn8-iNRCz47kWUuwNVRwQJX7TY,4534
|
|
11
|
+
brynq_sdk_nmbrs/debtors.py,sha256=yig5Fdv9deyeoVwlGu8n5wwKdx7gZBDKtJLitQDAX98,785
|
|
12
|
+
brynq_sdk_nmbrs/department.py,sha256=9Yk80w9lME5cN9FjtQ8_w0RDjqVwny54xDkI2FWmJ8M,4216
|
|
13
|
+
brynq_sdk_nmbrs/document.py,sha256=Eb2mpsQRI1t5u0szUsc8YYI8tC_8ARW7wZUZRFA8RzQ,839
|
|
14
|
+
brynq_sdk_nmbrs/employees.py,sha256=9ypKi7dFh5rqXL9mFJ2ltHci40idsk_sbuZjYfT_b_w,7517
|
|
15
|
+
brynq_sdk_nmbrs/employment.py,sha256=P5EQhSAA6LOfeF2VeaAI8NZFTwSpD81ggJ9kUQp-WpE,3789
|
|
16
|
+
brynq_sdk_nmbrs/function.py,sha256=bsafEcLglr2iT3jehbmGAme6-xI2ieOvaAueeVVT64I,3066
|
|
17
|
+
brynq_sdk_nmbrs/hours.py,sha256=3pbl6IA8BBC6wrfTvkJha1LJi4SjrZCBINUANhuDvDQ,8140
|
|
18
|
+
brynq_sdk_nmbrs/leave.py,sha256=Z17nPlRTVy_pqyInrbJNnF_83c8__Z207nh1aWVycCg,4515
|
|
19
|
+
brynq_sdk_nmbrs/manager.py,sha256=wE2UJYPsKUN5jv3HmLpVAERcxcChwoMLfFgja8vxM6U,9441
|
|
20
|
+
brynq_sdk_nmbrs/salaries.py,sha256=0VZgPwIl4YSeil7IUliPg8XFWloIQX2rBoWurSOLa9g,2910
|
|
21
|
+
brynq_sdk_nmbrs/salary_tables.py,sha256=T7_bJE-CtRF08FWyLJnXm5Q3Q5Usozx4iCByqoTPOwo,9390
|
|
22
|
+
brynq_sdk_nmbrs/schedules.py,sha256=jvi3aRdsgU_lalVWAcnfsfg8-g7J4m8pVW42HP-aExA,2928
|
|
23
|
+
brynq_sdk_nmbrs/social_insurance.py,sha256=7sfgZeGDXGrvcsj8tTj7JaFK2fSOzVdtEjJ0wKRr2BI,1899
|
|
24
|
+
brynq_sdk_nmbrs/wage_tax.py,sha256=NgqzEwzc_n28LtWhOM4EfHUo-vy-QwZA6wiL2n8LcdM,6241
|
|
25
|
+
brynq_sdk_nmbrs/wagecomponents.py,sha256=nkk7HGlcdEx2K3VQ2G2zwLbNMFPNHQK4YwOEnFBtDj0,9539
|
|
26
|
+
brynq_sdk_nmbrs/schemas/__init__.py,sha256=rwMb9AJSBXn_50SOa1rIvwOsCrtpj3vQxjXioxrxuyI,2301
|
|
27
|
+
brynq_sdk_nmbrs/schemas/absence.py,sha256=f2ZDpy0qnyUyCjk2JjTNCazB_12lmP462MkI4eyf3ws,3320
|
|
28
|
+
brynq_sdk_nmbrs/schemas/address.py,sha256=jgckNL5GhI23U0CS6VSs8vdl0pd4Goue57pIB8Mg6RU,4151
|
|
29
|
+
brynq_sdk_nmbrs/schemas/bank.py,sha256=h5OtnD9DfJXfNeAoD9gm1434qXchbS6RPLKNRpxQ2RU,4537
|
|
30
|
+
brynq_sdk_nmbrs/schemas/contracts.py,sha256=wb_NJyzKg7pjtWVelKj1_rfI57cs8jQ2QnMVu-aS_jI,3848
|
|
31
|
+
brynq_sdk_nmbrs/schemas/costcenter.py,sha256=vB-cJCaLn57Gc7oAK2PTJvIpnz7zZkEX5ry0iJ_ZaX8,5328
|
|
32
|
+
brynq_sdk_nmbrs/schemas/costunit.py,sha256=dH1nD9yuT94YamBz8phhuZ7E7AEuU4DmL6dXQYI8lu0,1854
|
|
33
|
+
brynq_sdk_nmbrs/schemas/days.py,sha256=GJC9-ELfWCFVA7Z1vq4UANq8omFnPdeiowhjUu7-7a0,6952
|
|
34
|
+
brynq_sdk_nmbrs/schemas/debtor.py,sha256=07FUL9MNKMfGKUifqeWSgQBTq1pVG5NB0OkaFgB9v88,721
|
|
35
|
+
brynq_sdk_nmbrs/schemas/department.py,sha256=Rq88XAOIMNzojpHhb3awdV1ALlmkI_ZjMbiwXKSz6lY,3106
|
|
36
|
+
brynq_sdk_nmbrs/schemas/employees.py,sha256=QblOZk4BCbXGoDW-kdAAykl-aLXzsBmfjewG_vU0qwg,11077
|
|
37
|
+
brynq_sdk_nmbrs/schemas/employment.py,sha256=4KY0WEdZfJ-4x_loaZhBLoPYwQcA3k3TYuWRZj4PDxI,2678
|
|
38
|
+
brynq_sdk_nmbrs/schemas/function.py,sha256=c0LkdAvyLr1_b9e7h7-2KD4v-YHtCKrm3x54Lc6V_sk,2503
|
|
39
|
+
brynq_sdk_nmbrs/schemas/hours.py,sha256=CJOD3-NL80bh3nqIZ6DwoKQ0MGfe5ba84IXv0HsA_pA,8201
|
|
40
|
+
brynq_sdk_nmbrs/schemas/leave.py,sha256=pofHHdYuPTS4hdFQbYQf2NbbYb4QlD3jI5CPGXSpNq8,3313
|
|
41
|
+
brynq_sdk_nmbrs/schemas/manager.py,sha256=NT8Uh1yfoZQ9ODCZBkVUJ50QwQ5GtHNG6_Rx_EO674U,9310
|
|
42
|
+
brynq_sdk_nmbrs/schemas/salary.py,sha256=pq-4hOB7QIo0BG8_Q_JnDbovPAhXOytfCpSuU_kXrGw,5511
|
|
43
|
+
brynq_sdk_nmbrs/schemas/schedules.py,sha256=ITB4GAVNXyQLh0Ji_kJpdp1ZNGtYRlOTNHRvNiLg8wg,5481
|
|
44
|
+
brynq_sdk_nmbrs/schemas/social_insurance.py,sha256=xJX7Duzcnu4vrKWIAan1iCUhNDtRflOLrIg7YBbtu70,2470
|
|
45
|
+
brynq_sdk_nmbrs/schemas/wage_tax.py,sha256=ohbsc0zIHcZ-oj4vctxFA6XWIs0Wv9Uu4jUy7EP61ZU,7342
|
|
46
|
+
brynq_sdk_nmbrs/schemas/wagecomponents.py,sha256=_t00-b22JEgihDdMMjwVw1mzCEnna55RnEZDYFwDZ1c,7769
|
|
47
|
+
brynq_sdk_nmbrs-2.3.1.dist-info/METADATA,sha256=Q0gZCGo8Lx9WF_6Difmfx_ClIhndS-fEgNELrzp0hUo,529
|
|
48
|
+
brynq_sdk_nmbrs-2.3.1.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
|
|
49
|
+
brynq_sdk_nmbrs-2.3.1.dist-info/top_level.txt,sha256=LrSQFzIV7FP02jBHdBKubiCbIy0C_5YnTz3DSYYoQzg,16
|
|
50
|
+
brynq_sdk_nmbrs-2.3.1.dist-info/RECORD,,
|