Skip to content

ccnl_engine.events

The work events of a run: pass them in PeriodFacts.events. Each changes gross, net and employer cost according to its treatment; see Work rules for the rules and the CCNL bands.

ccnl_engine.events.AbsenceEvent dataclass

Unpaid absence: deducted via EMPLOYEE_DEDUCTIONS; reduces INPS and TFR base.

Attributes:

Name Type Description
event_date date

Start date (or sole date) of the absence.

hours Decimal

Number of absent hours. Must be > 0.

hourly_rate Decimal

Rate at which the pay is deducted in EUR. Must be > 0.

end_date date | None

Last day of the absence range. None for single-day absences where event_date is both start and end. When set must be >= event_date.

suspends_accrual bool | None

True when the absence suspends the employment, so its calendar days do not accrue tredicesima and quattordicesima ratei (for example aspettativa non retribuita, or the congedo for serious family reasons of art. 4 c. 2 L. 53/2000); False when its days accrue the ratei. The caller states it: the engine does not decide which absences suspend accrual under the CCNL. None means not known: the days count as accruing, and a rateo they could change has a missing_fact blocker.

no_pay_due bool | None

True when no pay at all is due for every calendar day of the absence (aspettativa senza assegni): the days leave the days of the art. 13 TUIR deductions (AdE circ. 15/E/2007 par. 1.5.1: "vanno sottratti i giorni per i quali non spetta alcuna retribuzione"). False for a strike, an absence of hours or one whose days stay paid in part, which reduce nothing ("nessuna riduzione [...] in caso di giornate di sciopero"). None means not known: the days stay counted and a withholding run has a missing_fact blocker.

days property

Calendar days of the absence, first to last.

ccnl_engine.events.ArrearsEvent dataclass

Contract renewal arrears, taxed by the year they refer to.

Arrears of a tax year earlier than the run are taxed separately (art. 17 c. 1 lett. b TUIR; art. 19 c. 1 lett. b D.Lgs. 117/2026 from 2027) at :attr:separate_tax_rate; arrears of the tax year of the run are ordinary income of the run and the rate is not used.

Attributes:

Name Type Description
event_date date

Date the arrears are attributed to.

amount Decimal

Gross arrears amount in EUR. Must be >= 0.

separate_tax_rate Decimal

Caller-supplied rate of the separate taxation: the rate on half the income of the two years before the year of receipt (art. 21 c. 1 TUIR; art. 23 c. 1 D.Lgs. 117/2026 from 2027). Must be in [0, 1].

reference_period PeriodId | None

The competence period the arrears refer to. An earlier tax year selects the separate taxation, the tax year of the run the ordinary one, a later year is rejected. None leaves the taxation undetermined: the run taxes the arrears separately as a simulation, with a missing_fact blocker.

ccnl_engine.events.BilateralFundEvent dataclass

Bilateral or health fund contribution (fondi bilaterali/sanitari).

Both employee and employer portions are expressed as gross amounts. The employee portion reduces net pay; the employer portion increases employer cost.

Attributes:

Name Type Description
event_date date

Date the contribution is attributed to.

employee_amount Decimal

Employee-side contribution in EUR. Must be >= 0.

employer_amount Decimal

EmployerProfile-side contribution in EUR. Must be >= 0.

ccnl_engine.events.BonusEvent dataclass

One-off bonus: INPS + IRPEF (ordinary or substitute) + TFR excluded.

Attributes:

Name Type Description
event_date date

Date the bonus is attributed to.

amount Decimal

Gross bonus amount in EUR. Must be >= 0.

kind Literal['bonus', 'productivity_bonus', 'contract_renewal']

"productivity_bonus" routes the amount through the PdR substitute-tax regime (L. 208/2015 art. 1 cc. 182-190). "contract_renewal" marks a salary increment paid under a CCNL renewal, for the renewal substitute-tax regime (L. 199/2025 art. 1 c. 7). "bonus" (the default) applies ordinary IRPEF.

agreement_signed_on date | None

