Skip to content

Api reference

components.price_provider.public.api

InsuranceCostProviderService

Computing insurance costs.

get_insurance_cost staticmethod

get_insurance_cost(
    *,
    on_date: date,
    policy_id: UUID | int,
    contract_identifier: None = None,
    rounding_strategy: RoundingStrategy = RoundingStrategy.ARITHMETIC
) -> InsuranceCost
get_insurance_cost(
    *,
    on_date: date,
    policy_id: None = None,
    contract_identifier: ContractIdentifier,
    rounding_strategy: RoundingStrategy = RoundingStrategy.ARITHMETIC
) -> InsuranceCost
get_insurance_cost(
    *,
    on_date: date,
    beneficiary_specs: Sequence[BeneficiarySpec],
    policy_id: int | UUID,
    rounding_strategy: RoundingStrategy = RoundingStrategy.ARITHMETIC
) -> InsuranceCost
get_insurance_cost(
    *,
    on_date,
    policy_id=None,
    contract_identifier=None,
    beneficiary_specs=None,
    rounding_strategy=RoundingStrategy.ARITHMETIC
)

Compute insurance costs.

This insurance costs are evaluated based on
  • all coverage modules active on the given date, and the corresponding price grids
  • all beneficiaries active on the given date
  • all discounts active on the given date

When evaluating costs for a policy, if several coverage modules are active, the costs returned contain the aggregated cost breakdowns of all the coverage modules.

Parameters:

Name Type Description Default
on_date date

The reference date for coverage and affiliation data.

required
policy_id UUID | int | None

The unique identifier of the policy to compute costs for. Must be provided if contract_identifier is None.

None
contract_identifier ContractIdentifier | None

The contract identifier to compute costs for. Must be provided if policy_id is None. Currently not implemented.

None
beneficiary_specs Sequence[BeneficiarySpec] | None

Optional list of beneficiary specifications to use instead of the policy's current beneficiaries. When provided with policy_id, uses these beneficiaries with the policy's price grids.

None
rounding_strategy RoundingStrategy

Strategy for rounding monetary amounts when splitting costs between entities. Defaults to arithmetic rounding.

ARITHMETIC

Returns:

Type Description
InsuranceCost

An InsuranceCost object containing a detailed cost breakdown for 30 days of

InsuranceCost

coverage.

Raises:

Type Description
ValueError

If neither policy_id nor contract_identifier

ValueError

If no price grids are found for the policy on this date

NotImplementedError

If contract_identifier is used (not yet supported).

Examples:

# Use the beneficiary information corresponding to the state of the policy
# at the date of on_date.
# Use the price grid active on the policy's contract at the date of on_date
InsuranceCostProviderService.get_insurance_costs(policy_id=policy_id, on_date=on_date)

# Use an arbitrary list of beneficiaries.
# Use the price grid active on the policy's contract at the date of on_date
InsuranceCostProviderService.get_insurance_costs(
        beneficiarySpec=[BeneficiarySpec(...), BeneficiarySpec(...)]
        policy_id=policy_id,
        on_date=on_date
    )
