Skip to content

Api reference

components.premium.public.api

PremiumAggregationService

Service for retrieving and aggregating premium data with filtering capabilities.

Provides query interface for premium data retrieval with support for various filtering criteria such as time periods, policies, contracts, and beneficiary types. Designed to support analytics, reporting, and business intelligence use cases.

Note

This service is currently a placeholder for future premium retrieval functionality. Implementation will be added as premium storage capabilities are developed.

Future Capabilities
  • Filter premiums by date ranges, policy IDs, contract versions
  • Aggregate premiums by beneficiary type, coverage module, or time period
  • Support bulk retrieval for reporting and analytics

PremiumComputationService

Compute premiums.

Not responsible for storing the computed premiums

compute_insurance_premiums staticmethod

compute_insurance_premiums(
    session,
    *,
    policy,
    contract,
    start_month,
    end_month,
    engine_parameters=None
)

Compute how much money is owed to Alan and persist the results.

Parameters:

Name Type Description Default
session Session

SQLAlchemy session injected by @transactional decorator

required
policy Policy

The insurance policy containing enrollments

required
contract Contract

The contract defining pricing terms

required
start_month Month

First month to calculate premiums for

required
end_month Month

Last month to include in premium calculations

required
engine_parameters EngineParameters | None

Optional engine configuration. If not provided, uses defaults for current application

None

Returns:

Type Description
list[PremiumEntry]

All fresh entries returned by the computation.

Source code in components/premium/public/api.py
@staticmethod
@transactional
def compute_insurance_premiums(
    session: Session,
    *,
    policy: Policy,
    contract: Contract,
    start_month: Month,
    end_month: Month,
    engine_parameters: EngineParameters | None = None,
) -> list[PremiumEntry]:
    """
    Compute how much money is owed to Alan and persist the results.

    Args:
        session: SQLAlchemy session injected by @transactional decorator
        policy: The insurance policy containing enrollments
        contract: The contract defining pricing terms
        start_month: First month to calculate premiums for
        end_month: Last month to include in premium calculations
        engine_parameters: Optional engine configuration. If not provided, uses
            defaults for current application

    Returns:
        All fresh entries returned by the computation.
    """
    repository = get_app_dependency().get_premium_repository(session)
    engine_parameters = engine_parameters or EngineParameters.default(
        app_name=get_current_app_name()
    )

    affiliation_builder = AffiliationTimelineBuilder(
        policy=policy,
        contract=contract,
        engine_parameters=engine_parameters,
    )

    affiliation_timeline = affiliation_builder.compute_affiliation_timeline(
        start_date=start_month.first_day,
        end_date=end_month.last_day,
    )

    cost_timeline = map_timeline(
        affiliation_timeline,
        lambda period: CostPeriod(
            validity_period=period.validity_period,
            start_reason=period.start_reason,
            cost=InsuranceCostProviderService.get_insurance_cost(
                policy_id=policy.id,
                on_date=period.validity_period.start_date,
                beneficiary_specs=period.beneficiary_specs,
                rounding_strategy=engine_parameters.rounding_strategy,
            ),
        ),
    )

    all_new_entries = compute_subscription_fees(
        cost_timeline=cost_timeline,
        periodicity=Periodicity.monthly,
        start=start_month,
        end=end_month,
        engine_parameters=engine_parameters,
    )

    enrollment_ids = [enrollment.id for enrollment in policy.enrollments]
    existing_premiums = repository.get_latest_entries(
        enrollment_ids=enrollment_ids,
        period_start=start_month,
        period_end=end_month,
    )

    result = reconcile_premium_entries(
        new_premiums=all_new_entries,
        existing_premiums=existing_premiums,
    )

    repository.update(result["existing_entries_to_update"])
    repository.insert(
        result["cancelling_entries_to_insert"] + result["new_entries_to_insert"]
    )

    return all_new_entries

components.premium.public.commands

components.premium.public.dependencies

COMPONENT_NAME module-attribute

COMPONENT_NAME = 'premium'

Canonical name of the premium component.

PremiumDependency

Bases: ABC

Represents all the dependency required by components/premium to function as expected.

get_premium_repository abstractmethod

get_premium_repository(session)

Instantiate a persistence layer for premium repository

Source code in components/premium/public/dependencies.py
@abstractmethod
def get_premium_repository(self, session: Session | None) -> PremiumEntryRepository:
    """
    Instantiate a persistence layer for premium repository
    """
    ...

