Api reference
components.premium.public.api ¶
PremiumAggregationService ¶
Retrieve premiums, no matter which engine and storage format were used.
get_uninvoiced_premiums
staticmethod
¶
Retrieve premium entries with uninvoiced components, checking specifically if the company or primary part is invoiced.
Returns complete premium entries where at least one component has not been invoiced yet. The debtor is inferred from the contract type: - Policy: primary policy holder - Contract → company
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
policy
|
Policy | None
|
Policy to retrieve premiums for (mutually exclusive with contract). |
None
|
contract
|
Contract | None
|
Contract to retrieve premiums for (mutually exclusive with policy). |
None
|
up_to
|
date
|
Only returns entries where period_end <= up_to. |
required |
Returns:
| Type | Description |
|---|---|
list[PremiumEntry]
|
List of complete PremiumEntry objects with uninvoiced components. |
Source code in components/premium/public/api.py
mark_premiums_as_invoiced
staticmethod
¶
Mark premium entries as invoiced by setting invoice_id on matching components.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
session
|
Session
|
Database session. |
required |
premium_entries
|
list[PremiumEntry]
|
List of premium entries to mark as invoiced. |
required |
invoice_id
|
UUID
|
The invoice ID to set on matching components. |
required |
debtor
|
InsuranceBilledEntity
|
The billed entity whose components should be marked as invoiced. |
required |
Source code in components/premium/public/api.py
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
components.premium.public.commands ¶
components.premium.public.dependencies ¶
COMPONENT_NAME
module-attribute
¶
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_app_dependency ¶
Function used to fetch the dependencies from the flask app.
Source code in components/premium/public/dependencies.py
set_app_dependency ¶
Function used to actually inject the dependency class in the component.
Source code in components/premium/public/dependencies.py
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
¶
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 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 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
¶
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. |
EngineParameters
dataclass
¶
EngineParameters(
*,
age_strategy,
rounding_strategy,
prorata_strategy,
default_child_age,
default_adult_age
)
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
default
staticmethod
¶
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
default_adult_age
instance-attribute
¶
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.
FeeComponent
dataclass
¶
Bases: CostComponent
A fee component represents one part of a fee that we intend to bill to a customer.
__eq__ ¶
Source code in components/premium/internal/domain/fee.py
__hash__ ¶
Source code in components/premium/internal/domain/fee.py
amount_before_prorata
instance-attribute
¶
Amount for full period coverage without prorata applied. Expressed in the minor unit of the currency. This is the full monthly amount that would be charged for complete period coverage.
as_tuple ¶
Return (billed_entity, contribution_type, amount)
id
class-attribute
instance-attribute
¶
Unique identifier of the entry
inverted ¶
Returns a new FeeComponent offsetting the current one.
Source code in components/premium/internal/domain/fee.py
invoice_id
instance-attribute
¶
If the component is included in an invoice, it is represented here.
LegacyBelgianNormalization
dataclass
¶
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
normalize_age ¶
Source code in components/premium/internal/domain/age_normalization.py
Policy ¶
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__ ¶
Source code in components/premium/internal/domain/fee.py
__hash__ ¶
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
cancelled_by_entry_id
class-attribute
instance-attribute
¶
components_billed_to_debtor ¶
Returns components that are actually billed to the specified debtor.
This method accounts for collection methods: - If debtor is company: includes company components AND primary components with payroll - If debtor is primary: only includes primary components with direct_billing
Source code in components/premium/internal/domain/fee.py
components_for_debtor ¶
The debtor is not necessarily the entity being billed
If a component's debtor is the primary but the collection method is payroll, the company gets billed.
If your purpose is to list components that should be invoiced to a given debtor,
use components_billed_to_debtor().
Source code in components/premium/internal/domain/fee.py
pretax_amount_billed_to_debtor ¶
Returns the total pretax amount (membership fees + costs) billed to the specified debtor.
This includes components with contribution_type of: - InsuranceContribution.membership_fee: Base membership fees - InsuranceContribution.cost: Insurance coverage costs
This method accounts for collection methods: - If debtor is company: includes company components AND primary components with payroll - If debtor is primary: only includes primary components with direct_billing
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
debtor
|
InsuranceBilledEntity
|
The entity to which costs are billed |
required |
Returns:
| Type | Description |
|---|---|
int
|
Total pretax amount in minor currency units |
Source code in components/premium/internal/domain/fee.py
prorata_ratio ¶
Returns the prorata ratio for this premium entry.
The ratio is calculated as: - 1.0 (or -1.0 for negative days) if the premium covers the full month - num_days / 30 otherwise (using 30-day convention, rounded to 2 decimals)
Uses arithmetic rounding (ROUND_HALF_UP) for consistency with invoicing display.
Returns:
| Type | Description |
|---|---|
float
|
Prorata ratio as a float. Positive for regular premiums, negative for credits/reversals. |
Source code in components/premium/internal/domain/fee.py
taxes_billed_to_debtor ¶
Returns the total tax amount billed to the specified debtor.
This includes components with contribution_type of: - InsuranceContribution.taxes: Tax components
This method accounts for collection methods: - If debtor is company: includes company components AND primary components with payroll - If debtor is primary: only includes primary components with direct_billing
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
debtor
|
InsuranceBilledEntity
|
The entity to which taxes are billed |
required |
Returns:
| Type | Description |
|---|---|
int
|
Total tax amount in minor currency units |
Source code in components/premium/internal/domain/fee.py
total_amount ¶
total_amount_billed_to_debtor ¶
Returns the total amount for components actually billed to the specified debtor.
This method accounts for collection methods: - If debtor is company: includes company components AND primary components with payroll - If debtor is primary: only includes primary components with direct_billing
Source code in components/premium/internal/domain/fee.py
total_amount_for_debtor ¶
The debtor is not necessarily the entity being billed
If a component's debtor is the primary but the collection method is payroll, the company gets billed.
If your purpose is to compute the total amount that should be invoiced to a given debtor,
use total_amount_billed_to_debtor().
Source code in components/premium/internal/domain/fee.py
total_billed_to_debtor_without_prorata ¶
Returns the total amount before prorata for components actually billed to the specified debtor.
This method accounts for collection methods: - If debtor is company: includes company components AND primary components with payroll - If debtor is primary: only includes primary components with direct_billing
Source code in components/premium/internal/domain/fee.py
total_for_debtor_without_prorata ¶
The debtor is not necessarily the entity being billed
If a component's debtor is the primary but the collection method is payroll, the company gets billed.
If your purpose is to compute the total amount without prorata that should be invoiced to a given debtor,
use total_billed_to_debtor_without_prorata().
Source code in components/premium/internal/domain/fee.py
with_components_marked_as_invoiced ¶
Returns a new PremiumEntry with components for the specified debtor marked as invoiced.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
invoice_id
|
UUID
|
The invoice ID to set on matching components. |
required |
debtor
|
InsuranceBilledEntity
|
The billed entity whose components should be marked as invoiced. |
required |
Returns:
| Type | Description |
|---|---|
PremiumEntry
|
New PremiumEntry with updated components. |
Source code in components/premium/internal/domain/fee.py
with_version ¶
Returns a new PremiumEntry with a different version.
Source code in components/premium/internal/domain/fee.py
PremiumEntryRepository ¶
Bases: Protocol
Repository protocol for persisting and retrieving premium entries.
get_all_entries ¶
Retrieve all premium entries for specified enrollments 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
get_all_uninvoiced_entries_up_to ¶
Retrieve premium entries that have uninvoiced components for a specific debtor.
An entry is included if it has at least one component where the debtor has not been invoiced (invoice_id IS NULL). The returned entries are complete - they contain all components regardless of their invoice status or debtor.
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 |
debtor
|
InsuranceBilledEntity
|
The billed entity (primary, company, etc.) to check for uninvoiced components. |
required |
up_to
|
date
|
Only returns entries where period_end <= up_to. |
required |
Returns:
| Type | Description |
|---|---|
list[PremiumEntry]
|
List of complete PremiumEntry objects. |
Source code in components/premium/internal/domain/repository.py
get_latest_entries ¶
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
insert ¶
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
update ¶
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
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
¶
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.
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.
__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 for num_days of coverage from period_start to period_end. Expressed in the minor unit of the currency.
amount_before_prorata
class-attribute
instance-attribute
¶
Amount for full coverage from period_start to period_end. Expressed in the minor unit of the currency. This is the amount that would be billed if we decided not to apply prorata.
beneficiary_type
class-attribute
instance-attribute
¶
cancelled_by_entry_id
class-attribute
instance-attribute
¶
cancelled_entry_id
class-attribute
instance-attribute
¶
collection_method
class-attribute
instance-attribute
¶
contribution_type
class-attribute
instance-attribute
¶
coverage_type
class-attribute
instance-attribute
¶
currency
class-attribute
instance-attribute
¶
ISO4217 compliant alpha code of the currency.
debtor_type
class-attribute
instance-attribute
¶
enrollment_id
class-attribute
instance-attribute
¶
invoice_id
class-attribute
instance-attribute
¶
num_days
class-attribute
instance-attribute
¶
Number of days this fee covers within the billing period.