Source code in components/price_provider/public/api.py
@staticmethod
def get_insurance_cost(
    *,
    on_date: date,
    policy_id: UUID | int | None = None,
    contract_identifier: "ContractIdentifier | None" = None,
    beneficiary_specs: Sequence[BeneficiarySpec] | None = None,
    rounding_strategy: RoundingStrategy = RoundingStrategy.ARITHMETIC,
) -> "InsuranceCost":
    """Compute insurance costs.

    This insurance costs are evaluated based on:
        - all coverage modules active on the given date, and the corresponding
          price grids
        - all beneficiaries active on the given date
        - all discounts active on the given date

    When evaluating costs for a policy, if several coverage modules are active,
    the costs returned contain the aggregated cost breakdowns of all the coverage
    modules.

    Args:
        on_date: The reference date for coverage and affiliation data.
        policy_id: The unique identifier of the policy to compute costs for.
            Must be provided if contract_identifier is None.
        contract_identifier: The contract identifier to compute costs for.
            Must be provided if policy_id is None. Currently not implemented.
        beneficiary_specs: Optional list of beneficiary specifications to use
            instead of the policy's current beneficiaries. When provided with
            policy_id, uses these beneficiaries with the policy's price grids.
        rounding_strategy: Strategy for rounding monetary amounts when splitting
            costs between entities. Defaults to arithmetic rounding.

    Returns:
        An InsuranceCost object containing a detailed cost breakdown for 30 days of
        coverage.

    Raises:
        ValueError: If neither policy_id nor contract_identifier
        ValueError: If no price grids are found for the policy on this date
        NotImplementedError: If contract_identifier is used (not yet supported).

    Examples:
        ```python
        # Use the beneficiary information corresponding to the state of the policy
        # at the date of on_date.
        # Use the price grid active on the policy's contract at the date of on_date
        InsuranceCostProviderService.get_insurance_costs(policy_id=policy_id, on_date=on_date)

        # Use an arbitrary list of beneficiaries.
        # Use the price grid active on the policy's contract at the date of on_date
        InsuranceCostProviderService.get_insurance_costs(
                beneficiarySpec=[BeneficiarySpec(...), BeneficiarySpec(...)]
                policy_id=policy_id,
                on_date=on_date
            )

        ```
    """
    beneficiaries: Sequence[BeneficiarySpec] | None = None
    pricing_scheme = None
    price_grid_descriptor_list: Sequence[PriceGridDescriptor] = []

    if beneficiary_specs and policy_id:
        from components.price_provider.public.dependencies import get_app_dependency

        deps = get_app_dependency()
        beneficiaries = beneficiary_specs
        pricing_scheme, price_grid_descriptor_list = (
            deps.get_pricing_scheme_for_policy(
                policy_id=policy_id,
                on_date=on_date,
            )
        )

    elif policy_id:
        from components.price_provider.public.dependencies import get_app_dependency

        deps = get_app_dependency()
        beneficiaries = deps.get_beneficiary_specs_from_policy(
            policy_id=policy_id,
            on_date=on_date,
        )
        pricing_scheme, price_grid_descriptor_list = (
            deps.get_pricing_scheme_for_policy(
                policy_id=policy_id,
                on_date=on_date,
            )
        )

    elif contract_identifier:
        raise NotImplementedError(
            "get_insurance_cost by contract_identifier not implemented yet"
        )
    else:
        raise ValueError(
            "Must provide exactly one of policy_id or contract_identifier"
        )

    if len(price_grid_descriptor_list) == 0:
        raise ValueError("No price grid descriptors found")

    all_costs: list[InsuranceCost] = []

    for descriptor in price_grid_descriptor_list:
        costs = pricing_scheme.computed_cost_for_beneficiaries(
            on_date=on_date,
            beneficiary_specs=beneficiaries,
            price_grid_descriptor=descriptor,
            rounding_strategy=rounding_strategy,
        )

        all_costs.append(costs)

    return InsuranceCost.merge(all_costs)

components.price_provider.public.dependencies

COMPONENT_NAME module-attribute

COMPONENT_NAME = 'price_provider'

Canonical name of the price provider component.

PriceProviderDependency

Bases: ABC

Dependencies injected into the price provider component. Every component depending on the price provider component is responsible for injecting its own implementation of these dependencies.

get_beneficiary_specs_from_policy abstractmethod

get_beneficiary_specs_from_policy(*, policy_id, on_date)

Retrieve the beneficiary specifications for a given policy.

Parameters:

Name Type Description Default
policy_id int | UUID

The unique identifier of the policy.

required
on_date date

The date for which to retrieve beneficiary specifications.

required

Returns:

Type Description
Sequence[BeneficiarySpec]

A list of beneficiary specifications containing the beneficiary type,

Sequence[BeneficiarySpec]

age, and other characteristics relevant for pricing calculations.