get_app_dependency

get_app_dependency()

Function used to fetch the dependencies from the flask app.

Source code in components/premium/public/dependencies.py
def get_app_dependency() -> PremiumDependency:
    """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/premium/public/dependencies.py
def set_app_dependency(dependency: PremiumDependency) -> 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.premium.public.entities

AgeStrategy

Bases: AlanBaseEnum

Strategy for handling age calculation in insurance premium calculations.

The effective birthday or age we use for pricing a beneficiary may differ from their actual birthday or age.

KEEP_EXACT_BIRTHDAY class-attribute instance-attribute

KEEP_EXACT_BIRTHDAY = 'exact_date'

Use the exact birthday for age calculation.

Example: If a member turns 23 on March 15, 2023, their age changes exactly on March 15, 2023.

MOVE_BIRTHDAY_TO_FIRST_DAY_OF_MONTH class-attribute instance-attribute

MOVE_BIRTHDAY_TO_FIRST_DAY_OF_MONTH = (
    "move_to_first_day_of_month"
)

Move birthday to the first day of the birth month for age calculation.

Example: If a member turns 23 on March 15, 2023, they will be priced as 23 years old starting March 1, 2023 for the entire month.

MOVE_BIRTHDAY_TO_JAN_OF_NEXT_YEAR class-attribute instance-attribute

MOVE_BIRTHDAY_TO_JAN_OF_NEXT_YEAR = 'jan_of_next_year'

Move birthday to January 1st of the year following the birth year.

Example: If a member turns 23 on March 15, 2023, they will be priced as 22 years old for the entirety of 2023, and 23 years old starting January 1, 2024.

CostPeriod dataclass

CostPeriod(*, start_reason, cost)

Bases: GenericPeriodWithStartReason

Represents a timeline period with computed premium cost.

Final output of the premium calculation pipeline, containing the actual cost for the stable period. Each period guarantees the cost remains constant throughout its validity period.

Attributes:

Name Type Description
cost Cost

The computed insurance cost for this period, calculated based on the stable beneficiary composition and contract terms.

cost instance-attribute

cost

EngineParameters dataclass

EngineParameters(
    *,
    age_strategy,
    rounding_strategy,
    prorata_strategy,
    default_child_age,
    default_adult_age,
    age_normalization_strategy
)

Parameters dictating how the engine behaves and which rules it follows.

Example
  • which effective birth date to use
  • which prorata formula to use
  • which rounding strategy to use

age_normalization_strategy instance-attribute

age_normalization_strategy

Optional strategy for normalizing ages into specific buckets for pricing. When None, ages are used directly from beneficiary birthdates or defaults. When specified, the strategy determines how to group beneficiaries by age.

age_strategy instance-attribute

age_strategy

default staticmethod

default(app_name)

Get default engine parameters for a given application. Application is used as a proxy for country.

Parameters:

Name Type Description Default
name

The application name to get default parameters for

required

Raises:

Type Description
ValueError

If the application is not yet supported

Source code in components/premium/internal/domain/engine_parameters.py
@staticmethod
def default(app_name: AppName) -> "EngineParameters":
    """
    Get default engine parameters for a given application.
    Application is used as a proxy for country.

    Args:
        name: The application name to get default parameters for

    Raises:
        ValueError: If the application is not yet supported
    """
    match app_name:
        case AppName.ALAN_BE:
            return EngineParameters(
                age_strategy=AgeStrategy.MOVE_BIRTHDAY_TO_FIRST_DAY_OF_MONTH,
                rounding_strategy=RoundingStrategy.BANKERS,
                prorata_strategy=ProrataStrategy.THIRTY_DAY_PRORATA_WITH_LARGEST_REMAINDER_DISTRIBUTION_ACROSS_FEE_COMPONENTS,
                age_normalization_strategy=LegacyBelgianNormalization(),
                default_child_age=17,
                default_adult_age=25,
            )
        case AppName.ALAN_FR:
            return EngineParameters(
                age_strategy=AgeStrategy.MOVE_BIRTHDAY_TO_JAN_OF_NEXT_YEAR,
                rounding_strategy=RoundingStrategy.BANKERS,
                prorata_strategy=ProrataStrategy.THIRTY_DAY_PRORATA_WITH_LARGEST_REMAINDER_DISTRIBUTION_ACROSS_FEE_COMPONENTS,
                age_normalization_strategy=None,
                default_child_age=17,
                default_adult_age=25,
            )
        case _:
            raise ValueError(f"Unsupported app_name: {app_name}")

default_adult_age instance-attribute

default_adult_age

default_child_age instance-attribute

default_child_age

prorata_strategy instance-attribute

prorata_strategy

rounding_strategy instance-attribute

rounding_strategy

FeeComponent dataclass

FeeComponent(*, id=uuid4(), num_days, invoice_id)

Bases: CostComponent

A fee component represents one part of a fee that we intend to bill to a customer.

__eq__

__eq__(other)
Source code in components/premium/internal/domain/fee.py
def __eq__(self, other: object) -> bool:
    if not isinstance(other, FeeComponent):
        return False

    return (
        self.num_days == other.num_days
        and self.monthly_amount == other.monthly_amount
        and self.currency == other.currency
        and self.beneficiary_type == other.beneficiary_type
        and self.service_type == other.service_type
        and self.contribution_type == other.contribution_type
        and self.billed_entity == other.billed_entity
        and self.collection_method == other.collection_method
        and self.enrollment_id == other.enrollment_id
    )

__hash__

__hash__()
Source code in components/premium/internal/domain/fee.py
def __hash__(self) -> int:
    return hash(
        (
            self.num_days,
            self.monthly_amount,
            self.currency.alphabetic_code,
            self.beneficiary_type,
            self.service_type,
            self.contribution_type,
            self.billed_entity,
            self.collection_method,
            str(self.enrollment_id) if self.enrollment_id else None,
        )
    )

as_tuple

as_tuple()

Return (billed_entity, contribution_type, amount)

Source code in components/premium/internal/domain/fee.py
def as_tuple(
    self,
) -> tuple["InsuranceBilledEntity", "InsuranceContribution", int]:
    """Return (billed_entity, contribution_type, amount)"""

    return (self.billed_entity, self.contribution_type, self.monthly_amount)

id class-attribute instance-attribute

id = field(default_factory=uuid4)

Unique identifier of the entry

inverted

inverted()

Returns a new FeeComponent offsetting the current one.

Source code in components/premium/internal/domain/fee.py
def inverted(self) -> "FeeComponent":
    """
    Returns a new FeeComponent offsetting the current one.
    """
    return FeeComponent(
        num_days=-self.num_days,
        monthly_amount=-self.monthly_amount,
        currency=self.currency,
        beneficiary_type=self.beneficiary_type,
        service_type=self.service_type,
        contribution_type=self.contribution_type,
        billed_entity=self.billed_entity,
        collection_method=self.collection_method,
        enrollment_id=self.enrollment_id,
        invoice_id=None,
    )

invoice_id instance-attribute

invoice_id

If the component is included in an invoice, it is represented here.

num_days instance-attribute

num_days

Number of days this fee covers within the billing period.

LegacyBelgianNormalization dataclass

LegacyBelgianNormalization()

Groups beneficiaries into specific age buckets: - Children are treated as adults if they are 25 or above - Young adults (18-25) are priced as 25 or above if they are the primary policy holder or their partner - No birthdate available: default to age 25 - Anyone not falling in one of the buckets above: use their actual age

CHILD_AGE_LIMIT_YEARS class-attribute instance-attribute

CHILD_AGE_LIMIT_YEARS = 25

normalize_age

normalize_age(
    effective_birthdate, enrollment_type, reference_date
)
Source code in components/premium/internal/domain/age_normalization.py
def normalize_age(
    self,
    effective_birthdate: date | None,
    enrollment_type: EnrollmentType,
    reference_date: date,
) -> int:
    if not effective_birthdate:
        return self.CHILD_AGE_LIMIT_YEARS

    age = age_on(effective_birthdate, reference_date)

    if enrollment_type != EnrollmentType.child and age < self.CHILD_AGE_LIMIT_YEARS:
        return self.CHILD_AGE_LIMIT_YEARS

    if enrollment_type == EnrollmentType.child and age < self.CHILD_AGE_LIMIT_YEARS:
        return 17

    return age

Policy

Bases: Historizable

enrollments instance-attribute

enrollments

id instance-attribute

id

PremiumEntry dataclass

PremiumEntry(
    *,
    id=uuid4(),
    enrollment_id,
    components,
    period_start,
    period_end,
    version=1,
    cancelled_by_entry_id=None,
    cancelled_entry_id=None
)

A subscription fee specific to insurance subscriptions.

__eq__

__eq__(other)
Source code in components/premium/internal/domain/fee.py
def __eq__(self, other: object) -> bool:
    if not isinstance(other, PremiumEntry):
        return False

    return (
        self.enrollment_id == other.enrollment_id
        and self.period_start == other.period_start
        and self.period_end == other.period_end
        and set(self.components) == set(other.components)
    )

__hash__

__hash__()
Source code in components/premium/internal/domain/fee.py
def __hash__(self) -> int:
    return hash(
        (
            str(self.enrollment_id),
            self.period_start,
            self.period_end,
            frozenset(self.components),
        )
    )

cancelled

cancelled()

Returns two new entries: one marking this entry as cancelled, and one offsetting it.

Returns:

Type Description
tuple[PremiumEntry, PremiumEntry | None]

tuple[PremiumEntry, PremiumEntry]: - First entry: Same as self but marked as cancelled - Second entry: New entry to offset self.

Source code in components/premium/internal/domain/fee.py
def cancelled(self) -> tuple["PremiumEntry", "PremiumEntry | None"]:
    """
    Returns two new entries: one marking this entry as cancelled, and one offsetting it.

    Returns:
        tuple[PremiumEntry, PremiumEntry]:
            - First entry: Same as self but marked as cancelled
            - Second entry: New entry to offset self.
    """

    # If B cancels A and we cancel B, it's equivalent to undoing the cancelation of
    # A
    # Therefore, canceling entries should never get canceled.
    if self.cancelled_entry_id:
        return self, None

    if self.cancelled_by_entry_id:
        return self, None

    cancelling_entry_id = uuid4()

    cancelled_entry = PremiumEntry(
        id=self.id,
        enrollment_id=self.enrollment_id,
        components=self.components,
        period_start=self.period_start,
        period_end=self.period_end,
        version=self.version,
        cancelled_entry_id=self.cancelled_entry_id,
        cancelled_by_entry_id=cancelling_entry_id,
    )

    offsetting_entry = PremiumEntry(
        id=cancelling_entry_id,
        enrollment_id=self.enrollment_id,
        components=[component.inverted() for component in self.components],
        period_start=self.period_start,
        period_end=self.period_end,
        version=self.version + 1,
        cancelled_by_entry_id=None,
        cancelled_entry_id=self.id,
    )

    return cancelled_entry, offsetting_entry

cancelled_by_entry_id class-attribute instance-attribute

cancelled_by_entry_id = field(default=None)

cancelled_entry_id class-attribute instance-attribute

cancelled_entry_id = field(default=None)

components instance-attribute

components

components_for_debtor

components_for_debtor(debtor)
Source code in components/premium/internal/domain/fee.py
def components_for_debtor(
    self, debtor: "InsuranceBilledEntity"
) -> list[FeeComponent]:
    return [c for c in self.components if c.billed_entity == debtor]

enrollment_id instance-attribute

enrollment_id

id class-attribute instance-attribute

id = field(default_factory=uuid4)

period_end instance-attribute

period_end

period_start instance-attribute

period_start

total_amount

total_amount()
Source code in components/premium/internal/domain/fee.py
def total_amount(self) -> int:
    return sum(c.monthly_amount for c in self.components)

total_amount_for_debtor

total_amount_for_debtor(debtor)
Source code in components/premium/internal/domain/fee.py
def total_amount_for_debtor(self, debtor: "InsuranceBilledEntity") -> int:
    return sum(
        c.monthly_amount for c in self.components if c.billed_entity == debtor
    )

version class-attribute instance-attribute

version = field(default=1)

with_version

with_version(version)

Returns a new PremiumEntry with a different version.

Source code in components/premium/internal/domain/fee.py
def with_version(self, version: int) -> "PremiumEntry":
    """Returns a new PremiumEntry with a different version."""
    return PremiumEntry(
        id=self.id,
        enrollment_id=self.enrollment_id,
        components=self.components,
        period_start=self.period_start,
        period_end=self.period_end,
        version=version,
        cancelled_by_entry_id=self.cancelled_by_entry_id,
        cancelled_entry_id=self.cancelled_entry_id,
    )

PremiumEntryRepository

Bases: Protocol

Repository protocol for persisting and retrieving premium entries.

get_all_entries

get_all_entries(enrollment_ids, period_start, period_end)

Retrieve all premium entries for specified enrollments Accepts an with an optional period.

Returns all stored premium entries including both cancelled and active entries.

Parameters:

Name Type Description Default
enrollment_ids list[int | UUID]

IDs (int or UUID) of enrollments to retrieve entries for. Some implementations may only support UUID IDs and will raise an error if int IDs are provided.

required
period_start Month | date | None

Optional lower bound for the entry period. If provided, only returns entries where entry.period_start == period_start. If Month is passed, use the first day of the month. If None, there is no filter on the start date of the period.

required
period_end Month | date | None

Optional upper bound for the entry period. If provided, only returns entries where entry.period_end == period_end. If Month is passed, use the last day of the month. If None, there is no filter on the end date of the period.

required

Returns:

Type Description
list[PremiumEntry]

List of PremiumEntry objects matching the filtering criteria.

list[PremiumEntry]

If both date parameters are None, returns all entries for the enrollments.

Source code in components/premium/internal/domain/repository.py
def get_all_entries(
    self,
    enrollment_ids: list[int | UUID],
    period_start: Month | date | None,
    period_end: Month | date | None,
) -> list[PremiumEntry]:
    """
    Retrieve all premium entries for specified enrollments
    Accepts an with an optional period.

    Returns all stored premium entries including both cancelled and active entries.

    Args:
        enrollment_ids: IDs (int or UUID) of enrollments to retrieve entries for.
            Some implementations may only support UUID IDs and will raise an error
            if int IDs are provided.
        period_start: Optional lower bound for the entry period.
            If provided, only returns entries where entry.period_start == period_start.
            If Month is passed, use the first day of the month.
            If None, there is no filter on the start date of the period.
        period_end: Optional upper bound for the entry period.
            If provided, only returns entries where entry.period_end == period_end.
            If Month is passed, use the last day of the month.
            If None, there is no filter on the end date of the period.

    Returns:
        List of PremiumEntry objects matching the filtering criteria.
        If both date parameters are None, returns all entries for the enrollments.
    """
    ...

get_latest_entries

get_latest_entries(
    enrollment_ids, period_start, period_end
)

Retrieve the latest premium entries for specified enrollments and period.

Note: For each period, an enrollee may have multiple entries.

Parameters:

Name Type Description Default
enrollment_ids list[int | UUID]

IDs (int or UUID) of enrollments to retrieve entries for. Some implementations may only support UUID IDs and will raise an error if int IDs are provided.

required
period_start Month | date

Exact start date of the period. If Month is passed, use the first day of the month.

required
period_end Month | date

Exact end date of the period. If Month is passed, use the last day of the month.

required

Returns:

Type Description
list[PremiumEntry]

List of PremiumEntry objects representing the latest entries

list[PremiumEntry]

for each enrollment with the specified period dates.

Source code in components/premium/internal/domain/repository.py
def get_latest_entries(
    self,
    enrollment_ids: list[int | UUID],
    period_start: Month | date,
    period_end: Month | date,
) -> list[PremiumEntry]:
    """
    Retrieve the latest premium entries for specified enrollments and period.

    Note: For each period, an enrollee may have multiple entries.

    Args:
        enrollment_ids: IDs (int or UUID) of enrollments to retrieve entries for.
            Some implementations may only support UUID IDs and will raise an error
            if int IDs are provided.
        period_start: Exact start date of the period.
             If Month is passed, use the first day of the month.
        period_end: Exact end date of the period.
             If Month is passed, use the last day of the month.

    Returns:
        List of PremiumEntry objects representing the latest entries
        for each enrollment with the specified period dates.
    """
    ...

insert

insert(entries)

Insert new premium entries into the database.

Parameters:

Name Type Description Default
entries list[PremiumEntry]

List of PremiumEntry objects to insert. Each entry's components will be added to the database.

required
Source code in components/premium/internal/domain/repository.py
def insert(self, entries: list[PremiumEntry]) -> None:
    """
    Insert new premium entries into the database.

    Args:
        entries: List of PremiumEntry objects to insert.
                 Each entry's components will be added to the database.
    """
    ...

session instance-attribute

session

update

update(entries)

Update existing premium entries in the database.

Parameters:

Name Type Description Default
entries list[PremiumEntry]

List of PremiumEntry objects to update. Each entry's components will be merged into the database.

required
Source code in components/premium/internal/domain/repository.py
def update(self, entries: list[PremiumEntry]) -> None:
    """
    Update existing premium entries in the database.

    Args:
        entries: List of PremiumEntry objects to update.
                 Each entry's components will be merged into the database.
    """
    ...

ProrataStrategy

Bases: AlanBaseEnum

Strategy for applying prorata to cost components.

When multiple cost components need prorating (e.g., base cost, membership fee, taxes), different strategies can be used that may produce slightly different results due to rounding.

THIRTY_DAY_PRORATA class-attribute instance-attribute

THIRTY_DAY_PRORATA = '30_day_prorata'

If the service covers the whole month, bill the full amount for 1 month. A month is a full month if the number of days covered equals the number of days in the month. If the service does not cover the whole month, prorate on the base of 30 days.

Formula: monthly_price * days_covered / 30

This prorata is applied to all the components of the subscription fee and may carry rounding errors, meaning the total of components may exceed the initial total.

THIRTY_DAY_PRORATA_WITH_LARGEST_REMAINDER_DISTRIBUTION_ACROSS_FEE_COMPONENTS class-attribute instance-attribute

THIRTY_DAY_PRORATA_WITH_LARGEST_REMAINDER_DISTRIBUTION_ACROSS_FEE_COMPONENTS = "30_day_prorata_with_largest_remainder_distribution_across_fee_components"

Similar to THIRTY_DAY_PRORATA except rounding errors are avoided by using the largest remainder algorithm to distribute the last few cents across the component.

There is a risk of losing accuracy, for example attributing more to the membership fee than we should. But we have the guarantee the total of the components will never exceed the initial total and the inaccuracies should never exceed 1 cent.

SubscriptionPeriod dataclass

SubscriptionPeriod(*, fees)

Bases: GenericPeriod

fees instance-attribute

fees

components.premium.public.models

premium_component

PremiumComponentModel

Bases: BaseModel

A model describing how to store global premium entries...

Each country is responsible for reimplementing their own model, inheriting from this one.

__abstract__ class-attribute instance-attribute
__abstract__ = True
__table_args__ class-attribute instance-attribute
__table_args__ = (
    UniqueConstraint(
        "enrollment_id",
        "premium_entry_id",
        "coverage_type",
        "beneficiary_type",
        "debtor_type",
        "period_start",
        "period_end",
        "contribution_type",
        "version",
        name="one_component_across_all_dimensions_per_version",
    ),
    Index(
        "ix_enrollment_id_version",
        "enrollment_id",
        "version",
    ),
    Index(
        "ix_period_start_end", "period_start", "period_end"
    ),
)
amount class-attribute instance-attribute
amount = mapped_column(Integer, nullable=False)

Expressed in the minor unit of the currency.

beneficiary_type class-attribute instance-attribute
beneficiary_type = mapped_column(
    Enum(InsuranceBeneficiary), nullable=False
)
cancelled_by_entry_id class-attribute instance-attribute
cancelled_by_entry_id = mapped_column(
    UUID(as_uuid=True), nullable=True, index=True
)
cancelled_entry_id class-attribute instance-attribute
cancelled_entry_id = mapped_column(
    UUID(as_uuid=True), nullable=True, index=True
)
collection_method class-attribute instance-attribute
collection_method = mapped_column(
    Enum(InsuranceCollectionMethod, nullable=True)
)
contribution_type class-attribute instance-attribute
contribution_type = mapped_column(
    Enum(InsuranceContribution), nullable=False
)
coverage_type class-attribute instance-attribute
coverage_type = mapped_column(
    Enum(InsuranceService), nullable=False
)
currency class-attribute instance-attribute
currency = mapped_column(String, nullable=False)

ISO4217 compliant alpha code of the currency.

debtor_type class-attribute instance-attribute
debtor_type = mapped_column(
    Enum(InsuranceBilledEntity), nullable=False
)
enrollment_id class-attribute instance-attribute
enrollment_id = mapped_column(
    UUID(as_uuid=True), nullable=False
)
invoice_id class-attribute instance-attribute
invoice_id = mapped_column(nullable=True, index=True)
num_days class-attribute instance-attribute
num_days = mapped_column(Integer, nullable=False)

Number of days this fee covers within the billing period.

period_end class-attribute instance-attribute
period_end = mapped_column(Date, nullable=False)
period_start class-attribute instance-attribute
period_start = mapped_column(Date, nullable=False)
premium_entry_id class-attribute instance-attribute
premium_entry_id = mapped_column(
    UUID(as_uuid=True), nullable=False
)
version class-attribute instance-attribute
version = mapped_column(Integer, nullable=False)