Signing date of the CCNL renewal a "contract_renewal" increment is paid under. The renewal substitute tax applies only to renewals signed within the window of the regime (1 January 2024 to 31 December 2026); None means not known: ordinary IRPEF and a provisional result. Only allowed with kind="contract_renewal".

The prior-year income and the written waiver the regimes check are declared once in :class:~ccnl_engine.irpef.declaration.inputs.PriorYearTaxFacts.

ccnl_engine.events.FringeEvent dataclass

Fringe benefit (art. 51 co. 3 TUIR).

The annual exemption threshold is resolved by calculate_period from the year-level VariablePayRules.fringe_benefit policy — it is not carried on the event itself. Taxability is determined cumulatively across all fringe events in the year (YTD + current period).

Attributes:

Name Type Description
event_date date

Date the benefit is attributed to.

amount Decimal

Value of the fringe benefit in EUR. Must be >= 0.

ccnl_engine.events.HolidayWorkEvent dataclass

Holiday or weekly rest-day supplement: INPS + IRPEF on the supplement.

Covers the maggiorazioni and indennita for work on public holidays and on weekly rest days as identified by the CCNL, eligible for the 15% substitute tax within the 1,500 EUR annual cap. TFR is not accrued on holiday supplements under the standard Italian treatment (art. 2120 c.c. excludes accidental pay).

Attributes:

Name Type Description
event_date date

Calendar date the holiday or rest day was worked.

supplement_amount Decimal

Flat supplement for the day in EUR. Must be >= 0.

ccnl_engine.events.NightShiftEvent dataclass

Night-work supplement: INPS + IRPEF on the supplement amount.

Covers the maggiorazioni and indennita for night work (D.Lgs. 66/2003 art. 1 c. 2 and the CCNL), eligible for the 15% substitute tax within the 1,500 EUR annual cap.

Attributes:

Name Type Description
event_date date

Calendar date the shift was worked.

supplement_amount Decimal

Flat supplement for the night period in EUR. Must be >= 0.

ccnl_engine.events.OvertimeEvent dataclass

Overtime hours: INPS + IRPEF + TFR on computed gross.

Attributes:

Name Type Description
event_date date

Calendar date the overtime was worked.

hours Decimal

Number of overtime hours, above 0 and at most the 744 hours of a month of 31 days.

hourly_rate Decimal

Base hourly rate in EUR. Must be > 0.

multiplier Decimal | None

Overtime multiplier applied to the hourly rate (e.g. 1.25 for 25% supplement). Must be > 0. None (the default) derives it from the CCNL band of kind as 1 + band; the run is rejected when the CCNL has no single percentage band for it. An explicit value prevails over the CCNL band.

kind OvertimeKind

When the hours were worked, selecting the CCNL band.

ccnl_engine.events.OvertimeKind

Bases: StrEnum

When overtime hours were worked, selecting the CCNL overtime band.

The values match the work kinds the CCNL time_supplements bands apply to.

Attributes:

Name Type Description
WEEKDAY

Daytime overtime on a working day (straordinario diurno).

NIGHT

Night overtime (straordinario notturno).

HOLIDAY

Overtime on a public holiday or rest day (straordinario festivo).

REST_DAY

Overtime on the weekly rest day (Sunday, or the day the rest moves to) where the CCNL pays it apart from the public holidays; a CCNL without a rest-day band pays it as HOLIDAY.

NIGHT_HOLIDAY

Night overtime on a public holiday (straordinario festivo notturno).

ccnl_engine.events.PeriodId dataclass

Identifies a single payroll period by calendar year and month.

Use this instead of relying on structural.employment.as_of to identify the competence period. Both the period calculation request and :class:~ccnl_engine.period.results.PeriodResult carry a period_id so consumers can match requests to results without parsing dates.

Attributes:

Name Type Description
year int

Calendar year (e.g. 2026).

month int

Month of competence, 1-12.

ccnl_engine.events.ShiftWorkEvent dataclass

Shift-work allowance: INPS + IRPEF on the supplement amount.

Covers the indennita di turno and the other shift-work pay set by the CCNL, eligible for the 15% substitute tax within the 1,500 EUR annual cap. TFR is not accrued, as for the other work-time supplements.