Source code in components/price_provider/public/dependencies.py
@abstractmethod
def get_beneficiary_specs_from_policy(
    self,
    *,
    policy_id: int | UUID,
    on_date: date,
) -> Sequence[BeneficiarySpec]:
    """Retrieve the beneficiary specifications for a given policy.

    Args:
        policy_id: The unique identifier of the policy.
        on_date: The date for which to retrieve beneficiary specifications.

    Returns:
        A list of beneficiary specifications containing the beneficiary type,
        age, and other characteristics relevant for pricing calculations.
    """
    pass

get_pricing_scheme_for_policy abstractmethod

get_pricing_scheme_for_policy(*, policy_id, on_date)

Retrieve the pricing scheme and price grid descriptor for a given policy.

Parameters:

Name Type Description Default
policy_id int | UUID

The unique identifier of the policy.

required
on_date date

The date for which to retrieve the pricing information.

required

Returns:

Type Description
PricingScheme

A tuple containing:

Sequence[PriceGridDescriptor]
  • PricingScheme: An object used to apply prices of a coverage module to a list of beneficiaries
tuple[PricingScheme, Sequence[PriceGridDescriptor]]
  • list of PriceGridDescriptor: One descriptor per active coverage module on the policy
Source code in components/price_provider/public/dependencies.py
@abstractmethod
def get_pricing_scheme_for_policy(
    self,
    *,
    policy_id: int | UUID,
    on_date: date,
) -> tuple[PricingScheme, Sequence[PriceGridDescriptor]]:
    """Retrieve the pricing scheme and price grid descriptor for a given policy.

    Args:
        policy_id: The unique identifier of the policy.
        on_date: The date for which to retrieve the pricing information.

    Returns:
        A tuple containing:
        - PricingScheme: An object used to apply prices of a coverage module to a
          list of beneficiaries
        - list of PriceGridDescriptor: One descriptor per active coverage module on
          the policy
    """
    pass

get_app_dependency

get_app_dependency()

Function used to fetch the dependencies from the flask app.

Source code in components/price_provider/public/dependencies.py
def get_app_dependency() -> PriceProviderDependency:
    """Function used to fetch the dependencies from the flask app."""
    from flask import current_app

    return cast("CustomFlask", current_app).get_component_dependency(COMPONENT_NAME)  # type: ignore[no-any-return]

set_app_dependency

set_app_dependency(dependency)

Function used to actually inject the dependency class in the component.

Source code in components/price_provider/public/dependencies.py
def set_app_dependency(dependency: PriceProviderDependency) -> None:
    """Function used to actually inject the dependency class in the component."""
    from flask import current_app

    cast("CustomFlask", current_app).add_component_dependency(
        COMPONENT_NAME, dependency
    )

components.price_provider.public.entities

PriceGridDescriptor

Bases: Protocol

Identifies which specific price grid to use for cost calculations.

At the moment, price grid have very local implementations and it is complicated to find a common global abstraction. Because the differences are so strong and we don't yet have the correct mental model in place, this protocol voluntarily very shallow. All we impose is that there is a class returning the ID of the entity to use to access price. For the moment, local implementations are responsible for coping with the complexity.

In France, it will be the ID of a PriceGrid. In Belgium, it will be the ID of a HealthSubscriptionPayload.

🇧🇪 Belgium Structure: Plan → Coverage Modules → Price Grids → Age-based Rules - 1 plan has many coverage modules - 1 coverage module has one price grid - 1 price grid has many age-based rules - Different beneficiaries can be on different coverage modules - Enrollment.coverage_module_name routes to the correct coverage module - Options are separate coverage modules (base + option modules coexist)

Belgian beneficiaries from the same policy can be on different coverage modules

Each beneficiary on a different coverage module implies they can be a on different grid. Pricing an entire policy using a single grid is not guaranteed to work !

🇫🇷 France Structure: Plan → Coverage Modules → Price Grids → Age-based Rules - 1 plan has many coverage modules (1 base + N options) - 1 coverage module can have up to 2 price grids: * Base modules: standard grid + optional Alsace-Moselle grid * Option modules: only standard grid - All beneficiaries always use the same coverage module - Policy with options = multiple active modules simultaneously (base + options) - Pricing entire policy = price multiple grids and merge results

