brynq-sdk-alight 1.0.0__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_alight/__init__.py +1019 -0
- brynq_sdk_alight/address.py +72 -0
- brynq_sdk_alight/archive/flat_wrapper.py +139 -0
- brynq_sdk_alight/archive/hrxml_generator.py +280 -0
- brynq_sdk_alight/archive/managers.py +132 -0
- brynq_sdk_alight/archive/managers_generic.py +114 -0
- brynq_sdk_alight/archive/managers_old_complex.py +294 -0
- brynq_sdk_alight/archive/managers_simple.py +229 -0
- brynq_sdk_alight/employee.py +81 -0
- brynq_sdk_alight/job.py +89 -0
- brynq_sdk_alight/leave.py +97 -0
- brynq_sdk_alight/pay_elements.py +97 -0
- brynq_sdk_alight/salary.py +89 -0
- brynq_sdk_alight/schemas/__init__.py +26 -0
- brynq_sdk_alight/schemas/absence.py +83 -0
- brynq_sdk_alight/schemas/address.py +113 -0
- brynq_sdk_alight/schemas/employee.py +641 -0
- brynq_sdk_alight/schemas/generated_envelope_xsd_schema/__init__.py +38683 -0
- brynq_sdk_alight/schemas/generated_envelope_xsd_schema/process_pay_serv_emp.py +622264 -0
- brynq_sdk_alight/schemas/generated_xsd_schemas/__init__.py +10965 -0
- brynq_sdk_alight/schemas/generated_xsd_schemas/csec_person.py +39808 -0
- brynq_sdk_alight/schemas/generated_xsd_schemas/hrxml_indicative_data.py +90318 -0
- brynq_sdk_alight/schemas/generated_xsd_schemas/openapplications_bod.py +33869 -0
- brynq_sdk_alight/schemas/generated_xsd_schemas/openapplications_code_list_currency_code_iso_7_04.py +365 -0
- brynq_sdk_alight/schemas/generated_xsd_schemas/openapplications_code_list_language_code_iso_7_04.py +16 -0
- brynq_sdk_alight/schemas/generated_xsd_schemas/openapplications_code_list_mimemedia_type_code_iana_7_04.py +16 -0
- brynq_sdk_alight/schemas/generated_xsd_schemas/openapplications_code_list_unit_code_unece_7_04.py +14 -0
- brynq_sdk_alight/schemas/generated_xsd_schemas/openapplications_code_lists.py +535 -0
- brynq_sdk_alight/schemas/generated_xsd_schemas/openapplications_qualified_data_types.py +84 -0
- brynq_sdk_alight/schemas/generated_xsd_schemas/openapplications_unqualified_data_types.py +1449 -0
- brynq_sdk_alight/schemas/job.py +129 -0
- brynq_sdk_alight/schemas/leave.py +58 -0
- brynq_sdk_alight/schemas/payments.py +207 -0
- brynq_sdk_alight/schemas/salary.py +67 -0
- brynq_sdk_alight/schemas/termination.py +48 -0
- brynq_sdk_alight/schemas/timequota.py +66 -0
- brynq_sdk_alight/schemas/utils.py +452 -0
- brynq_sdk_alight/termination.py +103 -0
- brynq_sdk_alight/time_elements.py +121 -0
- brynq_sdk_alight/time_quotas.py +114 -0
- brynq_sdk_alight-1.0.0.dist-info/METADATA +20 -0
- brynq_sdk_alight-1.0.0.dist-info/RECORD +44 -0
- brynq_sdk_alight-1.0.0.dist-info/WHEEL +5 -0
- brynq_sdk_alight-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Flat, user-friendly job/deployment model for Alight SDK.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import datetime
|
|
6
|
+
from typing import List, Optional, Dict, Any
|
|
7
|
+
from pydantic import Field, BaseModel
|
|
8
|
+
|
|
9
|
+
from .utils import add_to_nested_path # not used here; kept for parity if needed
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Job(BaseModel):
|
|
13
|
+
"""
|
|
14
|
+
Simplified job/deployment model.
|
|
15
|
+
Uses PURE schema-driven conversion - NO hardcoded structure mappings.
|
|
16
|
+
Uses aliases to match expected field names in Employee model.
|
|
17
|
+
"""
|
|
18
|
+
model_config = {
|
|
19
|
+
"populate_by_name": True # Allow populating by field name in addition to alias
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
title: str = Field(
|
|
23
|
+
description="Job title",
|
|
24
|
+
alias="indicative_person_dossier.indicative_deployment.job.job_title"
|
|
25
|
+
)
|
|
26
|
+
department: Optional[str] = Field(
|
|
27
|
+
default=None,
|
|
28
|
+
description="Department name",
|
|
29
|
+
alias="indicative_person_dossier.indicative_deployment.department_name"
|
|
30
|
+
)
|
|
31
|
+
position_id: Optional[str] = Field(
|
|
32
|
+
default=None,
|
|
33
|
+
description="Position identifier",
|
|
34
|
+
alias="indicative_person_dossier.indicative_deployment.position_id"
|
|
35
|
+
)
|
|
36
|
+
position_title: Optional[str] = Field(
|
|
37
|
+
default=None,
|
|
38
|
+
description="Position title",
|
|
39
|
+
alias="indicative_person_dossier.indicative_deployment.position_title"
|
|
40
|
+
)
|
|
41
|
+
location_code: Optional[str] = Field(
|
|
42
|
+
default=None,
|
|
43
|
+
description="Work location code",
|
|
44
|
+
alias="indicative_person_dossier.indicative_deployment.work_location.location_id"
|
|
45
|
+
)
|
|
46
|
+
work_location_city_name: Optional[str] = Field(
|
|
47
|
+
default=None,
|
|
48
|
+
description="Work location city name",
|
|
49
|
+
alias="indicative_person_dossier.indicative_deployment.work_location.address.city_name"
|
|
50
|
+
)
|
|
51
|
+
work_location_country_sub_division_code: Optional[str] = Field(
|
|
52
|
+
default=None,
|
|
53
|
+
description="Work location country subdivision/state code",
|
|
54
|
+
alias="indicative_person_dossier.indicative_deployment.work_location.address.country_sub_division_code"
|
|
55
|
+
)
|
|
56
|
+
work_location_postal_code: Optional[str] = Field(
|
|
57
|
+
default=None,
|
|
58
|
+
description="Work location postal code",
|
|
59
|
+
alias="indicative_person_dossier.indicative_deployment.work_location.address.postal_code"
|
|
60
|
+
)
|
|
61
|
+
manager_id: Optional[str] = Field(
|
|
62
|
+
default=None,
|
|
63
|
+
description="Manager employee ID",
|
|
64
|
+
alias="indicative_person_dossier.indicative_deployment.manager_id.id"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Schedule
|
|
68
|
+
weekly_hours: Optional[float] = Field(
|
|
69
|
+
default=None,
|
|
70
|
+
description="Weekly working hours",
|
|
71
|
+
alias="indicative_person_dossier.indicative_deployment.schedule.scheduled_hours[0].value"
|
|
72
|
+
)
|
|
73
|
+
weekly_hours_basis: Optional[str] = Field(
|
|
74
|
+
default="Week",
|
|
75
|
+
description="Schedule basis for weekly hours",
|
|
76
|
+
alias="indicative_person_dossier.indicative_deployment.schedule.scheduled_hours[0].schedule_basis"
|
|
77
|
+
)
|
|
78
|
+
pay_cycle_hours: Optional[float] = Field(
|
|
79
|
+
default=None,
|
|
80
|
+
description="Hours per pay cycle",
|
|
81
|
+
alias="indicative_person_dossier.indicative_deployment.schedule.scheduled_hours[1].value"
|
|
82
|
+
)
|
|
83
|
+
pay_cycle_hours_basis: Optional[str] = Field(
|
|
84
|
+
default=None,
|
|
85
|
+
description="Schedule basis for pay cycle hours",
|
|
86
|
+
alias="indicative_person_dossier.indicative_deployment.schedule.scheduled_hours[1].schedule_basis"
|
|
87
|
+
)
|
|
88
|
+
scheduled_days_per_week: Optional[float] = Field(
|
|
89
|
+
default=None,
|
|
90
|
+
description="Scheduled days per week",
|
|
91
|
+
alias="indicative_person_dossier.indicative_deployment.schedule.scheduled_days[0].value"
|
|
92
|
+
)
|
|
93
|
+
scheduled_days_basis: Optional[str] = Field(
|
|
94
|
+
default=None,
|
|
95
|
+
description="Schedule basis for scheduled days",
|
|
96
|
+
alias="indicative_person_dossier.indicative_deployment.schedule.scheduled_days[0].schedule_basis"
|
|
97
|
+
)
|
|
98
|
+
day_schedule_id: Optional[str] = Field(
|
|
99
|
+
default=None,
|
|
100
|
+
description="Day schedule ID",
|
|
101
|
+
alias="indicative_person_dossier.indicative_deployment.schedule.day_schedule[0].id"
|
|
102
|
+
)
|
|
103
|
+
fte_ratio: Optional[str] = Field(
|
|
104
|
+
default=None,
|
|
105
|
+
description="Full-time equivalent ratio",
|
|
106
|
+
alias="indicative_person_dossier.indicative_deployment.full_time_equivalent_ratio"
|
|
107
|
+
)
|
|
108
|
+
work_level_code: Optional[str] = Field(
|
|
109
|
+
default="FullTime",
|
|
110
|
+
description="FullTime/PartTime",
|
|
111
|
+
alias="indicative_person_dossier.indicative_deployment.work_level_code"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# Organization fields removed - these belong in Employee model
|
|
115
|
+
|
|
116
|
+
# Dates - employment lifecycle dates moved to Employee model
|
|
117
|
+
valid_from: Optional[datetime.date] = Field(
|
|
118
|
+
default=None,
|
|
119
|
+
description="Valid from date",
|
|
120
|
+
alias="indicative_person_dossier.indicative_deployment.valid_from"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
def to_nested_dict(self) -> Dict[str, Any]:
|
|
124
|
+
"""
|
|
125
|
+
Convert to nested structure compatible with employee job fields.
|
|
126
|
+
Rely on index-aware aliases.
|
|
127
|
+
"""
|
|
128
|
+
data = self.model_dump(exclude_none=True, by_alias=True)
|
|
129
|
+
return data
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Flat, user-friendly leave model for Alight SDK.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import datetime
|
|
6
|
+
from typing import Optional, Dict, Any
|
|
7
|
+
from pydantic import Field, BaseModel
|
|
8
|
+
|
|
9
|
+
from .utils import add_to_nested_path # not used here
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Leave(BaseModel):
|
|
13
|
+
"""
|
|
14
|
+
Simplified leave model.
|
|
15
|
+
Uses PURE schema-driven conversion - NO hardcoded structure mappings.
|
|
16
|
+
Uses aliases to match expected field names in Employee model.
|
|
17
|
+
Maps to IndicativeEmployment.employment_lifecycle.leave[0].
|
|
18
|
+
"""
|
|
19
|
+
model_config = {
|
|
20
|
+
"populate_by_name": True
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
leave_reason_code: Optional[str] = Field(
|
|
24
|
+
default=None,
|
|
25
|
+
description="Reason for leave",
|
|
26
|
+
alias="indicative_person_dossier.indicative_employment.employment_lifecycle.leave[0].leave_reason_code"
|
|
27
|
+
)
|
|
28
|
+
leave_status_code: Optional[str] = Field(
|
|
29
|
+
default=None,
|
|
30
|
+
description="Current leave status",
|
|
31
|
+
alias="indicative_person_dossier.indicative_employment.employment_lifecycle.leave[0].leave_status_code"
|
|
32
|
+
)
|
|
33
|
+
leave_start_date: Optional[datetime.date] = Field(
|
|
34
|
+
default=None,
|
|
35
|
+
description="Leave start date",
|
|
36
|
+
alias="indicative_person_dossier.indicative_employment.employment_lifecycle.leave[0].leave_start_date"
|
|
37
|
+
)
|
|
38
|
+
last_paid_date: Optional[datetime.date] = Field(
|
|
39
|
+
default=None,
|
|
40
|
+
description="Last paid date during leave",
|
|
41
|
+
alias="indicative_person_dossier.indicative_employment.employment_lifecycle.leave[0].last_paid_date"
|
|
42
|
+
)
|
|
43
|
+
scheduled_work_return_date: Optional[datetime.date] = Field(
|
|
44
|
+
default=None,
|
|
45
|
+
description="Scheduled work return date",
|
|
46
|
+
alias="indicative_person_dossier.indicative_employment.employment_lifecycle.leave[0].scheduled_work_return_date"
|
|
47
|
+
)
|
|
48
|
+
work_return_date: Optional[datetime.date] = Field(
|
|
49
|
+
default=None,
|
|
50
|
+
description="Actual work return date",
|
|
51
|
+
alias="indicative_person_dossier.indicative_employment.employment_lifecycle.leave[0].work_return_date"
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
def to_nested_dict(self) -> Dict[str, Any]:
|
|
55
|
+
"""
|
|
56
|
+
Convert to nested structure compatible with employee model.
|
|
57
|
+
"""
|
|
58
|
+
return self.model_dump(exclude_none=True, by_alias=True)
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
from typing import Optional, Dict, Any
|
|
2
|
+
import datetime
|
|
3
|
+
from pydantic import Field, BaseModel
|
|
4
|
+
|
|
5
|
+
from .utils import add_to_nested_path, post_process_nested_data, convert_datetime_to_xml, construct_model
|
|
6
|
+
from .absence import Absences
|
|
7
|
+
from .timequota import TimeQuotas
|
|
8
|
+
from ..schemas.generated_envelope_xsd_schema.process_pay_serv_emp import PayServEmpExtension as XsdPayServEmpExtension
|
|
9
|
+
from ..schemas.generated_envelope_xsd_schema.process_pay_serv_emp import PayServEmpPayElements as XsdPayServEmpPayElements
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PayServEmpExtensionCreate(BaseModel):
|
|
13
|
+
"""
|
|
14
|
+
Alias-driven flat model for NGA PayServEmpExtension (index-aware paths, no custom logic).
|
|
15
|
+
"""
|
|
16
|
+
model_config = {
|
|
17
|
+
"populate_by_name": True
|
|
18
|
+
}
|
|
19
|
+
# Payment Instructions [0]
|
|
20
|
+
payment_valid_from: Optional[datetime.date] = Field(default=None, alias="payment_instructions[0].valid_from")
|
|
21
|
+
payment_type: Optional[str] = Field(default=None, alias="payment_instructions[0].payment_type")
|
|
22
|
+
payment_method: Optional[str] = Field(default=None, alias="payment_instructions[0].payment_method")
|
|
23
|
+
payment_type_code: Optional[str] = Field(default=None, alias="payment_instructions[0].payment_type_code")
|
|
24
|
+
local_payment_method: Optional[str] = Field(default=None, alias="payment_instructions[0].local_payment_method")
|
|
25
|
+
amount: Optional[list[str]] = Field(default=None, alias="payment_instructions[0].amount")
|
|
26
|
+
currency_code: Optional[str] = Field(default=None, alias="payment_instructions[0].currency_code")
|
|
27
|
+
payment_percentage: Optional[list[str]] = Field(default=None, alias="payment_instructions[0].payment_percentage")
|
|
28
|
+
name_on_account: Optional[str] = Field(default=None, alias="payment_instructions[0].direct_deposit_account.name_on_account")
|
|
29
|
+
account_type_code: Optional[str] = Field(default=None, alias="payment_instructions[0].direct_deposit_account.type_code[0]")
|
|
30
|
+
bank_routing_id: Optional[str] = Field(default=None, alias="payment_instructions[0].direct_deposit_account.bank_routing_id[0]")
|
|
31
|
+
bank_routing_id_swift: Optional[str] = Field(default=None, alias="payment_instructions[0].direct_deposit_account.bank_routing_id[1]")
|
|
32
|
+
bank_routing_id_swift_scheme_name: Optional[str] = Field(default=None, alias="payment_instructions[0].direct_deposit_account.bank_routing_id[1].scheme_name")
|
|
33
|
+
account_id: Optional[str] = Field(default=None, alias="payment_instructions[0].direct_deposit_account.account_id[0]")
|
|
34
|
+
iban: Optional[str] = Field(default=None, alias="payment_instructions[0].direct_deposit_account.iban")
|
|
35
|
+
account_country_code: Optional[str] = Field(default=None, alias="payment_instructions[0].direct_deposit_account.country_code[0]")
|
|
36
|
+
account_currency_code: Optional[str] = Field(default=None, alias="payment_instructions[0].direct_deposit_account.currency_code")
|
|
37
|
+
additional_account_id: Optional[str] = Field(default=None, alias="payment_instructions[0].direct_deposit_account.additional_account_id")
|
|
38
|
+
account_postal_code: Optional[str] = Field(default=None, alias="payment_instructions[0].direct_deposit_account.postal_code")
|
|
39
|
+
account_city_name: Optional[str] = Field(default=None, alias="payment_instructions[0].direct_deposit_account.city_name")
|
|
40
|
+
|
|
41
|
+
# Payment Instructions [1] (second instruction, e.g., OTHER)
|
|
42
|
+
payment2_valid_from: Optional[datetime.date] = Field(default=None, alias="payment_instructions[1].valid_from")
|
|
43
|
+
payment2_type: Optional[str] = Field(default=None, alias="payment_instructions[1].payment_type")
|
|
44
|
+
payment2_method: Optional[str] = Field(default=None, alias="payment_instructions[1].payment_method")
|
|
45
|
+
payment2_type_code: Optional[str] = Field(default=None, alias="payment_instructions[1].payment_type_code")
|
|
46
|
+
payment2_amount: Optional[str] = Field(default=None, alias="payment_instructions[1].amount")
|
|
47
|
+
name_on_account2: Optional[str] = Field(default=None, alias="payment_instructions[1].direct_deposit_account.name_on_account")
|
|
48
|
+
account_type_code_2: Optional[str] = Field(default=None, alias="payment_instructions[1].direct_deposit_account.type_code[0]")
|
|
49
|
+
bank_routing_id2: Optional[str] = Field(default=None, alias="payment_instructions[1].direct_deposit_account.bank_routing_id[0]")
|
|
50
|
+
bank_routing_id2_swift: Optional[str] = Field(default=None, alias="payment_instructions[1].direct_deposit_account.bank_routing_id[1]")
|
|
51
|
+
bank_routing_id2_swift_scheme_name: Optional[str] = Field(default=None, alias="payment_instructions[1].direct_deposit_account.bank_routing_id[1].scheme_name")
|
|
52
|
+
account_id2: Optional[str] = Field(default=None, alias="payment_instructions[1].direct_deposit_account.account_id[0]")
|
|
53
|
+
additional_account_id2: Optional[str] = Field(default=None, alias="payment_instructions[1].direct_deposit_account.additional_account_id")
|
|
54
|
+
iban2: Optional[str] = Field(default=None, alias="payment_instructions[1].direct_deposit_account.iban")
|
|
55
|
+
account_country_code2: Optional[str] = Field(default=None, alias="payment_instructions[1].direct_deposit_account.country_code[0]")
|
|
56
|
+
account_currency_code2: Optional[str] = Field(default=None, alias="payment_instructions[1].direct_deposit_account.currency_code")
|
|
57
|
+
|
|
58
|
+
# Cost Assignment [0]
|
|
59
|
+
cost_valid_from: Optional[datetime.date] = Field(default=None, alias="cost_assignment[0].valid_from")
|
|
60
|
+
cost_center_code: Optional[str] = Field(default=None, alias="cost_assignment[0].cost_center_code")
|
|
61
|
+
cost_center_name: Optional[str] = Field(default=None, alias="cost_assignment[0].cost_center_name")
|
|
62
|
+
percentage: Optional[int] = Field(default=None, alias="cost_assignment[0].percentage")
|
|
63
|
+
|
|
64
|
+
# Pay Scales (single)
|
|
65
|
+
pay_scales_valid_from: Optional[datetime.date] = Field(default=None, alias="pay_scales.valid_from")
|
|
66
|
+
pay_scale_type: Optional[str] = Field(default=None, alias="pay_scales.pay_scale_type")
|
|
67
|
+
pay_scale_group: Optional[str] = Field(default=None, alias="pay_scales.pay_scale_group")
|
|
68
|
+
pay_scale_level: Optional[str] = Field(default=None, alias="pay_scales.pay_scale_level")
|
|
69
|
+
|
|
70
|
+
# Date Specifications (indices)
|
|
71
|
+
date_active_status_type: Optional[str] = Field(default=None, alias="date_specifications.date[0].date_type")
|
|
72
|
+
date_active_status: Optional[datetime.date] = Field(default=None, alias="date_specifications.date[0].value")
|
|
73
|
+
date_hire_type: Optional[str] = Field(default=None, alias="date_specifications.date[1].date_type")
|
|
74
|
+
date_hire: Optional[datetime.date] = Field(default=None, alias="date_specifications.date[1].value")
|
|
75
|
+
date_continuous_service_type: Optional[str] = Field(default=None, alias="date_specifications.date[2].date_type")
|
|
76
|
+
date_continuous_service: Optional[datetime.date] = Field(default=None, alias="date_specifications.date[2].value")
|
|
77
|
+
date_seniority_type: Optional[str] = Field(default=None, alias="date_specifications.date[3].date_type")
|
|
78
|
+
date_seniority: Optional[datetime.date] = Field(default=None, alias="date_specifications.date[3].value")
|
|
79
|
+
date_benefits_service_type: Optional[str] = Field(default=None, alias="date_specifications.date[4].date_type")
|
|
80
|
+
date_benefits_service: Optional[datetime.date] = Field(default=None, alias="date_specifications.date[4].value")
|
|
81
|
+
date_company_service_type: Optional[str] = Field(default=None, alias="date_specifications.date[5].date_type")
|
|
82
|
+
date_company_service: Optional[datetime.date] = Field(default=None, alias="date_specifications.date[5].value")
|
|
83
|
+
date_first_day_type: Optional[str] = Field(default=None, alias="date_specifications.date[6].date_type")
|
|
84
|
+
date_first_day_of_work: Optional[datetime.date] = Field(default=None, alias="date_specifications.date[6].value")
|
|
85
|
+
|
|
86
|
+
# Approvers [0]
|
|
87
|
+
approver_valid_from: Optional[datetime.date] = Field(default=None, alias="approvers.approver[0].valid_from")
|
|
88
|
+
approver_value: Optional[str] = Field(default=None, alias="approvers.approver[0].value")
|
|
89
|
+
approver_type: Optional[str] = Field(default=None, alias="approvers.approver[0].type_value")
|
|
90
|
+
|
|
91
|
+
# Contract Elements [0]
|
|
92
|
+
contract_valid_from: Optional[datetime.date] = Field(default=None, alias="contract_elements[0].valid_from")
|
|
93
|
+
contract_type: Optional[str] = Field(default=None, alias="contract_elements[0].contract_type")
|
|
94
|
+
contract_start_date: Optional[datetime.date] = Field(default=None, alias="contract_elements[0].contract_start_date")
|
|
95
|
+
contract_end_date: Optional[datetime.date] = Field(default=None, alias="contract_elements[0].contract_end_date")
|
|
96
|
+
|
|
97
|
+
# Payroll Specific Groupings (single object)
|
|
98
|
+
psg_valid_from: Optional[datetime.date] = Field(default=None, alias="payroll_specific_groupings.valid_from")
|
|
99
|
+
psg1: Optional[str] = Field(default=None, alias="payroll_specific_groupings.payroll_specific_grouping1")
|
|
100
|
+
psg2: Optional[str] = Field(default=None, alias="payroll_specific_groupings.payroll_specific_grouping2")
|
|
101
|
+
psg3: Optional[str] = Field(default=None, alias="payroll_specific_groupings.payroll_specific_grouping3")
|
|
102
|
+
psg4: Optional[str] = Field(default=None, alias="payroll_specific_groupings.payroll_specific_grouping4")
|
|
103
|
+
psg5: Optional[str] = Field(default=None, alias="payroll_specific_groupings.payroll_specific_grouping5")
|
|
104
|
+
psg6: Optional[str] = Field(default=None, alias="payroll_specific_groupings.payroll_specific_grouping6")
|
|
105
|
+
psg7: Optional[str] = Field(default=None, alias="payroll_specific_groupings.payroll_specific_grouping7")
|
|
106
|
+
psg8: Optional[str] = Field(default=None, alias="payroll_specific_groupings.payroll_specific_grouping8")
|
|
107
|
+
psg9: Optional[str] = Field(default=None, alias="payroll_specific_groupings.payroll_specific_grouping9")
|
|
108
|
+
psg10: Optional[str] = Field(default=None, alias="payroll_specific_groupings.payroll_specific_grouping10")
|
|
109
|
+
|
|
110
|
+
# Alternate Identifiers
|
|
111
|
+
payroll_exchange_id: Optional[str] = Field(default=None, alias="alternate_identifiers.payroll_exchange_id")
|
|
112
|
+
alternate_id: Optional[str] = Field(default=None, alias="alternate_identifiers.alternate_id[0]")
|
|
113
|
+
alternate_id_type: Optional[str] = Field(default=None, alias="alternate_identifiers.alternate_id[0].type_value")
|
|
114
|
+
pay_serv_id: Optional[str] = Field(default=None, alias="alternate_identifiers.pay_serv_id")
|
|
115
|
+
prior_incorrect_pay_serv_id: Optional[str] = Field(default=None, alias="alternate_identifiers.prior_incorrect_pay_serv_id")
|
|
116
|
+
|
|
117
|
+
# Alternate Descriptions
|
|
118
|
+
alt_desc_valid_from: Optional[datetime.date] = Field(default=None, alias="alternate_descriptions.valid_from")
|
|
119
|
+
alt_desc_1: Optional[str] = Field(default=None, alias="alternate_descriptions.description[0]")
|
|
120
|
+
alt_desc_1_type: Optional[str] = Field(default=None, alias="alternate_descriptions.description[0].type_value")
|
|
121
|
+
alt_desc_2: Optional[str] = Field(default=None, alias="alternate_descriptions.description[1]")
|
|
122
|
+
alt_desc_2_type: Optional[str] = Field(default=None, alias="alternate_descriptions.description[1].type_value")
|
|
123
|
+
alt_desc_3: Optional[str] = Field(default=None, alias="alternate_descriptions.description[2]")
|
|
124
|
+
alt_desc_3_type: Optional[str] = Field(default=None, alias="alternate_descriptions.description[2].type_value")
|
|
125
|
+
|
|
126
|
+
# Time Elements
|
|
127
|
+
time_elements: Optional[Absences] = None
|
|
128
|
+
time_quotas: Optional[TimeQuotas] = None
|
|
129
|
+
|
|
130
|
+
def to_nested_dict(self) -> Dict[str, Any]:
|
|
131
|
+
flat = self.model_dump(exclude_none=True, by_alias=True)
|
|
132
|
+
nested: Dict[str, Any] = {}
|
|
133
|
+
for k, v in flat.items():
|
|
134
|
+
add_to_nested_path(nested, k, v)
|
|
135
|
+
# Merge time elements
|
|
136
|
+
if self.time_elements is not None:
|
|
137
|
+
te = self.time_elements.to_nested_dict()
|
|
138
|
+
if te:
|
|
139
|
+
# Wrap into container
|
|
140
|
+
nested.setdefault("pay_serv_emp_time_elements", {})
|
|
141
|
+
nested["pay_serv_emp_time_elements"].update({"time_element": te.get("time_element", [])})
|
|
142
|
+
# Merge time quotas
|
|
143
|
+
if self.time_quotas is not None:
|
|
144
|
+
tq = self.time_quotas.to_nested_dict()
|
|
145
|
+
if tq:
|
|
146
|
+
nested.setdefault("pay_serv_emp_time_quotas", {})
|
|
147
|
+
nested["pay_serv_emp_time_quotas"].update({"time_quota": tq.get("time_quota", [])})
|
|
148
|
+
post_process_nested_data(nested, XsdPayServEmpExtension)
|
|
149
|
+
return nested
|
|
150
|
+
|
|
151
|
+
def to_model(self) -> XsdPayServEmpExtension:
|
|
152
|
+
nested = self.to_nested_dict()
|
|
153
|
+
try:
|
|
154
|
+
return construct_model(XsdPayServEmpExtension, nested)
|
|
155
|
+
except Exception:
|
|
156
|
+
return XsdPayServEmpExtension.model_validate(nested)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class PayElementCreate(BaseModel):
|
|
160
|
+
"""
|
|
161
|
+
Alias-driven flat model for a single PayElement item.
|
|
162
|
+
"""
|
|
163
|
+
model_config = {
|
|
164
|
+
"populate_by_name": True
|
|
165
|
+
}
|
|
166
|
+
valid_from: Optional[datetime.date] = Field(default=None, alias="valid_from")
|
|
167
|
+
id: Optional[str] = Field(default=None, alias="id[0].value")
|
|
168
|
+
pay_element_type: Optional[str] = Field(default=None, alias="pay_element_type.value")
|
|
169
|
+
amount: Optional[str] = Field(default=None, alias="amount.value")
|
|
170
|
+
currency_code: Optional[str] = Field(default=None, alias="currency_code.value")
|
|
171
|
+
rate: Optional[str] = Field(default=None, alias="rate.value")
|
|
172
|
+
units: Optional[str] = Field(default=None, alias="units.value")
|
|
173
|
+
unit_type: Optional[str] = Field(default=None, alias="unit_type.value")
|
|
174
|
+
reference_number: Optional[str] = Field(default=None, alias="reference_number.value")
|
|
175
|
+
cost_center_code: Optional[str] = Field(default=None, alias="cost_center_code.value")
|
|
176
|
+
end_date: Optional[datetime.date] = Field(default=None, alias="end_date.value")
|
|
177
|
+
premium_id: Optional[str] = Field(default=None, alias="premium_id.value")
|
|
178
|
+
different_valuation: Optional[str] = Field(default=None, alias="different_valuation.value")
|
|
179
|
+
off_cycle_indicator: Optional[bool] = Field(default=None, alias="off_cycle_indicator.value")
|
|
180
|
+
|
|
181
|
+
def to_nested_dict(self) -> Dict[str, Any]:
|
|
182
|
+
flat = self.model_dump(exclude_none=True, by_alias=True)
|
|
183
|
+
nested: Dict[str, Any] = {}
|
|
184
|
+
for k, v in flat.items():
|
|
185
|
+
add_to_nested_path(nested, k, v)
|
|
186
|
+
# Ensure required wrappers and types explicitly (schema nuances)
|
|
187
|
+
# id must be a list of wrapper dicts
|
|
188
|
+
if "id" in nested:
|
|
189
|
+
if isinstance(nested["id"], list):
|
|
190
|
+
nested["id"] = [item if isinstance(item, dict) and "value" in item else {"value": item} for item in nested["id"]]
|
|
191
|
+
else:
|
|
192
|
+
nested["id"] = [{"value": nested["id"]}]
|
|
193
|
+
# Wrap simple fields (only those not already aliased as .value)
|
|
194
|
+
for key in ("pay_element_type", "amount", "currency_code"):
|
|
195
|
+
if key in nested and not (isinstance(nested[key], dict) and "value" in nested[key]):
|
|
196
|
+
nested[key] = {"value": nested[key]}
|
|
197
|
+
# Convert dates
|
|
198
|
+
if "valid_from" in nested and isinstance(nested["valid_from"], (datetime.date, datetime.datetime)):
|
|
199
|
+
nested["valid_from"] = convert_datetime_to_xml(nested["valid_from"], None)
|
|
200
|
+
if "end_date" in nested and isinstance(nested["end_date"], dict) and "value" in nested["end_date"]:
|
|
201
|
+
inner = nested["end_date"]["value"]
|
|
202
|
+
if isinstance(inner, (datetime.date, datetime.datetime)):
|
|
203
|
+
nested["end_date"]["value"] = convert_datetime_to_xml(inner, None)
|
|
204
|
+
# Final pass through schema container to catch any remaining wrappers
|
|
205
|
+
container = {"pay_element": [nested]}
|
|
206
|
+
post_process_nested_data(container, XsdPayServEmpPayElements)
|
|
207
|
+
return container["pay_element"][0]
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Flat, user-friendly salary model for Alight SDK.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import datetime
|
|
6
|
+
from typing import Optional, Dict, Any
|
|
7
|
+
from pydantic import Field, BaseModel
|
|
8
|
+
|
|
9
|
+
from .utils import add_to_nested_path # not used directly; kept for parity if needed
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Salary(BaseModel):
|
|
13
|
+
"""
|
|
14
|
+
Simplified salary/compensation model.
|
|
15
|
+
Uses PURE schema-driven conversion - NO hardcoded structure mappings.
|
|
16
|
+
Uses aliases to match expected field names in Employee model.
|
|
17
|
+
"""
|
|
18
|
+
model_config = {
|
|
19
|
+
"populate_by_name": True # Allow populating by field name (base_salary) in addition to alias (pay_amount)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
base_salary: float = Field(
|
|
23
|
+
description="Base salary amount",
|
|
24
|
+
alias="indicative_person_dossier.pay_cycle_remuneration.remuneration.amount.value"
|
|
25
|
+
)
|
|
26
|
+
currency_code: str = Field(
|
|
27
|
+
default="USD",
|
|
28
|
+
description="Currency code (USD/GBP/EUR)",
|
|
29
|
+
alias="indicative_person_dossier.pay_cycle_remuneration.remuneration.amount.currency_code"
|
|
30
|
+
)
|
|
31
|
+
pay_frequency: Optional[str] = Field(
|
|
32
|
+
default="Monthly",
|
|
33
|
+
description="Monthly/Weekly/Hourly",
|
|
34
|
+
alias="indicative_person_dossier.pay_cycle_remuneration.pay_cycle_interval_code"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Pay Elements
|
|
38
|
+
element_code: Optional[str] = Field(
|
|
39
|
+
default="0010",
|
|
40
|
+
description="Pay element code",
|
|
41
|
+
alias="indicative_person_dossier.pay_cycle_remuneration.remuneration.pay_element.id"
|
|
42
|
+
)
|
|
43
|
+
element_type: Optional[str] = Field(
|
|
44
|
+
default="RECURRING",
|
|
45
|
+
description="RECURRING/BONUS/etc.",
|
|
46
|
+
alias="indicative_person_dossier.pay_cycle_remuneration.remuneration.pay_element.type_code"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Dates
|
|
50
|
+
valid_from: Optional[datetime.date] = Field(
|
|
51
|
+
default=None,
|
|
52
|
+
description="Valid from date",
|
|
53
|
+
alias="indicative_person_dossier.pay_cycle_remuneration.valid_from"
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
def to_nested_dict(self) -> Dict[str, Any]:
|
|
57
|
+
"""
|
|
58
|
+
Convert salary data to format suitable for pay elements in the HR-XML.
|
|
59
|
+
Using aliases for direct mapping to employee fields.
|
|
60
|
+
"""
|
|
61
|
+
data = self.model_dump(exclude_none=True, by_alias=True)
|
|
62
|
+
|
|
63
|
+
# Ensure amount is a string for XML compatibility
|
|
64
|
+
if 'pay_amount' in data and isinstance(data['pay_amount'], (int, float)):
|
|
65
|
+
data['pay_amount'] = str(data['pay_amount'])
|
|
66
|
+
|
|
67
|
+
return data
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Flat, user-friendly termination model for Alight SDK.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import datetime
|
|
6
|
+
from typing import Optional, Dict, Any
|
|
7
|
+
from pydantic import Field, BaseModel
|
|
8
|
+
|
|
9
|
+
from .utils import add_to_nested_path # not used here
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Termination(BaseModel):
|
|
13
|
+
"""
|
|
14
|
+
Simplified termination model.
|
|
15
|
+
Maps to IndicativeEmployment.employment_lifecycle.termination.
|
|
16
|
+
"""
|
|
17
|
+
model_config = {
|
|
18
|
+
"populate_by_name": True
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
voluntary_termination_indicator: Optional[bool] = Field(
|
|
22
|
+
default=None,
|
|
23
|
+
description="Voluntary termination indicator",
|
|
24
|
+
alias="indicative_person_dossier.indicative_employment.employment_lifecycle.termination.voluntary_termination_indicator"
|
|
25
|
+
)
|
|
26
|
+
termination_reason_code: Optional[str] = Field(
|
|
27
|
+
default=None,
|
|
28
|
+
description="Reason for termination",
|
|
29
|
+
alias="indicative_person_dossier.indicative_employment.employment_lifecycle.termination.termination_reason_code"
|
|
30
|
+
)
|
|
31
|
+
termination_date: Optional[datetime.date] = Field(
|
|
32
|
+
default=None,
|
|
33
|
+
description="Termination date",
|
|
34
|
+
alias="indicative_person_dossier.indicative_employment.employment_lifecycle.termination.termination_date"
|
|
35
|
+
)
|
|
36
|
+
last_worked_date: Optional[datetime.date] = Field(
|
|
37
|
+
default=None,
|
|
38
|
+
description="Last worked date",
|
|
39
|
+
alias="indicative_person_dossier.indicative_employment.employment_lifecycle.termination.last_worked_date"
|
|
40
|
+
)
|
|
41
|
+
last_paid_date: Optional[datetime.date] = Field(
|
|
42
|
+
default=None,
|
|
43
|
+
description="Last paid date",
|
|
44
|
+
alias="indicative_person_dossier.indicative_employment.employment_lifecycle.termination.last_paid_date"
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
def to_nested_dict(self) -> Dict[str, Any]:
|
|
48
|
+
return self.model_dump(exclude_none=True, by_alias=True)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Flat, user-friendly time quota model for Alight SDK.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import datetime
|
|
6
|
+
from typing import Optional, Dict, Any, List
|
|
7
|
+
from pydantic import Field, BaseModel
|
|
8
|
+
|
|
9
|
+
from .utils import add_to_nested_path, convert_datetime_to_xml
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TimeQuota(BaseModel):
|
|
13
|
+
"""
|
|
14
|
+
Maps to PayServEmpTimeQuotas.time_quota[0].
|
|
15
|
+
"""
|
|
16
|
+
model_config = {"populate_by_name": True}
|
|
17
|
+
|
|
18
|
+
id: Optional[str] = Field(default=None, alias="time_quota[0].id[0].value")
|
|
19
|
+
units: Optional[str] = Field(default=None, alias="time_quota[0].units")
|
|
20
|
+
units_taken: Optional[str] = Field(default=None, alias="time_quota[0].units_taken")
|
|
21
|
+
units_remaining: Optional[str] = Field(default=None, alias="time_quota[0].units_remaining")
|
|
22
|
+
unit_type: Optional[str] = Field(default=None, alias="time_quota[0].unit_type")
|
|
23
|
+
accrued_to_date: Optional[str] = Field(default=None, alias="time_quota[0].accrued_to_date")
|
|
24
|
+
deduction_start: Optional[datetime.date] = Field(default=None, alias="time_quota[0].deduction_start")
|
|
25
|
+
deduction_end: Optional[datetime.date] = Field(default=None, alias="time_quota[0].deduction_end")
|
|
26
|
+
valid_from: Optional[datetime.date] = Field(default=None, alias="time_quota[0].valid_from")
|
|
27
|
+
valid_to: Optional[datetime.date] = Field(default=None, alias="time_quota[0].valid_to")
|
|
28
|
+
|
|
29
|
+
def to_nested_dict(self) -> Dict[str, Any]:
|
|
30
|
+
flat = self.model_dump(exclude_none=True, by_alias=True)
|
|
31
|
+
nested: Dict[str, Any] = {}
|
|
32
|
+
for k, v in flat.items():
|
|
33
|
+
add_to_nested_path(nested, k, v)
|
|
34
|
+
# Convert date/period values to XML-compatible
|
|
35
|
+
for key in ("valid_from", "valid_to", "deduction_start", "deduction_end"):
|
|
36
|
+
node = nested
|
|
37
|
+
parts = key.split(".")
|
|
38
|
+
if key in nested and isinstance(nested[key], (datetime.date, datetime.datetime)):
|
|
39
|
+
nested[key] = convert_datetime_to_xml(nested[key], None)
|
|
40
|
+
return nested
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class TimeQuotas(BaseModel):
|
|
44
|
+
"""
|
|
45
|
+
Wrapper for multiple TimeQuota items mapping to time_quota[*].
|
|
46
|
+
"""
|
|
47
|
+
time_quotas: Optional[List[TimeQuota]] = Field(default=None, description="List of time quota items")
|
|
48
|
+
|
|
49
|
+
def to_nested_dict(self) -> Dict[str, Any]:
|
|
50
|
+
nested: Dict[str, Any] = {}
|
|
51
|
+
if not self.time_quotas:
|
|
52
|
+
return nested
|
|
53
|
+
items: List[Dict[str, Any]] = []
|
|
54
|
+
for idx, item in enumerate(self.time_quotas):
|
|
55
|
+
data = item.to_nested_dict()
|
|
56
|
+
remapped: Dict[str, Any] = {}
|
|
57
|
+
for k, v in data.items():
|
|
58
|
+
remapped[k.replace("time_quota[0]", f"time_quota[{idx}]")] = v
|
|
59
|
+
item_nested: Dict[str, Any] = {}
|
|
60
|
+
for k, v in remapped.items():
|
|
61
|
+
add_to_nested_path(item_nested, k, v)
|
|
62
|
+
if "time_quota" in item_nested and isinstance(item_nested["time_quota"], list):
|
|
63
|
+
items.extend(item_nested["time_quota"])
|
|
64
|
+
if items:
|
|
65
|
+
nested["time_quota"] = items
|
|
66
|
+
return nested
|