Attributes:

Name Type Description
event_date date

Calendar date the shift was worked.

supplement_amount Decimal

Shift allowance in EUR. Must be >= 0.

ccnl_engine.events.SickLeaveEvent dataclass

Sick pay amount set by the caller: an explicit, never payable override.

The engine computes sickness from a :class:~ccnl_engine.sickness.models.SicknessEpisode. This event overrides that computation with an employer-paid amount the caller computed; the run records a caller-supplied decision for the sickness capability, so its result is not payable. The amount is subject to INPS and IRPEF but not TFR accrual.

The engine deducts the carenza (waiting-period) portion from amount: net = amount - (amount / sick_days * waiting_period_days).

Attributes:

Name Type Description
event_date date

First day of the sick-leave period.

amount Decimal

Total employer-liable sick-leave gross in EUR, before carenza deduction.

sick_days int

Total working days of the sick-leave spell. Must be >= 1. Used to compute the daily rate for the carenza deduction. Defaults to 1.

waiting_period_days int

Number of carenza days (waiting period) at the start of the sick-leave period. Must not exceed sick_days. Defaults to 0 (no carenza).

ccnl_engine.events.SicknessEpisode dataclass

One sickness episode, a work event of every run whose month it touches.

Attributes:

Name Type Description
episode_id str

Stable identifier of the episode, the same in every run (e.g. the protocol number of the first certificate).

started_on date

First day of illness.

ended_on date

Last day of illness on the certificates known so far. A later run may pass a later day when the illness is extended.

relapse_of str | None

Identifier of the episode this one continues, when the certificate marks it as a relapse (ricaduta): the days of both count as one episode, so no new waiting period applies.

short_absence_exempt bool | None

Whether the CCNL exempts the absence from the lower pay of repeated absences (for Federmeccanica: a hospital stay or day hospital, sickness during a certified pregnancy, or one of the diseases the CCNL lists; for Commercio, Art. 187: a hospital stay, day hospital or dialysis, an initial prognosis of at least 12 days, the listed diseases, or a pregnancy); None when not stated. Read only by a CCNL that reduces short absences or the carenza by event, when the reduction could apply.

hospital_stays tuple[tuple[date, date], ...] | None

Hospital stays within the episode, each its first and last day; () for none, None when not stated. Read only by a CCNL that pays long stays in full.

serious_illness bool | None

Whether the illness is one the CCNL treats as particularly serious (Logistica: INPS circ. 95/2016); None when not stated. Read only by a CCNL with such a treatment.

periodic_check bool | None

Whether the absence is a periodic check of a worker who had an invalidating illness (Concia art. 60 B), which a CCNL may leave out of the comporto; None when not stated.

daily_contributions int | None

Daily contributions of the worker from 1 January of the year before the episode, every employer counted (spettacolo: art. 66 D.L. 73/2021); None when not stated. Read only by an INPS regime with a requirement.

prior_worked_days int | None

Days of work activity of a fixed-term worker in the 12 months before the episode, with every employer (D.L. 463/1983 art. 5 c. 1); None when not stated. Read only for a fixed-term contract, which pays sickness for no more days.

Raises:

Type Description
InvalidInputError

When the identifier is blank, a day is not a date, short_absence_exempt is not a bool, prior_worked_days is not an int in [0, 366], the episode ends before it starts or continues itself.

event_date property

First day of the episode: the date of the event.

days property

Calendar days from :attr:started_on to :attr:ended_on.

long_stay_days(more_than, day)

Return the days up to day of the stays longer than more_than.

Returns:

Type Description
int

The days from the start of each such stay to day, the stay

int

of day included; zero when day is in no such stay.

within(first, last)

Return the days of the episode from first to last.

Returns:

Type Description
tuple[date, date] | None

The first and last sick day of the interval, None when the

tuple[date, date] | None

episode does not touch it.

through(day)

Return the episode cut at day, the last day processed.

Returns:

Type Description
SicknessEpisode

The episode ending on day when it lasts beyond it.

before(day)

Return the part of the episode before day.