French policies may have several active coverage modules at once

If a policy has an option, there are two coverage modules: 1 for the base and 1 for the option. The implication is that to retrieve the entire costs for a policy, we need to price two on two grids.

🇪🇸 Spain Structure: Hardcoded Product Types → Static Pricing Tables - No traditional grid system - uses hardcoded pricing matrices ?

🇨🇦 Canada Structure: Contract → Health Plan → Price Grid - Each contract has its own plan and price grid - Ultra-simple: only single_price_in_cents vs family_price_in_cents - No age-based rules, no options, no modules - Only 2 coverage types available (bear, marmot)

unique_identifier property

unique_identifier

ID of the object to fetch in order to resolves prices. In Belgium, it is the ID of HealthSubscriptionPayload as it gives us access to: - all coverage modules and their associated price grids - participation data

PricingScheme

Bases: Protocol

Encapsulates price grids and price rules. Local implementations are responsible for bringing their own PricingScheme and PriceGridDescriptor.

computed_cost_for_beneficiaries

computed_cost_for_beneficiaries(
    on_date,
    beneficiary_specs,
    price_grid_descriptor,
    rounding_strategy=RoundingStrategy.ARITHMETIC,
)

Compute monthly insurance costs for beneficiaries according to the grid pointed to by the descriptor.

Parameters:

Name Type Description Default
on_date date

Date for which we are projecting costs. The date is relevant because some discounts are date-based, and some grids have prices depending on the age of the beneficiary.

required
beneficiary_specs Sequence[BeneficiarySpec]

A description of beneficiaries with emphasis on the characteristics relevant to pricing,

required
price_grid_descriptor PriceGridDescriptor

A vague object pointing to a concrete price grid.

required
rounding_strategy RoundingStrategy

Strategy for rounding monetary amounts when splitting costs between various entities.

ARITHMETIC

Returns:

Type Description
InsuranceCost

Insurance costs.

Source code in components/price_provider/public/entities.py
def computed_cost_for_beneficiaries(
    self,
    on_date: date,
    beneficiary_specs: Sequence[BeneficiarySpec],
    price_grid_descriptor: PriceGridDescriptor,
    rounding_strategy: RoundingStrategy = RoundingStrategy.ARITHMETIC,
) -> InsuranceCost:
    """Compute monthly insurance costs for beneficiaries according to the grid
    pointed to by the descriptor.

    Args:
        on_date: Date for which we are projecting costs. The date is relevant because some discounts are date-based, and some grids have prices depending on the age of the beneficiary.
        beneficiary_specs: A description of beneficiaries with emphasis on the characteristics relevant to pricing,
        price_grid_descriptor: A vague object pointing to a concrete price grid.
        rounding_strategy: Strategy for rounding monetary amounts when splitting costs between various entities.

    Returns:
        Insurance costs.
    """
    ...

RoundingStrategy

Bases: AlanBaseEnum

Strategy for rounding monetary amounts.

ARITHMETIC class-attribute instance-attribute

ARITHMETIC = 'arithmetic'

Round half up (0.5 -> 1). Traditional rounding method.

BANKERS class-attribute instance-attribute

BANKERS = 'bankers'

Round half to even (0.5 -> 0, 1.5 -> 2). Reduces systematic bias.

components.price_provider.public.insurance_entities

BeneficiarySpec

Bases: Protocol

Represents a beneficiary for whom we are evaluating prices or costs.

beneficiary_age property

beneficiary_age

The age of the beneficiary, if available.

beneficiary_date_of_birth property

beneficiary_date_of_birth

The date of birth of the beneficiary, if available

beneficiary_type property

beneficiary_type

The type of beneficiary (primary, partner, child).

enrollment_id property

enrollment_id

Does this spec corresponding to a member enrolled on a policy ?

Currencies

Common currencies supported by this component.

EUR class-attribute instance-attribute

EUR = Currency(
    alphabetic_code="EUR", numeric_code=978, minor_unit=2
)

from_alphabetic_code classmethod

