Api reference
components.employment.public.api ¶
cancel ¶
Sets the employment to cancelled.
Source code in components/employment/public/api.py
employment_component_context ¶
A decorator to set a context variable indicating that an employment component function is running. This is useful to highlight updates of the legacy Employment table outside of the usage of the Employment Component which will help us finish the migration to the Employment Component.
Source code in components/employment/public/api.py
ingest_employment_declaration ¶
ingest_employment_declaration(
employment_declaration,
source_information,
commit,
event_bus_orchestrator=None,
retried_blocked_movement=None,
upstream_retried_blocked_movement=None,
source_rules_override=None,
)
Ingests the given employment declarations, notifies the consumers, and executes side effects.
Source code in components/employment/public/api.py
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 | |
ingest_employment_declaration_without_blocked_movement ¶
ingest_employment_declaration_without_blocked_movement(
employment_declaration,
source_information,
commit,
event_bus_orchestrator=None,
source_rules_override=None,
)
Ingests the given employment declarations, notifies the consumers, and executes side effects.
Source code in components/employment/public/api.py
is_running_employment_component
module-attribute
¶
resume ¶
resume(
employment_id,
source_type,
source_information,
commit,
extended_information=None,
event_bus_orchestrator=None,
)
Resumes an ended employment.
Source code in components/employment/public/api.py
set_extended_employment_values ¶
set_extended_employment_values(
employment_id,
values,
validity_period,
source_type,
source_information,
commit,
event_bus_orchestrator=None,
)
Create a new ExtendedEmploymentUpdate with the given values for the employment with the given id.
The update will contain only the values passed as argument, the other values will remain unchanged. Doc: https://www.notion.so/alaninsurance/Definitions-employments-sources-etc-1301426e8be780cc9796ee31f49559e5?pvs=4#1301426e8be78052977ff4fbb932c8f7 ⧉
Source code in components/employment/public/api.py
set_external_employee_id ¶
set_external_employee_id(
employment_id,
new_external_employee_id,
source_type,
source_information,
commit,
event_bus_orchestrator=None,
)
Updates the external employee id of the employment with the given id. WARNING: This function does not check if the external employee id is valid according to local country rules. Please do that check upstream.
Source code in components/employment/public/api.py
terminate_or_update_termination ¶
terminate_or_update_termination(
employment_id,
end_date,
extended_information,
source_type,
source_information,
commit,
event_bus_orchestrator=None,
)
Source code in components/employment/public/api.py
transfer ¶
transfer(
current_employment_id,
new_employment_declaration,
source_information,
commit,
event_bus_orchestrator=None,
)
Source code in components/employment/public/api.py
uncancel ¶
Undo the cancellation of the employment.
Source code in components/employment/public/api.py
update_start_date ¶
update_start_date(
employment_id,
new_start_date,
source_type,
source_information,
commit,
event_bus_orchestrator=None,
)
Source code in components/employment/public/api.py
components.employment.public.business_logic ¶
actions ¶
blocked_movement ¶
amend_core_blocked_movement_note ¶
Appends the provided note to the end of the core blocked movement's current note.
Source code in components/employment/public/business_logic/actions/blocked_movement.py
amend_upstream_blocked_movement_note ¶
Appends the provided note to the end of the upstream blocked movement's current note.
Source code in components/employment/public/business_logic/actions/blocked_movement.py
automatically_cancel_pending_core_blocked_movement ¶
Automatically cancel a core blocked movement.
This should only be used to automatically cancel a blocked movement immediately after its creation.
Otherwise: - If the cancellation is a result of a manual, human action, use manually_cancel_core_blocked_movement instead. - If the cancellation is part of an async/automated process, use mark_...as_self_healing as soon as possible, then cancel_self_healing..._blocked_movement
Source code in components/employment/public/business_logic/actions/blocked_movement.py
automatically_cancel_pending_upstream_blocked_movement ¶
Automatically cancel an upstream blocked movement.
This should only be used to automatically cancel a blocked movement immediately after its creation.
Otherwise: - If the cancellation is a result of a manual, human action, use manually_cancel_upstream_blocked_movement instead. - If the cancellation is part of an async/automated process, use mark_...as_self_healing as soon as possible, then cancel_self_healing..._blocked_movement
Source code in components/employment/public/business_logic/actions/blocked_movement.py
cancel_pending_blocked_movement ¶
Cancels a pending blocked movement by its ID. It'll manage indifferently if it's an upstream or core blocked movement.
If blocked movement is not found or is not in the 'pending' status, an error will be raised
Source code in components/employment/public/business_logic/actions/blocked_movement.py
cancel_self_healing_core_blocked_movement ¶
Cancels a core blocked movement which you previously took ownership of via
mark_pending_core_blocked_movement_as_self_healing.
Source code in components/employment/public/business_logic/actions/blocked_movement.py
cancel_self_healing_upstream_blocked_movement ¶
Cancels an upstream blocked movement which you previously took ownership of via
mark_pending_upstream_blocked_movement_as_self_healing.
Source code in components/employment/public/business_logic/actions/blocked_movement.py
manually_cancel_core_blocked_movement ¶
Cancel a core blocked movement as a result of a manual, human action. The blocked movement may be pending or awaiting_user_response.
To automatically cancel a blocked movement as a result of automated action, mark the blocked movement as self
healing as early as possible (via mark_pending_core_blocked_movement_as_self_healing), then cancel it
using cancel_self_healing_core_blocked_movement when needed.
Source code in components/employment/public/business_logic/actions/blocked_movement.py
manually_cancel_upstream_blocked_movement ¶
Cancel an upstream blocked movement as a result of a manual, human action. The blocked movement may be pending or awaiting_user_response.
To automatically cancel a blocked movement as a result of automated action, mark the blocked movement as self
healing as early as possible (via mark_pending_upstream_blocked_movement_as_self_healing), then cancel it
using cancel_self_healing_upstream_blocked_movement when needed.
Source code in components/employment/public/business_logic/actions/blocked_movement.py
mark_pending_core_blocked_movement_as_self_healing ¶
Mark a core blocked movement as self healing. By using this, you signal to the Employment Component that a custom local process will take care of the blocked movement from now on.
To "end" a blocked movement you take ownership of via this function, use:
cancel_self_healing_core_blocked_movementto cancel it (automatically_cancelled)resolve_self_healing_core_blocked_movementto resolve it (automatically_resolved)
Source code in components/employment/public/business_logic/actions/blocked_movement.py
mark_pending_or_awaiting_user_response_core_blocked_movement_as_self_healing ¶
mark_pending_or_awaiting_user_response_core_blocked_movement_as_self_healing(
core_blocked_movement_id, commit
)
Mark a core blocked movement as self healing. This is a variant of mark_pending_core_blocked_movement_as_self_healing you can use in case the blocked movement may have been marked as "awaiting_user_response" by Ops. Typical use cases include:
- Automatically moving the to a self-healing resolution process
- An Ops taking a blocked movement (marking it as awaiting_user_response) then manually putting it back to a self-healing resolution process.
By using this, you signal to the Employment Component that a custom local process will take care of the blocked movement from now on.
To "end" a blocked movement you take ownership of via this function, use:
cancel_self_healing_core_blocked_movementto cancel it (automatically_cancelled)resolve_self_healing_core_blocked_movementto resolve it (automatically_resolved)
Source code in components/employment/public/business_logic/actions/blocked_movement.py
mark_pending_or_awaiting_user_response_upstream_blocked_movement_as_self_healing ¶
mark_pending_or_awaiting_user_response_upstream_blocked_movement_as_self_healing(
upstream_blocked_movement_id, commit
)
Mark a upstream blocked movement as self healing. This is a variant of mark_pending_upstream_blocked_movement_as_self_healing you can use in case the blocked movement may have been marked as "awaiting_user_response" by Ops. Typical use cases include:
- Automatically moving the to a self-healing resolution process
- An Ops contacting admin or member about a blocked movement (marking it as awaiting_user_response) then manually putting it back to a self-healing resolution process.
By using this, you signal to the Employment Component that a custom local process will take care of the blocked movement from now on.
To "end" a blocked movement you take ownership of via this function, use:
cancel_self_healing_upstream_blocked_movementto cancel it (automatically_cancelled)resolve_self_healing_upstream_blocked_movementto resolve it (automatically_resolved)
Source code in components/employment/public/business_logic/actions/blocked_movement.py
mark_pending_self_healing_core_blocked_movement_as_awaiting_user_response_self_healing ¶
mark_pending_self_healing_core_blocked_movement_as_awaiting_user_response_self_healing(
core_blocked_movement_id, commit
)
Mark a core blocked movement you previously took ownership of via
mark_pending_core_blocked_movement_as_self_healing as awaiting user response,
but still under the "self healing" process.
This is useful if you need to contact the user/admin about the blocked movement, but you still want to keep ownership of the blocked movement.
awaiting_user_response_self_healing is considered as a terminal status in SLA computation.
By using this, you signal to the Employment Component that a custom local process still takes care of the blocked movement. Typically, this blocked movement will not be automatically retried, and won't be displayed by default in the Ops tool.
To "end" a blocked movement you took ownership of, use:
- cancel_self_healing_core_blocked_movement to cancel it (automatically_cancelled)
- resolve_self_healing_core_blocked_movement to resolve it (automatically_resolved)
Source code in components/employment/public/business_logic/actions/blocked_movement.py
mark_pending_upstream_blocked_movement_as_self_healing ¶
Mark an upstream blocked movement as self healing. By using this, you signal to the Employment Component that a custom local process will take care of the blocked movement from now on.
To "end" a blocked movement you take ownership of via this function, use:
cancel_self_healing_upstream_blocked_movementto cancel it (automatically_cancelled)resolve_self_healing_upstream_blocked_movementto resolve it (automatically_resolved)
Source code in components/employment/public/business_logic/actions/blocked_movement.py
resolve_self_healing_core_blocked_movement ¶
Resolves a core blocked movement which you previously took ownership of via
mark_pending_core_blocked_movement_as_self_healing.
Source code in components/employment/public/business_logic/actions/blocked_movement.py
resolve_self_healing_upstream_blocked_movement ¶
Resolves an upstream blocked movement which you previously took ownership of via
mark_pending_upstream_blocked_movement_as_self_healing.
Source code in components/employment/public/business_logic/actions/blocked_movement.py
retry_core_blocked_movement ¶
retry_core_blocked_movement(
blocked_movement_id,
*,
employment_declaration_override=None,
source_rules_override=None,
commit=False
)
Retry a core blocked movement
Retries a core blocked movement, using the provided overrides.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
blocked_movement_id
|
UUID
|
The ID of the core blocked movement to retry |
required |
employment_declaration_override
|
EmploymentDeclaration | None
|
If set, will be used instead of the blocked movement's declaration. Defaults to None. |
None
|
source_rules_override
|
SourceRules | None
|
If set, will be used instead of the blocked movement's original source type's source rules. Defaults to None. |
None
|
commit
|
bool
|
True will commit (incl. executing side effects), False will dry-run. Defaults to False. |
False
|
Source code in components/employment/public/business_logic/actions/blocked_movement.py
retry_upstream_blocked_movement ¶
retry_upstream_blocked_movement(
upstream_blocked_movement_id,
*,
upstream_data_override=None,
commit=False
)
Retries an upstream blocked movement
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
upstream_blocked_movement_id
|
UUID
|
The ID of the blocked movement to retry |
required |
upstream_data_override
|
Optional[dict[str, Any]]
|
If set, values present in this dict will override those present in the upstream blocked movement's |
None
|
commit
|
bool
|
True will commit (incl. executing side effects), False will dry-run. Defaults to False. |
False
|
Source code in components/employment/public/business_logic/actions/blocked_movement.py
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 | |
delete_user ¶
delete_user_in_employment_component ¶
Support function for the "delete user" procedure. Delete all employments (core and extended) that target user and related data (blocked movements and source data).
Note that this will NOT be notified to consumers.
Source code in components/employment/public/business_logic/actions/delete_user.py
employment_source_data ¶
find_similar_source_data_and_mark_as_duplicate ¶
find_similar_source_data_and_mark_as_duplicate(
source_type,
user_identifier_field_name,
company_identifier_field_name,
start_date_field_name,
field_names_to_compare,
raw_data_to_compare,
commit,
)
Looks at the latest EmploymentSourceData with the same source type and identifier fields.
If the values are the same as raw_data_to_compare for all fields in field_names_to_compare,
it updates the source's metadata with last_received_at=utcnow() and returns its ID.
Otherwise, it returns None.
Note: if an identifier field is not present in raw_data_to_compare,
it will only consider EmploymentSourceData that do not have this field in their raw_data.
param field_names_to_compare: list of fields from raw_data that will need to be equal to be considered as similar
param raw_data_to_compare: new raw data dict for which we want to look for existing similar data
Source code in components/employment/public/business_logic/actions/employment_source_data.py
run_rollout_initialisation ¶
For some sources (most likely automated one), when activating it for a company, we don't want to process ALL past data (because of the high risk of data inconsistencies that can be too costly to fix).
Instead, we want to start processing data from the moment the source is activated.
To do so, we need to create a new EmploymentSourceDataModel with the source_information provided and rely on the "source deduplication" mechanism (see find_similar_source_data_and_mark_as_duplicate above and doc: https://www.notion.so/alaninsurance/Source-Deduplication-37060a0d1c884c1b970aa6b2a4600ea4?pvs=26&qid=1%3Ac0d72661-8c33-41aa-9b99-25d9fd8203ee%3A5 ⧉)
We use the rollout_initialisation metadata key to mark the source as "initialised" (to help excluded those when needed)
These sources are excluded from SLA computations.
Source code in components/employment/public/business_logic/actions/employment_source_data.py
update_employment_source_data_metadata_with ¶
Update the metadata stored in the DB using the provided update_dict. Each value in the update_dict will update the existing value for the given key. Keys not present in update_dict will not be changed.
Source code in components/employment/public/business_logic/actions/employment_source_data.py
merge_users ¶
merge_users_in_employment_component ¶
Support function for the "merge user" procedure: change all employments that target user merge_from so that they
target user merge_into instead.
This will change ALL employments for the user, including cancelled ones.
Note that this will NOT be notified to consumers.
⚠️ Blocked movements will NOT be retargeted!
If logs is not None, strings describing the actions will be appended to it
Source code in components/employment/public/business_logic/actions/merge_users.py
source_information ¶
update_source_information_metadata_with ¶
Update the provided source_information's metadata in place using the provided update_dict.
Never commits, even if the underlying source_information is a persisted DB model.
Source code in components/employment/public/business_logic/actions/source_information.py
upstream_blocked_movement_creator ¶
UpstreamBlockedMovementCreator ¶
UpstreamBlockedMovementCreator(
commit,
source,
upstream_data,
source_information,
upstream_retried_blocked_movement=None,
**unexpected_error_kwargs
)
Context manager that catch exceptions and create an upstream blocked movement if needed
upstream_data: data used to decide if we should create a new blocked movement or not Basically, if a new movement is failing with the same error and the same upstream_data, we won't create a new blocked movement
Source code in components/employment/public/business_logic/actions/upstream_blocked_movement_creator.py
__enter__ ¶
__exit__ ¶
Source code in components/employment/public/business_logic/actions/upstream_blocked_movement_creator.py
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | |
employment_source_data
instance-attribute
¶
If created_blocked_movement is True (i.e. an upstream blocked movement was created because the block inside this creator was unsuccessful), employment_source_data will be set to the corresponding EmploymentSourceData.
If created_blocked_movement is False (i.e. the block inside this creator executed without raising), employment_source_data will be None.
retried_blocked_movement
instance-attribute
¶
queries ¶
blocked_movement ¶
get_core_blocked_movement_or_none ¶
Get a core blocked movement by its ID.
Source code in components/employment/public/business_logic/queries/blocked_movement.py
get_pending_blocked_movements_for_company_id ¶
Gets all pending blocked movements for the provided company ID. The intended usage for this function is to retrieve blocked movements for company admins (both displaying them and acting upon them).
This function specifically returns only 'pending' blocked movements (i.e. with the 'pending' status), but not all active blocked movements. This is intentional: all other statuses indicate that the blocked movement is currently being handled, either manually (e.g. 'awaiting_user_response' status) or by some automated process (e.g. 'pending_self_healing'), as it is assumed that we do not want to provide actionability to admins on these blocked movements.
Note: upstream blocked movements must have a proper company_id value set in order to be returned by this function.
The blocked movements are returned in an arbitrary order.
Source code in components/employment/public/business_logic/queries/blocked_movement.py
get_upstream_blocked_movement_or_none ¶
Get an upstream blocked movement by its ID.
Source code in components/employment/public/business_logic/queries/blocked_movement.py
get_upstream_or_core_blocked_movement_or_none ¶
Get an upstream or core blocked movement by its ID.
Source code in components/employment/public/business_logic/queries/blocked_movement.py
core_employment_version ¶
get_all_latest_core_employment_versions_on ¶
Like get_latest_core_employment_version_on, but supports multiple users.
Source code in components/employment/public/business_logic/queries/core_employment_version.py
get_all_latest_core_employment_versions_overlapping ¶
Like get_latest_core_employment_versions_overlapping, but for multiple users.
Source code in components/employment/public/business_logic/queries/core_employment_version.py
get_core_employments_for_company ¶
Return the core employments for all employees of a company, using their latest version.
Source code in components/employment/public/business_logic/queries/core_employment_version.py
get_core_employments_for_external_employee_id_in_company_overlapping ¶
get_core_employments_for_external_employee_id_in_company_overlapping(
external_employee_id, company_id, start_date, end_date
)
Source code in components/employment/public/business_logic/queries/core_employment_version.py
get_core_employments_for_user ¶
Source code in components/employment/public/business_logic/queries/core_employment_version.py
get_core_employments_for_user_company ¶
Source code in components/employment/public/business_logic/queries/core_employment_version.py
get_latest_cancelled_core_employment_versions_overlapping ¶
get_latest_cancelled_core_employment_versions_overlapping(
user_id, company_id, start_date, end_date
)
Source code in components/employment/public/business_logic/queries/core_employment_version.py
get_latest_core_employment_version_on ¶
Source code in components/employment/public/business_logic/queries/core_employment_version.py
get_latest_core_employment_versions_overlapping ¶
Source code in components/employment/public/business_logic/queries/core_employment_version.py
get_latest_version_for_employment_or_raise ¶
Source code in components/employment/public/business_logic/queries/core_employment_version.py
country_helpers ¶
fr ¶
get_all_employment_source_data_for_bulk_action_report ¶
FR-specific DB helper: retrieves all Employment Source Data objects that we need to send bulk action reports.
Source code in components/employment/public/business_logic/queries/country_helpers/fr.py
get_blocked_movements_for_dsn_removal_suggestions ¶
Returns a list of blocked movements that should be considered for DSN removal suggestions. If multiple blocked movements exist for the same user and company, only the one with the latest end date is returned. This is to avoid a weird experience for the admin where they'd see multiple suggestions for the same user.
Source code in components/employment/public/business_logic/queries/country_helpers/fr.py
get_dsn_removal_suggestion_blocked_movements_to_cancel ¶
When getting the blocked movements for DSN removal suggestions, we only want to keep the latest one. (This is done in the get_blocked_movements_for_dsn_removal_suggestions function above.) However, we need to cancel ALL the suggestion blocked movements, because we don't want to leave them in a pending_self_healing state.
Source code in components/employment/public/business_logic/queries/country_helpers/fr.py
get_employment_source_data_extra_fields_for_company ¶
get_employment_source_data_extra_fields_for_company(
company_id,
keys,
on_date,
raw_data_additional_filters=None,
)
Get values for the specified keys from EmploymentSourceData.raw_data["extra"] for all active employees in company.
This has been built for Finance integration "Flux Retour"
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
company_id
|
str
|
Company ID to filter by |
required |
keys
|
list[str]
|
List of keys to extract from raw_data["extra"] |
required |
on_date
|
date
|
Date to check for active employments |
required |
raw_data_additional_filters
|
dict[str, Any] | None
|
Additional filters to apply on raw_data |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, dict[str, Any]]
|
Dictionary mapping user_id to a dictionary of key-value pairs from raw_data["extra"]. |
dict[str, dict[str, Any]]
|
Only keys that exist in the data are included. |
dict[str, dict[str, Any]]
|
If the keys are present in several EmploymentSourceData entries for the same user, |
dict[str, dict[str, Any]]
|
the returned values are the initial ones (first received). |
Source code in components/employment/public/business_logic/queries/country_helpers/fr.py
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | |
employment_source_data ¶
get_employment_metadata_value ¶
Get the value of the provided metadata key for the employment source data with the provided ID.
Source code in components/employment/public/business_logic/queries/employment_source_data.py
get_employment_source_data_from_id ¶
Get an EmploymentSourceData object from its ID.
Source code in components/employment/public/business_logic/queries/employment_source_data.py
get_employment_source_data_from_workflow_id ¶
Get all EmploymentSourceData objects from a workflow.
Source code in components/employment/public/business_logic/queries/employment_source_data.py
extended_employment_update ¶
get_employment_values_on ¶
Source code in components/employment/public/business_logic/queries/extended_employment_update.py
source_information ¶
get_metadata_from_source_information_like ¶
Retrieve the metadata dictionary from a SourceInformationLike object.
Must not be used for updating the metadata, should only be used for reading the metadata! If you want to update
the metadata, use update_employment_source_data_metadata_with or update_source_information_metadata_with
instead.
Source code in components/employment/public/business_logic/queries/source_information.py
stale_invitations ¶
get_stale_invitations ¶
Retrieves stale invitations for the given company IDs, optionally filtering by creation date.
Source code in components/employment/public/business_logic/queries/stale_invitations.py
rules ¶
blocked_movements ¶
make_error_message_from_integrity_error ¶
Format an integrity error in a meaningful message to be used in blocked movements.
It doesn't contain the IDs of objects because the error message is used for deduplication of blocked movements.
Source code in components/employment/public/business_logic/rules/blocked_movements.py
employment_input_error_info ¶
EmploymentInputErrorCode ¶
Bases: AlanBaseEnum
Generic and global error codes for Employment Component upstreams, especially for extractors
company_is_not_authorized
class-attribute
instance-attribute
¶
has_reimbursed_care_acts
class-attribute
instance-attribute
¶
invalid_external_employee_id
class-attribute
instance-attribute
¶
invalid_hiring_date
class-attribute
instance-attribute
¶
invalid_identity_document_type
class-attribute
instance-attribute
¶
invalid_is_alsace_moselle
class-attribute
instance-attribute
¶
invalid_is_unpaid_leave
class-attribute
instance-attribute
¶
invalid_passport_number
class-attribute
instance-attribute
¶
invalid_professional_category
class-attribute
instance-attribute
¶
invalid_termination_reason
class-attribute
instance-attribute
¶
invalid_unpaid_leave_end_date
class-attribute
instance-attribute
¶
mandatory_termination_type
class-attribute
instance-attribute
¶
missing_hiring_date
class-attribute
instance-attribute
¶
missing_required_birth_date
class-attribute
instance-attribute
¶
missing_required_email
class-attribute
instance-attribute
¶
missing_required_external_employee_id
class-attribute
instance-attribute
¶
missing_required_gender
class-attribute
instance-attribute
¶
missing_required_identity_document_type
class-attribute
instance-attribute
¶
missing_required_nif
class-attribute
instance-attribute
¶
missing_required_ssn_ntt
class-attribute
instance-attribute
¶
multiple_employments_found
class-attribute
instance-attribute
¶
no_active_employment_found
class-attribute
instance-attribute
¶
not_matching_external_employee_id
class-attribute
instance-attribute
¶
start_date_too_far_back
class-attribute
instance-attribute
¶
EmploymentInputErrorInfo
dataclass
¶
extractors ¶
This file contains "extractors", which are utility functions that aim to parse and validate items from a dict.
This file only contains global extractors for use in any country - more specialized extractors (e.g. French SSN extractors) should be put in an appropriate spot in each country's component.
Extractors ensure that we perform validation consistently across a range of input methods.
Typical usage of extractors will follow this pattern:
- Provide a function that raises an exception for a specific error
- Use
partialonextract_or_raiseto get your extraction function - Use the extraction function with the extractors you need
Here's a working example:
def raiser(error: EmploymentInputErrorInfo) -> NoReturn:
raise ExtractorInputException(
company_id=..., # or None if you don't have it yet
user_id=..., # or None if you don't have it yet
error=error
)
extract = partial(extract_or_raise, data=YOUR_DICT, raiser=raiser)
first_name = extract(extractor=extract_mandatory_first_name, field="first_name")
ExtractorInputException ¶
Bases: UpstreamError
A simple exception when you don't need to use a specific exception with except_or_raise.
Usage:
def raiser(error: EmploymentInputErrorInfo) -> NoReturn:
raise ExtractorInputException(
company_id=..., # or None if you don't have it yet
user_id=..., # or None if you don't have it yet
error=error
)
Optionally, you can also pass a context value, which will end up in the UpstreamBlockedMovement's context field.
Source code in components/employment/public/business_logic/rules/extractors.py
to_blocked_movement_info ¶
Source code in components/employment/public/business_logic/rules/extractors.py
ExtractorResult
module-attribute
¶
Result of an extractor function. Always a tuple:
- If a success, the first value is the parsed value (may be
Nonedepending on the extractor), the second value is None - If a failure, the first value is None, the second value is an
EmploymentInputErrorInfowith details on the error.
cast_to_date_with_validation ¶
Cast the provided value to a datetime object.
By default, strings are parsed using the regular ISO format (YYYY-MM-DD).
Returns a tuple with both the parsed value (or none if the input value was falsy) and a boolean indicating whether the parsing was successful or not.
Note: this in itself is not an extractor, but can be used to build extractors with more useful error diagnostics.
Source code in components/employment/public/business_logic/rules/extractors.py
extract_birth_date_from_data ¶
Birth date extractor
Source code in components/employment/public/business_logic/rules/extractors.py
extract_boolean_from_data ¶
Utility for parsing booleans written in plain language.
Note: this is not a real extract (as it doesn't return a proper ExtractorResult), this is intended to be used
as a utility to build extractors.
Source code in components/employment/public/business_logic/rules/extractors.py
extract_email_from_data ¶
Email extractor
Source code in components/employment/public/business_logic/rules/extractors.py
extract_end_date_from_data ¶
End date extractor
Source code in components/employment/public/business_logic/rules/extractors.py
extract_external_employee_id_from_data_without_validation ¶
External employee ID (matricule, payroll ID, etc.) extractor.
Note: this extractor does NOT perform validation. For France, use the "extract_external_employee_id" function, which does.
Source code in components/employment/public/business_logic/rules/extractors.py
extract_gender_from_data ¶
Gender extractor
Source code in components/employment/public/business_logic/rules/extractors.py
extract_mandatory_birth_date_from_data
module-attribute
¶
extract_mandatory_birth_date_from_data = mandatory_extractor(
extractor=extract_birth_date_from_data,
missing_value_error_code=missing_required_birth_date,
value_name="birth date",
)
extract_mandatory_email_from_data
module-attribute
¶
extract_mandatory_email_from_data = mandatory_extractor(
extractor=extract_email_from_data,
missing_value_error_code=missing_required_email,
value_name="e-mail",
)
extract_mandatory_first_name_from_data ¶
First name extractor
Source code in components/employment/public/business_logic/rules/extractors.py
extract_mandatory_gender_from_data
module-attribute
¶
extract_mandatory_gender_from_data = mandatory_extractor(
extractor=extract_gender_from_data,
missing_value_error_code=missing_required_gender,
value_name="gender",
)
extract_mandatory_last_name_from_data ¶
Last name extractor
Source code in components/employment/public/business_logic/rules/extractors.py
extract_mandatory_start_date_from_data ¶
Start date extractor
Source code in components/employment/public/business_logic/rules/extractors.py
extract_or_raise ¶
Used to wrap an extractor to make its use easier in upstream scenarios.
Typical usage:
def raiser(error: EmploymentInputErrorInfo) -> NoReturn:
raise SomeException(...)
extract = partial(extract_or_raise, data=..., raiser=raiser)
first_name = extract(extractor=extract_mandatory_first_name_from_data, field_name="first_name")
# ...
Note: if you do not have or need a custom exception for your use case, you can use ExtractorInputException, like
so:
def raiser(error: EmploymentInputErrorInfo) -> NoReturn:
raise ExtractorInputException(
company_id=..., # or None if you don't have it yet
user_id=..., # or None if you don't have it yet
error=error
)
Source code in components/employment/public/business_logic/rules/extractors.py
mandatory_extractor ¶
Utility function to turn an extractor that returns a value or None if absent into a "mandatory" extractor.
Usage:
extract_mandatory_email_from_data = mandatory_extractor(
extract_email_from_data,
EmploymentInputErrorCode.missing_invite_email,
"Invitation Email"
)
This function is typed properly: the signature of the initial extractor is retained (and you can safely use it with 'partial'), and the resulting function is guaranteed to return a non-None value.
Source code in components/employment/public/business_logic/rules/extractors.py
parse_integer_string ¶
Used for SSNs, NTTs, SIRENs and external employee IDs ("matricules"). Sometimes these integer strings are floats in the excel spreadsheet, so it adds a decimal part when we stringify them (str(float(1)) -> '1.0')
Source code in components/employment/public/business_logic/rules/extractors.py
stale_invitations ¶
SKIP_STALE_INVITATION_CHECK_METADATA_KEY
module-attribute
¶
check_invitation_is_not_stale ¶
Verifies that an invitation with the provided date does not fall under a "stale invitation" scenario.
Stale invitations are a special flow used to handle invitations that would incur more than 100 days of coverage upon invitation. These can be admin mistakes and might need to be checked - otherwise, admins would incur a lot of regularization.
Note that 'start_date' is not the start date of the employee in the company, but the effective start date of their coverage. For example, employees added with a start date in the 2000s but whose company just signed up for Alan do not count as "stale" invitations.
Source code in components/employment/public/business_logic/rules/stale_invitations.py
components.employment.public.constants ¶
components.employment.public.country_gateway ¶
CompanyInformation
dataclass
¶
CountryGateway ¶
Bases: ABC, Generic[_TValues]
Class used by the Employment Component to retrieve local-specific data.
!!! ALL imports to local components MUST be done as local imports. !!!
There should be one implementation of CountryGateway per country that uses the Employment Component. You need to add your country's implementation in components.employment.external.country_gateways
are_companies_in_same_account
abstractmethod
¶
Returns True if the two companies are in the same account - false otherwise.
This is used to determine whether a transfer is necessary or not - see here ⧉.
Source code in components/employment/public/country_gateway.py
get_account_name
abstractmethod
¶
get_blocked_invitations_validation_broadcast_id ¶
(Advanced) Get the ID of the daily broadcast to send to admins with stale invitations that need to be validated.
This is used by the send_stale_invitations_validation_broadcasts command
to send a daily broadcast to all admins with stale invitations that need to be validated.
If your country does not require Stale Invitations support, you can leave this unimplemented.
Returns:
| Type | Description |
|---|---|
str | None
|
str | None: The ID of the daily broadcast, or None if no broadcast is required. |
Source code in components/employment/public/country_gateway.py
get_company_information
abstractmethod
¶
Retrieves comprehensive company information including display name, account ID, and settings.
get_consumers_to_notify_for_legacy_backfill ¶
(Advanced) Gets all employment consumers to notify for legacy backfill.
Typically, consumers are not notified for legacy backfill, as it's data ingested from the country legacy tables so countries already have the data. Some consumers may not look at the "legacy tables" and hence need to be notified for legacy backfill though (e.g. Occupational Health in FR).
If you want the consumer to also be notified for other source types, you should add it to the get_employment_consumers method.
Source code in components/employment/public/country_gateway.py
get_employee_identifier_for_country
abstractmethod
¶
Retrieves the Employee Identifier from the provided extended values.
Note: implementation is only required if your country requires Stale Invitations support.
Source code in components/employment/public/country_gateway.py
get_employment_consumers
abstractmethod
¶
Gets all employment consumers contributed by this country.
Notes: 1. ALL Employment Consumers will be called regardless of the country of origin. 2. The function that will be called must have all local code as LOCAL (in-function) imports - otherwise, this breaks Canada (where loading non-CA models is forbidden)
Source code in components/employment/public/country_gateway.py
get_retry_function ¶
(Advanced) Get the function used for retrying Core Blocked Movements.
You should generally not need to implement this.
Source code in components/employment/public/country_gateway.py
get_source_detail_for_blocked_movement ¶
(Advanced) Get detailed information on the blocked movement source.
For example, in France, this is used to extract the source's external provider when the source type is an external API. If not null, it will then be displayed alongside the source type on the blocked movements ops tool.
Source code in components/employment/public/country_gateway.py
get_upstream_retry_handler
abstractmethod
¶
Retrieves the upstream blocked movement retry function that corresponds to the given source_type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source_type
|
SourceType
|
The source type for which to retrieve the retry function - guaranteed to be of the CountryCode that corresponds to this CountryGateway. |
required |
Returns:
| Type | Description |
|---|---|
UpstreamBlockedMovementRetryFunction[_TValues] | None
|
UpstreamBlockedMovementRetryFunction[_TValues] | None: The retry function, or None if no retry function is available for the given source type. |
Source code in components/employment/public/country_gateway.py
get_user_admined_company_ids
abstractmethod
¶
Retrieves the list of company IDs admined by this user.
Note: implementation is only required if your country requires Stale Invitations support.
Source code in components/employment/public/country_gateway.py
get_user_full_name
abstractmethod
¶
Retrieves a user's full name (BaseUser.full_name), or None if the user does not exist
last_stale_invite_notification_email_sent_to_admin_on ¶
(Advanced) Get the timestamp of the last email sent to an admin of the given company regarding stale invitations.
This is used to determine whether an admin has already been notified of the stale invitations
If they have, we will set the stale invitation's status to awaiting_user_response_pending_self_healing
which will
- count as a terminal status for the purpose of our affiliation speed computation
- not notify admins again for this stale invitation.
If your country does not require Stale Invitations support, you can leave this unimplemented.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
company_id
|
str
|
The company ID for which to retrieve the last notification timestamp. |
required |
Returns: datetime | None: The timestamp of the last email sent, or None if no email has been sent.
Source code in components/employment/public/country_gateway.py
UpstreamBlockedMovementRetryFunction ¶
Bases: Protocol, Generic[_TValues]
A function that retries an Upstream Blocked Movement:
__call__ ¶
Retry an Upstream Blocked Movement from the provided upstream_data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
upstream_data
|
dict
|
The |
required |
root_employment_source_data_id
|
UUID
|
The Employment Source Data ID that corresponds to this upstream blocked movement - in order to correctly correlate the upstream blocked movement with the retry's results, you must set the EmploymentDeclaration's source_information field to this UUID. |
required |
commit
|
bool
|
As a general rule, the Upstream Retry Handler should NOT commit - disregard this parameter. |
required |
Returns:
| Type | Description |
|---|---|
EmploymentDeclaration[_TValues] | None
|
EmploymentDeclaration[_TValues] - if an EmploymentDeclaration needs to be processed as part of the retry |
EmploymentDeclaration[_TValues] | None
|
None - if no EmploymentDeclaration needs to be processed as part of the retry. |
Source code in components/employment/public/country_gateway.py
components.employment.public.entities ¶
CoreBlockedMovement
dataclass
¶
CoreBlockedMovement(
*,
id,
user_id,
company_id,
source_type,
error_code,
error_message,
context,
employment_id,
status,
note,
input_override,
parent_blocked_movement_id,
new_blocked_movements_after_retry,
upstream_parent_blocked_movement_id,
employment_source_data_id
)
Bases: DataClassJsonMixin
A blocked movement representing an error that occurred either:
- Within the Employment Component itself
- In one of the consumers of the Employment Component
from_core_blocked_movement_model
classmethod
¶
Internal conversion from the DB model to this dataclass
Source code in components/employment/public/entities.py
is_active ¶
Returns True if this blocked movement is considered to be active, i.e. something will happen and its status is expected to evolve (either by itself or via Ops action).
Source code in components/employment/public/entities.py
is_cancelled ¶
Returns True if this blocked movement is considered to be cancelled, i.e. it was not and will not be processed by the Employment Component.
Source code in components/employment/public/entities.py
CoreEmploymentVersion
dataclass
¶
CoreEmploymentVersion(
*,
employment_id,
user_id,
company_id,
start_date=isodate_field(),
end_date=optional_isodate_field(),
is_cancelled,
source_type,
employment_change_types,
employment_source_data_id,
external_employee_id=None
)
Bases: DataClassJsonMixin
A version of core information of an employment in the Employment Component.
This may or may not be the latest version of the employment depending on how you got this object.
employment_change_types
instance-attribute
¶
The change types that happened for this employment
employment_id
instance-attribute
¶
The ID of the employment within the Employment Component
employment_source_data_id
instance-attribute
¶
The Employment Source Data ID which this Core Employment Version comes from
end_date
class-attribute
instance-attribute
¶
End date of the employment. As much as possible, this should correspond to the real work contract's end date.
external_employee_id
class-attribute
instance-attribute
¶
An ID for the employee on the customer's HRIS.
In France, this corresponds to the "Matricule RH". Completely optional, can be None.
from_core_employment_version_model
classmethod
¶
Internal conversion from the DB model to this dataclass
Source code in components/employment/public/entities.py
is_cancelled
instance-attribute
¶
If True, the employment is cancelled and "no longer counts", as if it was deleted
source_type
instance-attribute
¶
The source from which this employment version was created
start_date
class-attribute
instance-attribute
¶
Start date of the employment. As much as possible, this should correspond to the real work contract's start date.
EmploymentChange
dataclass
¶
EmploymentChange(
core_employment_version,
extended_employment_updates,
previous_core_employment_version,
country_code,
)
Bases: DataClassJsonMixin, Generic[_TValues]
A change that happened as a result of an action in the Employment Component.
To know what changes happened:
- Use core_employment_version.employment_change_types to know if the employment's state changed (e.g.
invitation, termination, etc., see EmploymentChangeType for the full list). This can be empty if the only
changes were updates to extended values.
- Use extended_employment_updates to know which extended values changed, got added, got removed, etc.
core_employment_version
instance-attribute
¶
The Core Employment Version related to this change.
country_code
instance-attribute
¶
The country from/for which this EmploymentChange emanates.
This will generally be hinted at by core_employment_version.source_type, but not all source types are "local":
some are global and will provide no indication of their origin. You should thus rely on this field, which is
guaranteed to be set.
extended_employment_updates
instance-attribute
¶
Extended employment value updates related to this change.
NB: Will only contain brand new values updated as part of this change, will NOT contain all of the known extended values for the employment.
previous_core_employment_version
instance-attribute
¶
The last known core_employment_version for the employment, which is replaced (either literally or logically, see below) by the EmploymentChange's core_employment_version.
Note that this does not necessarily refer to an employment with an identical employment_id (e.g. transfers use previous_core_employment_version to indicate which CoreEmploymentVersion we are transfering from, but it is in another company, hence we have a previous_core_employment_version with a different employment_id)
EmploymentConsumer ¶
Bases: Protocol, Generic[_TValues]
A consumer of Employment changes.
Employment Consumers are contributed via the CountryGateway.get_employment_consumers function.
__call__ ¶
React to an employment changing. This function has a few rules:
- It must not commit
- All side-effects, such as sending an email, must be published to the EventBusOrchestrator, e.g.
Source code in components/employment/public/entities.py
EmploymentDeclaration
dataclass
¶
EmploymentDeclaration(
*,
user_id,
company_id,
start_date=isodate_field(),
end_date=optional_isodate_field(),
source_type,
extended_informations,
external_employee_id=None
)
Bases: DataClassJsonMixin, Generic[_TValues]
An employment declaration that can be ingested by the Employment Component via the ingest_employment_declaration.
Part of the Declarative API, see https://www.notion.so/alaninsurance/Employment-Component-API-entrypoints-1261426e8be780b0ab95d8a8ee57c5cd?pvs=4 ⧉
end_date
class-attribute
instance-attribute
¶
End date of the employment. As much as possible, this should correspond to the real work contract's end date.
extended_informations
instance-attribute
¶
Extended information about the employment.
Upon ingestion, new information provided in this array is stored and sent to consumers.
external_employee_id
class-attribute
instance-attribute
¶
An ID for the employee on the customer's HRIS.
In France, this corresponds to the "Matricule RH". Completely optional, can be None.
source_type
class-attribute
instance-attribute
¶
The source type from which this employment comes from. Either:
- A local source type, e.g.
SourceType.fr_bulk_invite - A global source type associated with a country code, e.g.
GlobalSourceType.legacy_backfill.with_country(CountryCode.fr)
start_date
class-attribute
instance-attribute
¶
Start date of the employment. As much as possible, this should correspond to the real work contract's start date.
to_core_employment_version ¶
Converts this EmploymentDeclaration into a CoreEmploymentVersion.
Intended for internal use by the Employment Component.
Source code in components/employment/public/entities.py
EmploymentSourceData
dataclass
¶
EmploymentSourceData(
*,
id,
source_type,
raw_data,
metadata,
core_employment_versions,
extended_employment_updates,
upstream_blocked_movements,
core_blocked_movements
)
Bases: DataClassJsonMixin
Represents data attached to an ingestion in the Employment Component.
This corresponds to a SourceInformation that was attached to some action(s) done in the Employment Component.
Concretely, this may correspond to a UCE action on Marmot, a row in an Excel file, an admin action on their dashboard, etc.
from_employment_source_data_model
staticmethod
¶
Internal conversion from the DB model to this dataclass
Source code in components/employment/public/entities.py
metadata
instance-attribute
¶
Mutable metadata associated with this Employment Source Data. No specific format is expected (other than this has to be serializable to JSON). Can be used to store simple logging data, or to implement advanced custom flows on top of the Employment Component.
raw_data
instance-attribute
¶
The raw data, as it was received by the upstream. Taken from SourceInformation.raw_data
ExtendedEmploymentUpdate
dataclass
¶
ExtendedEmploymentUpdate(
employment_id,
validity_period,
source_type,
values,
employment_source_data_id,
)
Bases: DataClassJsonMixin, Generic[_TValues]
An update to the extended values of an employment.
NB: Do not directly use this class for getting all of the latest extended values of an employment, use get_employment_values_on instead.
employment_id
instance-attribute
¶
The ID of the employment within the Employment Component
employment_source_data_id
instance-attribute
¶
The Employment Source Data ID which this Core Employment Version comes from
from_extended_employment_update_model
classmethod
¶
Internal conversion from the DB model to this dataclass
Source code in components/employment/public/entities.py
ExtendedInformation
dataclass
¶
Bases: DataClassJsonMixin, Generic[_TValues]
Extended information related to an employment, see also EmploymentDeclaration.extended_informations.
validity_period
instance-attribute
¶
A validity period for the extended information. There are several possibilities:
validity_period=None: Information is valid for the entire duration of the employmentvalidity_period=ValidityPeriod(...): Information is valid for a specific duration within the employment.
values
instance-attribute
¶
The values in question, as a dict. Keys must always be strings, while values must be anything that can easily be translated to JSON by SQLAlchemy. We recommend only using simple types here (numbers, booleans, strings, etc.) to avoid serialization/deserialization issues.
Refer to ExtendedValuesDict for more information.
ExtendedValuesDict ¶
Bases: TypedDict
Subclass this class to define your extended values like so (the total=False is mandatory):
class CcExtendedValues(ExtendedValuesDict, total=False):
local_identifier: str
something_optional: str | None
CcEmploymentDeclaration = EmploymentDeclaration[CcExtendedValues]
# ...
employment_declaration = CcEmploymentDeclaration(
user_id=...
...
)
Cc = Country Code. For example, in France, you would use the FrExtendedValues name.
Typing rules¶
Because this dictionary is serialized and deserialized by SQLAlchemy, you must only use simple types, such as:
- Strings (
str) - Numbers (
int/float) - Booleans (
bool) None- Lists of the aforementioned types (
list[...]) - Dicts with string keys and values of the aforementioned types (
dict[str, ...])
Using anything else may lead to errors at runtime. We unfortunately cannot check this right via mypy now, see PEP 728.
Having None as a valid type is significant:
- Not specifying
Nonein your type (e.g.foo: str) means that it can be absent or present, and if present, it will not beNone(*equivalent toT | undefinedin TypeScript) - Specifying
Nonein your type (e.g.bar: str | None) means that it can be absent or present, and if present, it can beNone(*equivalent toT | null | undefinedin TypeScript)
Sensitive values (Kay anonymization)¶
The JSON is encrypted on Turing, but is passed through normally on Kay. In order to anonmyize extended values...
- ... with an
AlwaysNonestrategy, use theSensitiveNonetype alias: - ... with a custom strategoy, use
Annotated[..., SensitiveValue(kay.SomeStrategy())]:
class CcExtendedValues(ExtendedValuesDict, total=False):
something_sensitive: SensitiveNone[str | None]
some_email: Annotated[str | None, SensitiveValue(kay.Something())]
The resulting Kay strategy is built by the Employment Component, from all known ExtendedValuesDict subclasses.
GenericBlockedMovementInfo
dataclass
¶
Bases: DataClassJsonMixin
This dataclass is meant to represent both BlockedMovementInfo and UpstreamBlockedMovementInfo for the public API
IngestionResult
dataclass
¶
Bases: DataClassJsonMixin
The result of a call to the ingest_employment_declaration function.
employment_source_data
instance-attribute
¶
The EmploymentSourceData object associated with this ingestion, created from the provided SourceInformation..
success
instance-attribute
¶
If True, the declaration was processed successfully. If False, the declaration failed to be processed, and a blocked movement was created.
Inspect employment_source_data to find out more.
NoContext
dataclass
¶
Bases: UpstreamBlockedMovementContext
A simple context that contains nothing for Upstream Blocked Movements.
RULE_CASE_GETTER_BY_EMPLOYMENT_CHANGE_TYPE
module-attribute
¶
RULE_CASE_GETTER_BY_EMPLOYMENT_CHANGE_TYPE = {
invitation: lambda **_: invite,
termination: lambda end_date, **_: (
terminate
if not is_end_date_too_far_in_the_past(end_date)
else terminate_with_end_date_more_than_100_days_in_the_past
),
start_date_change: lambda **_: change_start_date,
end_date_change: lambda end_date, **_: (
change_end_date
if not is_end_date_too_far_in_the_past(end_date)
else change_end_date_more_than_100_days_in_the_past
),
resumption: lambda **_: resume,
cancellation: lambda **_: cancel,
transfer: lambda start_date, **_: (
transfer
if not is_transfer_date_too_far_in_the_past(
start_date
)
else transfer_more_than_100_days_in_the_past
),
external_employee_id_change: lambda external_employee_id, **_: (
change_external_employee_id
if external_employee_id is not None
else change_external_employee_id_if_none
),
}
RetryFunction ¶
Bases: Protocol, Generic[_TValues]
Function used for retrying an EmploymentDeclaration (as part of both Upstream and Core Blocked Movements).
This is a technical detail that should only be used in cases that need to do something, such as a legacy backfill, before sending an EmploymentDeclaration.
__call__ ¶
__call__(
employment_declaration,
source_information,
commit,
event_bus_orchestrator=None,
retried_blocked_movement=None,
upstream_retried_blocked_movement=None,
source_rules_override=None,
)
Process an EmploymentDeclaration - signature is the exact same as the ingest_employment_declaration function.
Source code in components/employment/public/entities.py
SensitiveValue
dataclass
¶
Identifies a value as sensitive - the provided Kay strategy will be applied on this value (as part of kay.StructedJsonStrategy()).
Must be used as an annotation on ExtendedValuesDict fields, like this:
For the AlwaysNone strategy, use the SensitiveNone alias instead:
SourceInformation ¶
Bases: DataClassJsonMixin
Provides additional information on the source of an EmploymentDeclaration or any action within the Employment Component.
This item allows accurately tracking the results of an action that impacts the Employment Component. Once
processed, the SourceInformation object becomes a row in the employment.employment_source_data table. All
models created as a result of the ingestion or action are correlated to this EmploymentSourceData row via the
employment_source_data_id.
There are several use cases for the SourceInformation object:
- Keep a log of the raw data, as it is received by you. This could be an Excel row, the body of a POST API call, etc.
- Keeping queryable and mutable metadata about an ingestion in the Employment Component.
Re-using SourceInformation objects¶
If your use case requires doing multiple things in the Employment Component, you can reuse the SourceInformation object.
For example, if your use case requires cancelling an employment, then ingesting an EmploymentDeclaration, you can use the same SourceInformation object to correlate these actions together:
source_information = SourceInformation(raw_data={...}, metadata={...})
cancel(employment_id=..., source_information=source_information)
declaration = EmploymentDeclaration(...)
result = ingest_employment_declaration(employment_declaration=declaration, source_information=source_information)
employment_source_data = result.employment_source_data
employment_source_data.core_employment_versions # will contain the cancelled employment + the new ingestion's result
metadata
class-attribute
instance-attribute
¶
Additional mutable metadata. For example, this could contain, IDs to the various files used to build a declaration, a flag, etc.
This metadata is mutable, see update_employment_source_data_metadata_with
raw_data
class-attribute
instance-attribute
¶
The raw data your upstream used to build the EmploymentDeclaration.
For example, if creating an EmploymentDeclaration because of an API called from a third party, you could put the body of this API call here. Philosophically, your upstream would be able to fully reconstruct the EmploymentDeclaration with the information in raw_data.
Used mainly for logging purposes. Once the employment declaration is ingested, this value is read-only.
source_type
class-attribute
instance-attribute
¶
The source type for this SourceInformation.
You do not need to set this value: by default, the SourceInformation will take on the source_type it is first used
with. For example, here, it will automatically get the fr_admin_dashboard source type:
source_information = SourceInformation(...)
cancel(..., source_type=SourceType.fr_admin_dashboard, source_information=source_information)
# -> Resulting EmploymentSourceData entry has source type `fr_admin_dashboard`
Setting this value forces a specific source type to be used. This is useful in case the first of this SourceInformation does something unrelated, like a Legacy Backfill in France.
SourceInformationLike
module-attribute
¶
A type that represents anything that can be converted into an EmploymentSourceDataModel, and that is usable from the outside (as things outside of the Employment Component don't have access to the raw model).
UUID is a more advanced option to correctly support edge cases. You should use SourceInformation in almost all cases.
SourceRules
dataclass
¶
SourceRules(
invite,
terminate,
change_start_date,
change_end_date,
resume,
cancel,
transfer,
change_external_employee_id,
terminate_with_end_date_more_than_100_days_in_the_past,
change_end_date_more_than_100_days_in_the_past,
change_external_employee_id_if_none,
transfer_more_than_100_days_in_the_past,
)
Bases: DataClassJsonMixin
This dataclass allows to define what action to take for each "rule case". The rules are defined for each source
type in sources_configuration.py.
Rule cases are changes that can happen to an employee. The main rule cases map 1-1 to EmploymentChangeTypes. There are also more specific rule cases to handle edge cases.
__post_init__ ¶
In order to be able to retry old blocked movements (which contain JSONified objects of this class), we need to provide a fallback for new cases. This is the way to do it with Python dataclasses whose default value depends on other fields.
Source code in components/employment/public/entities.py
change_end_date_more_than_100_days_in_the_past
instance-attribute
¶
change_external_employee_id_if_none
instance-attribute
¶
The employment's external employee ID is changed (EmploymentChangeType.external_employee_id_change), but the new
external employee ID is None, which can mean that it is not known.
This allows you to decide if None values you receive should clear the external employee ID value of the employment (= apply) or None values should be ignored (= ignore)
get_rule_case_action_for_employment_change_type ¶
get_rule_case_action_for_employment_change_type(
employment_change_type,
start_date,
end_date,
external_employee_id,
)
Define how to compute the rule case for a given employment change type and apply it to the employment_change_type parameter.
Source code in components/employment/public/entities.py
terminate_with_end_date_more_than_100_days_in_the_past
instance-attribute
¶
transfer_more_than_100_days_in_the_past
instance-attribute
¶
StaleInvitationInformation
dataclass
¶
StaleInvitationInformation(
blocked_movement_id,
company_id,
company_display_name,
employee_full_name,
employee_email,
employee_identifier,
start_date,
admin_was_notified,
created_at,
source_type,
country_code,
)
Bases: DataClassJsonMixin
admin_was_notified
instance-attribute
¶
Whether the admin was notified of the stale invitation - through CIO campaign cio-broadcast-221
StaleInvitationResolutionParameters
dataclass
¶
StaleInvitationResolutionParameters(
cancel,
can_have_target_start_date_more_than_100_days_in_the_past,
blocked_movement_id,
start_date_override=None,
)
UpstreamBlockedMovement
dataclass
¶
UpstreamBlockedMovement(
*,
id,
user_id,
company_id,
source_type,
error_code,
error_message,
context,
status,
note,
input_override,
parent_blocked_movement_id,
employment_source_data_id
)
Bases: DataClassJsonMixin
An upstream blocked movement, i.e. an error that happened within an Upstream (e.g. while building an Employment Declaration)
from_upstream_blocked_movement_model
classmethod
¶
Internal conversion from the DB model to this dataclass
Source code in components/employment/public/entities.py
is_active ¶
Returns True if this blocked movement is considered to be active, i.e. something will happen and its status is expected to evolve (either by itself or via Ops action).
Source code in components/employment/public/entities.py
is_cancelled ¶
Returns True if this blocked movement is considered to be cancelled, i.e. it was not and will not be processed by the Employment Component.
Source code in components/employment/public/entities.py
UpstreamBlockedMovementContext
dataclass
¶
Bases: DataClassJsonMixin
Root class for the context field of Upstream Blocked Movements
UpstreamBlockedMovementInfo
dataclass
¶
Bases: DataClassJsonMixin
Information to be used by UpstreamError implementations that are used to create an Upstream Blocked Movement
components.employment.public.enums ¶
ACTIVE_BLOCKED_MOVEMENT_STATUSES
module-attribute
¶
ACTIVE_BLOCKED_MOVEMENT_STATUSES = frozenset(
{
pending,
awaiting_user_response,
pending_self_healing,
awaiting_user_response_self_healing,
}
)
An immutable set containing all of the BlockedMovementStatuses considered "active", i.e. actions (of whichever kind) are required or are being done.
BLOCKED_MOVEMENT_SLA_TERMINAL_STATUSES
module-attribute
¶
BLOCKED_MOVEMENT_SLA_TERMINAL_STATUSES = frozenset(
{
cancelled,
resolved,
awaiting_user_response,
awaiting_user_response_self_healing,
automatically_resolved,
automatically_ignored,
automatically_cancelled,
}
)
BlockedMovementStatus ¶
Bases: AlanBaseEnum
The status of a blocked movement.
For more information, see https://www.notion.so/alaninsurance/Blocked-Movements-246a87a20f7a4cd388aee8a6327c4148?pvs=4 ⧉
automatically_cancelled
class-attribute
instance-attribute
¶
A self-healing blocked movement (whose status was pending_self_healing) that was cancelled as part of its automatic
self-healing process.
This is equivalent to cancelled for regular pending blocked movements.
automatically_ignored
class-attribute
instance-attribute
¶
A blocked movement that was created, but immediately ignored.
When a source rule dictates that a movement shall be ignored, instead of silently ignoring, a blocked movement with this status is created instead.
Automatically ignored blocked movements are automatically retried daily for technical reasons (context ⧉).
automatically_resolved
class-attribute
instance-attribute
¶
A self-healing blocked movement (whose status was pending_self_healing) that was resolved as part of its automatic
self-healing process.
This is equivalent to resolved for regular pending blocked movements.
awaiting_user_response
class-attribute
instance-attribute
¶
Ops has contacted the admin or member about this Blocked Movement. It is considered a terminal status in terms of SLA computation (our Ops' job is done), but is not the final status for a blocked movement (see https://www.notion.so/alaninsurance/Blocked-Movements-246a87a20f7a4cd388aee8a6327c4148?pvs=4#11c0a501e8b24cbb9603fa7dd273c321 ⧉).
awaiting_user_response blocked movements are automatically retried daily.
awaiting_user_response_self_healing
class-attribute
instance-attribute
¶
A blocked movement that is 'awaiting_user_response', but whose resolution is expected to happen automatically - this is a "self-healing" blocked movement.
Typical use cases include blocked movements that are created and automatically sent to the admin for action, and if the admin doesn't act after a certain time, the blocked movement is automatically resolved or cancelled by a daily command.
They are NOT automatically retried. This gives full control over their lifecycle to local code.
cancelled
class-attribute
instance-attribute
¶
A blocked movement that was cancelled - it was not resolved, usually because no action was required.
pending
class-attribute
instance-attribute
¶
A blocked movement that requires Ops attention. This is the default for newly created blocked movements.
Pending blocked movements are automatically retried daily.
pending_self_healing
class-attribute
instance-attribute
¶
A blocked movement that is 'pending', but whose resolution is expected to happen automatically - this is a "self-healing" blocked movement.
Typical use cases include blocked movements that are created, but then resolved or cancelled by a daily command. By
setting a blocked movement to have pending_self_healing status, it will not appear in the Blocked Movements tool
by default - meaning it will not create noise for Ops.
Note that blocked movements are never created with this state directly - you must manually mark pending blocked
movements as self-healing via the mark_pending_(core|upstream)_blocked_movement_as_self_healing function.
Self-healing blocked movements, i.e. those with status pending_self_healing, are NOT automatically retried. This
gives full control over their lifecycle to local code.
resolved
class-attribute
instance-attribute
¶
A blocked movement that was resolved, either automatically (by a daily retry, or a retry triggered by an Ops) or manually (status manually set to 'resolved').
Note that just because a blocked movement is resolved doesn't mean that the situation at hand is solved. A blocked movement may be resolved because another error happened - so this blocked movement is 'resolved' in the sense that we no longer get this specific error.
CANCELLED_BLOCKED_MOVEMENT_STATUSES
module-attribute
¶
An immutable set containing all of the BlockedMovementStatuses considered "cancelled", i.e. the blocked movement is not valid and/or there's nothing to process.
CountryCode ¶
Bases: AlanBaseEnum
The country associated with something in the Employment Component.
Usually deduced from the source_type of what you're looking at.
from_app_name
staticmethod
¶
Turns an AppName into a CountryCode - not compatible with all AppNames.
Source code in components/employment/public/enums.py
EmploymentChangeType ¶
Bases: AlanBaseEnum
The type of change that occurred.
cancellation
class-attribute
instance-attribute
¶
An employment is cancelled, and code should act as if this employment had never existed.
end_date_change
class-attribute
instance-attribute
¶
A change in the end date of an employment.
external_employee_id_change
class-attribute
instance-attribute
¶
The external employee ID of an employee is changed.
invitation
class-attribute
instance-attribute
¶
An invitation: an employee joins a company.
Mutually exclusive with all other change types.
NB: An invitation can also have an end_date in case of short-term work contracts. ⚠️ In this case, you will not receive a termination change type
resumption
class-attribute
instance-attribute
¶
A termination is cancelled, i.e. the end_date of an employment is cleared.
start_date_change
class-attribute
instance-attribute
¶
A change in the start date of an employment.
termination
class-attribute
instance-attribute
¶
A termination: an employee is terminated (an end_date is set).
NB: In case an employee is invited with an end_date, only invitation is set.
transfer
class-attribute
instance-attribute
¶
An employee is transferred from one company to another. This is both a termination (in the previous company) and an
invitation (in the new company).
This movement is computed when we receive a new employment for an employee that already has an employment in another
company of the same account.
Notes:
- An employee moving from one company to another company not part of the same account is not considered as a transfer,
an invitation will be computed in the new company and a termination in the old company when we receive the information.
This can potentially happen with a delay between the two actions
- It is still possible to force a transfer between two companies that are not part of the same account
by using the imperative function transfer
Mutually exclusive with all other change types.
uncancellation
class-attribute
instance-attribute
¶
An employment was cancelled by mistake and we want to undo the cancellation.
RuleCase ¶
Bases: AlanBaseEnum
The different cases that can Source Rules rule over.
change_end_date_more_than_100_days_in_the_past
class-attribute
instance-attribute
¶
change_end_date_more_than_100_days_in_the_past = (
"change_end_date_more_than_100_days_in_the_past"
)
change_external_employee_id
class-attribute
instance-attribute
¶
change_external_employee_id_if_none
class-attribute
instance-attribute
¶
terminate_with_end_date_more_than_100_days_in_the_past
class-attribute
instance-attribute
¶
terminate_with_end_date_more_than_100_days_in_the_past = (
"terminate_with_end_date_more_than_100_days_in_the_past"
)
transfer_more_than_100_days_in_the_past
class-attribute
instance-attribute
¶
RuleCaseAction ¶
Bases: AlanBaseEnum
An action to take when a rule is met.
block
class-attribute
instance-attribute
¶
Block: the whole declaration is blocked (a core blocked movement is created).
ignore
class-attribute
instance-attribute
¶
Ignore: skip this rule.
- If all movements are ignored, creates a core blocked movement with status
automatically_ignored - If some movements are ignored, the ignored one are not processed while the other are processed as usual
components.employment.public.exceptions ¶
ActionNotAllowed ¶
Bases: DeclarativeInputError
Raised when the source rules don't allow an action
Source code in components/employment/public/exceptions.py
create_blocked_movement_context ¶
Source code in components/employment/public/exceptions.py
AutomaticallyIgnoreConsumerError ¶
Bases: ConsumerError
A consumer error that is automatically ignored when created as a blocked movement.
Source code in components/employment/public/exceptions.py
to_blocked_movement_info ¶
Source code in components/employment/public/exceptions.py
ConsumerError ¶
Bases: DeclarativeInputError
Root class for errors raised within employment consumers that should lead to core blocked movements.
Source code in components/employment/public/exceptions.py
create_blocked_movement_context ¶
Source code in components/employment/public/exceptions.py
UnexpectedConsumerError ¶
Bases: ConsumerError
Error class used for unexpected errors raised from employment consumers.
Source code in components/employment/public/exceptions.py
create_blocked_movement_context ¶
Source code in components/employment/public/exceptions.py
UnexpectedLegacyBackfillError ¶
Bases: DeclarativeInputError
Error type for unexpected errors that occur during the legacy_backfill process.
Source code in components/employment/public/exceptions.py
create_blocked_movement_context ¶
Source code in components/employment/public/exceptions.py
to_blocked_movement_info ¶
Source code in components/employment/public/exceptions.py
UnexpectedUpstreamError ¶
Bases: UpstreamError
Error type used when an unexpected error occurs within an upstream (i.e. while preparing an Employment Declaration)
Source code in components/employment/public/exceptions.py
to_blocked_movement_info ¶
Source code in components/employment/public/exceptions.py
UnexpectedUpstreamErrorContext
dataclass
¶
UpstreamError ¶
Bases: ABC, Exception
An error that occurs within the upstream phase, i.e. when preparing an Employment Declaration.
Source code in components/employment/public/exceptions.py
to_blocked_movement_info
abstractmethod
¶
Generate an UpstreamBlockedMovementInfo object that will be used for creating the blocked movement.
components.employment.public.source_type ¶
components.employment.public.utils ¶
dump_results ¶
ExtraDumpData
dataclass
¶
upload_ingestion_results_as_csv ¶
Utility function that uploads the ingestion provided ingestion results as CSVs to S3 and prints links to download the files in the logs.
The main use-case for this function is for outputting the results of dry-run processes.
Source code in components/employment/public/utils/dump_results.py
user_matching ¶
UserMatchingProcessorWithEmploymentException ¶
Bases: UserMatchingProcessor[TSearchParams, TUser], Generic[TSearchParams, TUser]
A UserMatchingProcessor that raises exceptions that are compatible with the Employment Component's exception typing.
By inheriting from this class instead of the regular UserMatchingProcessor, your errors will show up as clean blocked movement instead of 'unexpected_upstream_error' blocked movements