Returns:

Type Description
SicknessEpisode | None

The episode cut on the day before day, None when it

SicknessEpisode | None

starts on or after day.

ccnl_engine.events.StandbyEvent dataclass

Standby (reperibilità) paid at the CCNL rates of the worker's level.

The time of the calls and of the intervention is not standby: it is paid as overtime or ordinary hours with their own events.

Attributes:

Name Type Description
event_date date

Date the standby is attributed to: the rates in force on it apply.

kind StandbyKind

Unit of the standby.

quantity Decimal

Hours, days or weeks of the unit, above 0.

calls int

Calls followed by an intervention, each paid the CCNL fee.

ccnl_engine.events.StandbyKind

Bases: StrEnum

Unit of a standby period, selecting the CCNL rate.

Attributes:

Name Type Description
HOURS

Hours of standby, paid at the working-day rate per hour.

WORKED_DAY

Day of 16 hours on a working day.

REST_DAY

Day of 24 hours on a rest day.

HOLIDAY

Day of 24 hours on a public holiday.

WEEK

Week of 6 days.

WEEK_HOLIDAY

Week of 6 days with a public holiday.

WEEK_HOLIDAY_REST_DAY

Week of 6 days with a public holiday and a rest day.

ccnl_engine.events.TerminationTFREvent dataclass

TFR settlement at cessazione (art. 19 TUIR, tassazione separata).

The caller supplies the applicable tax rate (determined via art. 19 TUIR using the employee's prior-year average IRPEF rate).

Attributes:

Name Type Description
event_date date

Date of cessazione.

amount Decimal

Total TFR payout in EUR. Must be >= 0.

separate_tax_rate Decimal

Applicable tassazione separata rate. Must be in [0, 1].

ccnl_engine.events.TravelAllowanceEvent dataclass

Daily travel allowance (indennità di trasferta) of a block of days.

The allowance outside the comune is income only above the daily cap of art. 51 c. 5 TUIR, for IRPEF and INPS alike (art. 12 c. 2 L. 153/1969); within the comune it is income in full. One event covers days with the same daily amount and the same conditions. Analytic reimbursements and travel costs are not pay and are not events.

Attributes:

Name Type Description
event_date date

Date the block of days is attributed to.

days int

Days of trasferta, at least 1.

outside_municipality bool

Whether the trasferta is outside the comune of the place of work: within it no part is exempt.

meals_lodging Literal['none', 'one', 'both']

"one" when meals or lodging are reimbursed or provided free, "both" when both are, "none" otherwise: the cap is reduced by one third or by two thirds. Required: "none" gives the largest exemption.

daily_amount Decimal | None

Allowance paid for each day in EUR, above 0; None takes the CCNL amount for :attr:hours_away.

hours_away Decimal | None

Hours away of each day, read with daily_amount None to select the CCNL span.

tfr_base Literal['none', 'whole', 'above_exempt'] | None

What enters the TFR base: "none", "whole", or "above_exempt" (the part above the exemption); None takes the CCNL rule, required without one.

abroad bool

Whether the trasferta is abroad, with the higher cap.

trasfertista bool

Whether the worker is bound by contract to work in places always different (art. 51 c. 6 TUIR, 50% exempt): not supported, the event is rejected.

Raises:

Type Description
InvalidInputError

When a field is invalid, neither daily_amount nor hours_away is given, or trasfertista is True.

ccnl_engine.events.WelfareEvent dataclass

Welfare benefit: exempt from INPS and IRPEF, no TFR accrual.

Attributes:

Name Type Description
event_date date

Date the benefit is attributed to.

amount Decimal

Value of the welfare benefit in EUR. Must be >= 0.

ccnl_engine.events.WorkEvent = OvertimeEvent | NightShiftEvent | HolidayWorkEvent | ShiftWorkEvent | StandbyEvent | AbsenceEvent | SickLeaveEvent | SicknessEpisode | BonusEvent | FringeEvent | TravelAllowanceEvent | WelfareEvent | ArrearsEvent | BilateralFundEvent | TerminationTFREvent module-attribute