from_alphabetic_code(code)

Get a Currency instance by its ISO4217 alphabetic code.

Parameters:

Name Type Description Default
code str

The ISO4217 alphabetic code (e.g., "EUR")

required

Returns:

Type Description
Currency

The Currency instance matching the code

Raises:

Type Description
ValueError

If the currency code is not supported

Examples:

>>> currency = Currencies.from_alphabetic_code("EUR")
>>> currency.alphabetic_code
'EUR'
Source code in components/price_provider/public/insurance_entities.py
@classmethod
def from_alphabetic_code(cls, code: str) -> Currency:
    """
    Get a Currency instance by its ISO4217 alphabetic code.

    Args:
        code: The ISO4217 alphabetic code (e.g., "EUR")

    Returns:
        The Currency instance matching the code

    Raises:
        ValueError: If the currency code is not supported

    Examples:
        >>> currency = Currencies.from_alphabetic_code("EUR")
        >>> currency.alphabetic_code
        'EUR'
    """
    for attr_name in dir(cls):
        if attr_name.startswith("_"):
            continue
        attr_value = getattr(cls, attr_name)
        if isinstance(attr_value, Currency) and attr_value.alphabetic_code == code:
            return attr_value

    supported_codes = [
        getattr(cls, attr).alphabetic_code
        for attr in dir(cls)
        if not attr.startswith("_") and isinstance(getattr(cls, attr), Currency)
    ]
    raise ValueError(
        f"Unsupported currency code: {code}. "
        f"Supported codes: {', '.join(supported_codes)}"
    )

Currency dataclass

Currency(*, alphabetic_code, numeric_code, minor_unit)

Represents a currency. Attempting to comply with ISO4217.

alphabetic_code instance-attribute

alphabetic_code

ISO4217 compliant alpha code of the currency.

format_amount

format_amount(amount)

Format an amount in minor units as a string with currency code.

Examples:

formatted = Currencies.EUR.format_amount(1032)
print(formatted) # "10.32 EUR"
Source code in components/price_provider/public/insurance_entities.py
def format_amount(self, amount: int) -> str:
    """Format an amount in minor units as a string with currency code.

    Examples:
        ```python
        formatted = Currencies.EUR.format_amount(1032)
        print(formatted) # "10.32 EUR"
        ```
    """
    decimal_amount = self.from_minor_unit(amount)
    return f"{decimal_amount} {self.alphabetic_code}"

from_minor_unit

from_minor_unit(amount)

Convert from integer representation of the currency to a decimal representation.

Examples:

decimal_representation = Currencies.EUR.from_minor_unit(1032)
print(decimal_representation) # 10.32
Source code in components/price_provider/public/insurance_entities.py
def from_minor_unit(self, amount: int) -> Decimal:
    """Convert from integer representation of the currency to a decimal
    representation.

    Examples:
        ```python
        decimal_representation = Currencies.EUR.from_minor_unit(1032)
        print(decimal_representation) # 10.32
        ```
    """
    return Decimal(amount) / Decimal(10**self.minor_unit)

minor_unit instance-attribute

minor_unit

The number of digits after the decimal separator to represent as the minor unit. Helps us represent amounts as integers instead of floats, for example representing euros as cents.

Certain currenceis are naturally representable as ints and have 0 digits after the decimal place.

Examples: Japanese yen, South Korean won

numeric_code instance-attribute

numeric_code

ISO4217 compliant code of the currency.

to_minor_unit

to_minor_unit(amount)

Convert from floating point representation of the currency to an integer representation.

Useful to avoid precision errors of large floats.

Examples:

integer_representation = Currencies.EUR.to_minor_unit(10.32)
print(integer_representation) # 1032 cents
Source code in components/price_provider/public/insurance_entities.py
def to_minor_unit(self, amount: Decimal) -> int:
    """Convert from floating point representation of the currency to an integer
    representation.

    Useful to avoid precision errors of large floats.

    Examples:
        ```python
        integer_representation = Currencies.EUR.to_minor_unit(10.32)
        print(integer_representation) # 1032 cents
        ```
    """
    return int(amount * (10**self.minor_unit))

InsuranceBeneficiary

Bases: AlanBaseEnum

Represents the different types of insurance beneficiaries.

children class-attribute instance-attribute

children = 'children'

from_enrollment_type classmethod

from_enrollment_type(enrollment_type)

Convert EnrollmentType to InsuranceBeneficiary.

Source code in components/price_provider/public/insurance_entities.py
@classmethod
def from_enrollment_type(
    cls, enrollment_type: EnrollmentType
) -> "InsuranceBeneficiary":
    """Convert EnrollmentType to InsuranceBeneficiary."""
    if enrollment_type == EnrollmentType.primary:
        return cls.primary
    elif enrollment_type == EnrollmentType.partner:
        return cls.partner
    elif enrollment_type == EnrollmentType.child:
        return cls.children
    else:
        raise ValueError(f"Unknown enrollment type: {enrollment_type}")

partner class-attribute instance-attribute

partner = 'partner'

primary class-attribute instance-attribute

primary = 'primary'

to_enrollment_type

to_enrollment_type()

Convert InsuranceBeneficiary to EnrollmentType.

Source code in components/price_provider/public/insurance_entities.py
def to_enrollment_type(self) -> EnrollmentType:
    """Convert InsuranceBeneficiary to EnrollmentType."""
    if self == InsuranceBeneficiary.primary:
        return EnrollmentType.primary
    elif self == InsuranceBeneficiary.partner:
        return EnrollmentType.partner
    elif self == InsuranceBeneficiary.children:
        return EnrollmentType.child
    else:
        raise ValueError(f"Unknown beneficiary type: {self}")

InsuranceBilledEntity

Bases: AlanBaseEnum

Represents an entity paying for an insurance service.

company class-attribute instance-attribute

company = 'company'

partner class-attribute instance-attribute

partner = 'partner'

primary class-attribute instance-attribute

primary = 'primary'

InsuranceCollectionMethod

Bases: AlanBaseEnum

Methods for collecting an employee's participation.

direct_billing class-attribute instance-attribute

direct_billing = 'direct_billing'

The amount is paid directly by the employee or their partner, using the payment method of their choice.

payroll class-attribute instance-attribute

payroll = 'payroll'

The amount is paid by the company but automatically deducted from the employee's payslip.

InsuranceContribution

Bases: AlanBaseEnum

Represents how an amount is used, what the money is going towards.

cost class-attribute instance-attribute

cost = 'cost'

discount class-attribute instance-attribute

discount = 'discount'

membership_fee class-attribute instance-attribute

membership_fee = 'membership_fee'

social_fund class-attribute instance-attribute

social_fund = 'social_fund'

taxes class-attribute instance-attribute

taxes = 'taxes'

InsuranceCost dataclass

InsuranceCost(*, cost_components)

Represents the entire cost of an insurance service.

No safeties on cost components

There are no checks verifying there are no duplicates in components. The caller is responsible for ensuring the components represent a valid cost breakdown.

Source code in components/price_provider/public/insurance_entities.py
def __init__(self, *, cost_components: list[InsuranceCostComponent]):
    if len(cost_components) == 0:
        raise ValueError("No components to build a cost out of.")

    self.cost_components = cost_components
    self.currency = cost_components[0].currency

    # Compute some intermediary values frequently used by consumers, in O(n) time
    monthly_untaxed_amount_billed_to_primary = 0
    monthly_untaxed_amount_billed_to_company = 0

    monthly_taxes_billed_to_company = 0
    monthly_taxes_billed_to_primary = 0

    for component in cost_components:
        if component.currency != self.currency:
            raise ValueError("Cannot mix different currencies.")

        match component.billed_entity:
            case InsuranceBilledEntity.company:
                if component.contribution_type == InsuranceContribution.taxes:
                    monthly_taxes_billed_to_company += component.monthly_amount
                else:
                    monthly_untaxed_amount_billed_to_company += (
                        component.monthly_amount
                    )
            case InsuranceBilledEntity.primary:
                if component.contribution_type == InsuranceContribution.taxes:
                    monthly_taxes_billed_to_primary += component.monthly_amount
                else:
                    monthly_untaxed_amount_billed_to_primary += (
                        component.monthly_amount
                    )
            case billed_entity:
                raise NotImplementedError(
                    f"Unimplement billed entity: {billed_entity}"
                )

    monthly_taxed_amount_billed_to_primary = (
        monthly_untaxed_amount_billed_to_primary + monthly_taxes_billed_to_primary
    )
    monthly_taxed_amount_billed_to_company = (
        monthly_untaxed_amount_billed_to_company + monthly_taxes_billed_to_company
    )

    self.monthly_taxed_amount_billed_to_primary = (
        monthly_taxed_amount_billed_to_primary
    )
    self.monthly_untaxed_amount_billed_to_primary = (
        monthly_untaxed_amount_billed_to_primary
    )
    self.monthly_untaxed_amount_billed_to_company = (
        monthly_untaxed_amount_billed_to_company
    )
    self.monthly_taxed_amount_billed_to_company = (
        monthly_taxed_amount_billed_to_company
    )

    # Once initialised, the dataclass is frozen.
    # Enforced via custom __setattr__ implementation.
    self._initialized = True

__setattr__

__setattr__(name, value)

Setting attributes once the dataclass is initialized is forbidden. Reproducing the behavior of frozen=True.

Source code in components/price_provider/public/insurance_entities.py
def __setattr__(self, name: str, value: object) -> None:
    """
    Setting attributes once the dataclass is initialized is forbidden.
    Reproducing the behavior of frozen=True.
    """
    if hasattr(self, "_initialized") and self._initialized:
        raise AttributeError(
            f"Cannot modify {name} after initialization. InsuranceCost is immutable."
        )
    super().__setattr__(name, value)

cost_components instance-attribute

cost_components = cost_components

currency instance-attribute

currency = currency

from_components staticmethod

from_components(cost_components)

Construct an InsuranceCost from several cost components.

Raises:

Type Description
NotImplementedError

if the billed entity is not implemented yet

ValueError

if the currency used by all the components is not the same

Source code in components/price_provider/public/insurance_entities.py
@staticmethod
def from_components(
    cost_components: list[InsuranceCostComponent],
) -> "InsuranceCost":
    """
    Construct an InsuranceCost from several cost components.

    Raises:
        NotImplementedError: if the billed entity is not implemented yet
        ValueError: if the currency used by all the components is not the same
    """
    return InsuranceCost(cost_components=cost_components)

merge staticmethod

merge(insurance_costs)

Merge several costs into the same cost objects.

When we evaluate the costs of coverage modules individually, merging them is useful to get the total aggregated costs.

Source code in components/price_provider/public/insurance_entities.py
@staticmethod
def merge(
    insurance_costs: list["InsuranceCost"],
) -> "InsuranceCost":
    """
    Merge several costs into the same cost objects.

    When we evaluate the costs of coverage modules individually, merging them is
    useful to get the total aggregated costs.
    """
    if len(insurance_costs) == 1:
        return insurance_costs[0]

    all_components: list[InsuranceCostComponent] = []
    for cost in insurance_costs:
        all_components.extend(cost.cost_components)
    return InsuranceCost.from_components(all_components)

monthly_taxed_amount_billed_to_company instance-attribute

monthly_taxed_amount_billed_to_company = (
    monthly_taxed_amount_billed_to_company
)

monthly_taxed_amount_billed_to_primary instance-attribute

monthly_taxed_amount_billed_to_primary = (
    monthly_taxed_amount_billed_to_primary
)

monthly_untaxed_amount_billed_to_company instance-attribute

monthly_untaxed_amount_billed_to_company = (
    monthly_untaxed_amount_billed_to_company
)

monthly_untaxed_amount_billed_to_primary instance-attribute

monthly_untaxed_amount_billed_to_primary = (
    monthly_untaxed_amount_billed_to_primary
)

InsuranceCostComponent dataclass

InsuranceCostComponent(
    *,
    service_type,
    contribution_type,
    beneficiary_type,
    billed_entity,
    collection_method=None,
    enrollment_id=None,
    currency,
    monthly_amount
)

Represents part of a cost of insurance service.

__post_init__

__post_init__()

Validate that collection method is set when billed entity is not company.

Source code in components/price_provider/public/insurance_entities.py
def __post_init__(self) -> None:
    """Validate that collection method is set when billed entity is not company."""
    if (
        self.billed_entity != InsuranceBilledEntity.company
        and self.collection_method is None
    ):
        raise ValueError(
            f"Collection method must be set when billed entity is {self.billed_entity}"
        )

beneficiary_type instance-attribute

beneficiary_type

Who's coverage does this cost correspond to ?

billed_entity instance-attribute

billed_entity

Who is responsible for paying this cost ?

collection_method class-attribute instance-attribute

collection_method = None

If an employee is responsible for paying this cost, how is the payment collected ?

compare_component_lists staticmethod

compare_component_lists(left, right)

Compare two lists of insurance cost components for equality.

Parameters:

Name Type Description Default
left list[InsuranceCostComponent]

First list of components to compare

required
right list[InsuranceCostComponent]

Second list of components to compare

required

Returns:

Type Description
bool

True if both lists contain the same components in any order, False otherwise

Source code in components/price_provider/public/insurance_entities.py
@staticmethod
def compare_component_lists(
    left: list["InsuranceCostComponent"], right: list["InsuranceCostComponent"]
) -> bool:
    """
    Compare two lists of insurance cost components for equality.

    Args:
        left: First list of components to compare
        right: Second list of components to compare

    Returns:
        True if both lists contain the same components in any order, False otherwise
    """
    return set(left) == set(right)

contribution_type instance-attribute

contribution_type

What part of the service is paid for by this cost?

currency instance-attribute

currency

enrollment_id class-attribute instance-attribute

enrollment_id = None

An optional enrollment ID, in case the component corresponds to an enrolled member. It would typically be set when computing the prices for an existing policy. It would be None when a member projects the cost of adding their partner to their policy.

group_by_beneficiary_id staticmethod

group_by_beneficiary_id(components)

Groups insurance cost components by enrollment ID.

Parameters:

Name Type Description Default
components list[InsuranceCostComponent]

List of InsuranceCostComponent to group

required

Returns:

Type Description
dict[int | UUID, list[InsuranceCostComponent]]

Dictionary mapping enrollment ID (int or UUID) to list of components

Raises:

Type Description
ValueError

If any component does not have an enrollment ID

Source code in components/price_provider/public/insurance_entities.py
@staticmethod
def group_by_beneficiary_id(
    components: list["InsuranceCostComponent"],
) -> dict[int | UUID, list["InsuranceCostComponent"]]:
    """
    Groups insurance cost components by enrollment ID.

    Args:
        components: List of InsuranceCostComponent to group

    Returns:
        Dictionary mapping enrollment ID (int or UUID) to list of components

    Raises:
        ValueError: If any component does not have an enrollment ID
    """
    grouped: dict[int | UUID, list[InsuranceCostComponent]] = {}

    for component in components:
        if component.enrollment_id is None:
            raise ValueError("All components must have an enrollment ID")

        enrollment_id = component.enrollment_id
        if enrollment_id not in grouped:
            grouped[enrollment_id] = []
        grouped[enrollment_id].append(component)

    return grouped

monthly_amount instance-attribute

monthly_amount

The amount for a month of service, independantly of the month's duration.

Can be negative, for example if the amount corresponds to a discount. Must be expressed in the minor unit of the chosen currency.

service_type instance-attribute

service_type

What insurance service does this cost correspond to ?

InsuranceService

Bases: AlanBaseEnum

Represents an insurance coverage module.

base class-attribute instance-attribute

base = 'base'

extended class-attribute instance-attribute

extended = 'extended'

Base + option rolled into the same coverage module.

option class-attribute instance-attribute

option = 'option'