Skip to content

ccnl_engine

The package root holds the common path: the facade, the request and plan types, the results the facade returns, the errors and the versions. Every other public name lives in one of the four namespaces: see API reference.

Entry point

ccnl_engine.PayrollEngine

Unified entry point for Italian CCNL payroll computation.

Pass explicit repository and policies arguments to inject custom knowledge and policy data, useful for testing or air-gapped deployments. Call :meth:bundled to create an engine backed by the package-bundled data.

The mode sets the payability policy of every result (see :class:~ccnl_engine.assurance.policies.EngineMode): "simulation" (the default) reports ruleset readiness, while "operational" also blocks payment from any ruleset that is not production. Both modes compute the same amounts.

Example::

from datetime import date
from ccnl_engine import (
    Employment, EmployerProfile, Headcount, PayrollEngine,
    PayrollRun, PeriodInput,
)

engine = PayrollEngine.bundled()
result = engine.calculate_period(PeriodInput(
    run=PayrollRun.regular(2026, 1),
    payment_date=date(2026, 1, 28),
    employment=Employment(
        ccnl_slug="metalmeccanico-federmeccanica.json",
        level_code="C3",
    ),
    employer=EmployerProfile(headcount=Headcount(50)),
))
print(result.is_payable, result.period_net)
for ruleset in result.rulesets:
    print(ruleset.id, ruleset.readiness)

mode property

Payability policy of the results of this engine.

bundled(*, mode='simulation') classmethod

Create an engine backed by the package-bundled knowledge data.

Parameters:

Name Type Description Default
mode EngineMode | Mode

"simulation" (the default) returns amounts with their assurance; "operational" also requires every ruleset that tracks readiness to be production.

'simulation'

Returns:

Name Type Description
A PayrollEngine

class:PayrollEngine instance using the shipped CCNL and

PayrollEngine

policy JSON files. The resolver is loaded once and cached on

PayrollEngine

the instance.

list_contracts() staticmethod

Return every bundled contract with its readiness tier.

Returns:

Type Description
tuple[ContractSummary, ...]

One summary per bundled CCNL, sorted by ccnl_id.

list_levels(ccnl_id)

Return the levels of one CCNL, each code as Employment takes it.

Parameters:

Name Type Description Default
ccnl_id str

Slug (with or without .json) or CNEL code; an unknown one raises UnknownCcnlError.

required

Returns:

Type Description
tuple[LevelSummary, ...]

One summary per level, in the order of the CCNL data.

inspect_ruleset(ccnl_id)

Return the identity, hash, readiness and confidence of a CCNL.

A run of the same CCNL reports the same assurance in result.rulesets, so a caller can check readiness before calculating.

Parameters:

Name Type Description Default
ccnl_id str

Slug (e.g. "metalmeccanico-federmeccanica", with or without .json) or CNEL code of a bundled CCNL.

required

Returns:

Type Description
RulesetAssurance

The assurance of the CCNL ruleset.

A ccnl_id that matches no bundled CCNL raises :class:~ccnl_engine.errors.UnknownCcnlError.

calculate_period(request)

Compute a single payroll run.

Parameters:

Name Type Description Default
request PeriodInput

The run, its payment date, the employment, the employer, the facts of the run, the prior-year facts and the opening state.

required

Returns:

Name Type Description
The PeriodResult

class:~ccnl_engine.period.results.PeriodResult:

PeriodResult

assurance and payability, issues, decisions, amounts, closing

PeriodResult

state, pay items, ledger entries and capability report.

calculate_competence_year(plan)

Compute every run of a competence year, in payment order.

The common case: twelve months and the extra months of the CCNL, each paid on the plan's payment day or date. The runs paid in the year settle its conguaglio on the last of them; a run paid in the next tax year (December paid after 12 January) opens it. See :func:~ccnl_engine.year.competence.services.calculate_competence_year.

Parameters:

Name Type Description Default
plan CompetenceYearPlan

The year, the employment, the employer, the prior-year facts, the facts per run, an optional calendar override, the payment day and dates, and the opening state.

required

Returns:

Type Description
CompetenceYearResult

One result per run and the annual totals;

CompetenceYearResult

next_opening_state opens the next competence year.

A calendar override that drops or lowers an extra month the CCNL grants, or does not match its reason, raises :class:~ccnl_engine.errors.InvalidInputError.

calculate_tax_year(plan)

Compute every payment cashed in a tax year, in payment order.

The payments of the competence years of plan attributed to its tax year, late payments of an earlier competence year included; the conguaglio falls on the last one. See :func:~ccnl_engine.year.tax_year.services.calculate_tax_year.

Parameters:

Name Type Description Default
plan TaxYearPlan

The tax year, its competence years and its opening state.

required

Returns:

Type Description
TaxYearResult

One result per payment computed, the payments of the year and

TaxYearResult

the conguaglio; next_opening_state opens the next tax year.

close_tax_year(closing_state) staticmethod

Open the next tax year from the closing state of the last run.

See :func:~ccnl_engine.year.tax_year.closing.rules.close_tax_year.

Parameters:

Name Type Description Default
closing_state PeriodState

closing_state of the last run of the year.

required

Returns:

Type Description
PeriodState

The opening state of the next tax year: a fresh tax year state

PeriodState

and the obligations still running.

import_opening_balances(balances) staticmethod

Return the state that opens a run after another provider's totals.

The one way to start from totals the engine did not compute: a mid-year takeover, the INPS base of the worker's other employers of the year, the competence runs of an earlier tax year a late December follows, or recoveries still running. The totals are verified against the payments that produced them.

Parameters:

Name Type Description Default
balances OpeningBalances

The totals, payments and obligations to import.

required

Returns:

Type Description
PeriodState

The opening state, bound to balances.tax_year.

Modes

PayrollEngine.bundled(mode=...) sets the payability policy of every result; both modes compute the same amounts. EngineMode is in ccnl_engine.inputs.

Mode Payable when
simulation (default) No blocker. Ruleset readiness is reported in result.rulesets, not enforced.
operational No blocker, and every ruleset that tracks readiness is production with a verified confidence. Otherwise the result carries one ruleset_not_production blocker per such ruleset (detail: the ruleset id), and the amounts stay inspectable.

An operational engine returns a result with blockers rather than refusing before the calculation: the amounts, the other blockers and the readiness of every ruleset remain visible, and a year aggregates its runs as in simulation. Readiness is tracked for CCNL rulesets only, so today the operational gate is the CCNL tier; tax, INPS and surtax rulesets report readiness = None and never raise it. A run whose CCNL has no ruleset identity fails closed with the detail no_ruleset_tracks_readiness.

Requests and plans

calculate_period takes a PeriodInput, calculate_competence_year a CompetenceYearPlan and calculate_tax_year a TaxYearPlan of competence years. They group the facts by owner and are validated when built; import_opening_balances takes the OpeningBalances of another provider:

Model Holds
Employment CCNL slug, level, contract type, category, EmploymentPeriod, weekly and full-time WeeklyHours, SeniorityFact, roles, ContributionHistory (IVS massimale eligibility), sector (None means unknown), PensionFundEnrolment or NoPensionFund (None means unknown)
EmployerProfile Headcount (required, no size is assumed) and activity (None means unknown)
PriorYearTaxFacts prior-year employment income and the regimes waived in writing, read by every substitute-tax regime and the PdR
CurrentYearTaxFacts income of the tax year beyond this employment, the main dwelling excluded, with its date and IncomeEstimateQuality; the Art. 12 family deductions add it to the employment income (None means unknown, a blocker when a dependent is entitled)
PeriodFacts events, contributable hours, region and Belfiore code, family composition, dependent children of one run

The other facts these types take are in ccnl_engine.inputs, the work events in ccnl_engine.events.

ccnl_engine.PeriodInput dataclass

Input of one payroll run.

Attributes:

Name Type Description
run PayrollRun

The run: its month, year and kind.

payment_date date

Date the run is paid. Selects the tax year (:class:~ccnl_engine.calendar.tax_year.rules.TaxYearPolicy).

employment Employment

Contract, level and worker facts.

employer EmployerProfile

The employer. Required: its headcount selects the INPS rate tier.

facts PeriodFacts

Facts of the run. Defaults to a run with no event and no surtax jurisdiction.

prior_year PriorYearTaxFacts

Prior-year income and waivers. Defaults to unknown income and no waiver.

current_year CurrentYearTaxFacts | None

Income of the tax year beyond this employment, which the family deductions add to the employment income of the year to get the reddito complessivo, and the INPS base of the other employments of the year. None means not known: with a dependent that gives right to a deduction, or INPS rules with a massimale or a 1% threshold and no base of other employments in opening_state, the result is not payable.

opening_state PeriodState

State entering the run, with the history of the employment. The default :meth:~ccnl_engine.balance.models.PeriodState.zero is the fact only for the first run of an employment whose employment_period starts in the run month; pass the closing_state of the previous run within a tax year, close_tax_year() of the last run of the previous year, or imported balances. A state that misses the history gives a missing_fact opening_state blocker.

planned_payments tuple[PaymentId, ...] | None

Payments of the same tax year still planned after this one, in payment order, when they differ from the CCNL standard calendar. () makes this payment the conguaglio: pass it on the last payment of a tax year whose December is paid after 12 January. None (the default) projects the standard runs that follow this run and are not yet paid.

Raises:

Type Description
InvalidInputError

When a field is not of its type, a regular run falls outside the employment, the payment precedes the run month, or opening_state belongs to another tax year.

calculation_request(*, extra_month_accrual=None, extra_month_settlements=None, withholding_schedule=None, uncovered_runs=())

Map this input to the request of the period calculation.

The only mapping from the public input to the internal request, used by both the single-run and the year calculation.

Parameters:

Name Type Description Default
extra_month_accrual ExtraMonthAccrual | None

Rateo of an extra-month run, supplied by the year calculation.

None
extra_month_settlements tuple[ExtraMonthAccrual, ...] | None

Ratei liquidated on this run because the employment ends before their payment month, supplied by the year calculation. None derives them from the CCNL calendar.

None
withholding_schedule WithholdingSchedule | None

Withholding slots of the tax year. None uses the standard calendar of the CCNL.

None
uncovered_runs tuple[PayrollRunId, ...]

Runs of the year the year calculation left out because the bundle holds no pay rules on their date.

()

Returns:

Type Description
PeriodCalculationRequest

The validated request.

ccnl_engine.PeriodFacts dataclass

Facts that hold in one payroll run.

Attributes:

Name Type Description
contributable_hours ContributableHours | None

Hours worked and paid in the run that are subject to INPS contributions. Required for domestic CCNLs.

ordinary_hours_worked ContributableHours | None

Ordinary hours actually worked in the month, sickness, ferie, permits, festività and other paid absences left out: the hours a CCNL with hourly_pay pays its worker (the operai of the building CCNLs) and the base of the Prevedi contractual contribution of an operaio. None is unknown: an operaio then has a missing_fact blocker. An AbsenceEvent of a worker paid by the hour is rejected: its hours are already left out of them.

events tuple[WorkEvent, ...]

Variable work events of the run (overtime, absences, bonuses, supplements), each one of the :data:~ccnl_engine.event.types.WorkEvent types. A list is accepted and stored as a tuple.

regione str | None

ISO 3166-2:IT region code for the regional surtax, e.g. "IT-45", "IT-BZ" / "IT-TN" for the autonomous provinces. None is unknown: when the employer withholds, a residence_unknown decision and a requirement_unresolved blocker on addizionale_regionale.

comune_belfiore str | None

Belfiore code for the municipal surtax, e.g. "F257". None is unknown: when the employer withholds, a residence_unknown decision and a requirement_unresolved blocker on addizionale_comunale.

family_composition FamilyComposition | None

Dependents for the Art. 12 TUIR deductions. None is unknown: when the employer withholds, a requirement_unresolved blocker on family_deductions; FamilyComposition() states that there is no dependant. Its children also select the fringe-benefit threshold: the higher one when a child is within the own-income limit of art. 12 c. 2 TUIR (L. 207/2024 art. 1 c. 390).

Raises:

Type Description
InvalidInputError

When a field is not of its type, an event is not a work event, or a surtax code is malformed.

ccnl_engine.PayrollRun dataclass

Identity and classification of one payroll computation.

Attributes:

Name Type Description
run_kind RunKind

Classification of the run type:

  • RunKind.REGULAR — ordinary monthly salary period.
  • RunKind.THIRTEENTH — tredicesima mensilità.
  • RunKind.FOURTEENTH — quattordicesima mensilità.
  • RunKind.ADJUSTMENT — conguaglio correction run.
  • RunKind.TERMINATION — cessazione run including TFR settlement.
month int

Calendar month (1-12) of the run.

year int

Year of the run month. The tax year follows from the payment date (:class:~ccnl_engine.calendar.tax_year.rules.TaxYearPolicy) and can be the next year when the run is paid late.

sequence int

Number of the run among the runs of its kind and month, from 1. Above 1 only for a second or later adjustment run of the month (:meth:adjustment).

run_id str

Unique, deterministic identifier derived from year, month, kind and sequence, e.g. "2026-01-regular" or "2026-12-adjustment-2". Computed automatically; do not pass to the constructor.

identifier property

Typed identifier of the run; str() of it is :attr:run_id.

of(run_id) classmethod

Return the run run_id identifies.

Returns:

Name Type Description
A PayrollRun

class:PayrollRun whose :attr:identifier is run_id.

regular(year, month) classmethod

Create a regular monthly run for the given year and month.

Parameters:

Name Type Description Default
year int

Year of the run month.

required
month int

Calendar month (1-12).

required

Returns:

Name Type Description
A PayrollRun

class:PayrollRun with run_kind=RunKind.REGULAR and a

PayrollRun

deterministic run_id.

thirteenth(year, payment_month) classmethod

Create a tredicesima run paid in the given calendar month.

Parameters:

Name Type Description Default
year int

Year of the run month.

required
payment_month int

Calendar month in which the tredicesima is paid.

required

Returns:

Name Type Description
A PayrollRun

class:PayrollRun with run_kind=RunKind.THIRTEENTH.

fourteenth(year, payment_month) classmethod

Create a quattordicesima run paid in the given calendar month.

Parameters:

Name Type Description Default
year int

Year of the run month.

required
payment_month int

Calendar month in which the quattordicesima is paid.

required

Returns:

Name Type Description
A PayrollRun

class:PayrollRun with run_kind=RunKind.FOURTEENTH.

adjustment(year, month, sequence=1) classmethod

Create an adjustment run correcting a run of the given month.

Parameters:

Name Type Description Default
year int

Year of the run month.

required
month int

Calendar month (1-12) of the run corrected.

required
sequence int

Number of the adjustment within the month: 1 for the first, 2 for a second correction of the same month, and so on. Each closes once.

1

Returns:

Name Type Description
A PayrollRun

class:PayrollRun with run_kind=RunKind.ADJUSTMENT.

ccnl_engine.Employment dataclass

The employment relationship: contract, level and worker facts.

Facts are validated on construction: a value of the wrong type or an impossible combination raises :class:~ccnl_engine.errors.InvalidInputError instead of producing a payslip.

Attributes:

Name Type Description
ccnl_slug str

Knowledge-bundle CCNL filename, e.g. "metalmeccanico-federmeccanica.json": lower-case letters, digits and hyphens, then .json. A name the bundle does not hold raises :class:~ccnl_engine.errors.UnknownCcnlError when the run loads it.

level_code str

Contractual level code, e.g. "C3".

contract_type Permanent | Apprentice | FixedTerm

:class:Permanent, :class:FixedTerm or :class:Apprentice, always stated: it selects the NASpI surcharge of a fixed-term contract and the art. 13 TUIR deduction minimum.

category WorkerCategory | None

Worker category; its string value (e.g. "operaio") is accepted and normalized. None takes the category fixed by the level, if any. The calculation raises when the category differs from the one the level fixes, or when it is None and seniority increments for the level differ by category.

employment_period EmploymentPeriod | None

Start and optional end of the employment. None when not tracked: a year then computes every run of the calendar with full ratei.

weekly_hours WeeklyHours | None

Contracted weekly hours. Required for domestic CCNLs to select the INPS bracket; below full_time_weekly_hours it scales the pay for part time.

full_time_weekly_hours WeeklyHours | None

Full-time weekly hours of the contract. weekly_hours must not exceed it.

seniority SeniorityFact | None

Recognised seniority, aged by the engine to each run. None means not known: a run whose level pays seniority increments or service-gated allowances then has a missing_fact blocker, and its amounts leave them out.

roles frozenset[str] | None

Role codes that unlock role-specific contractual allowances, each a non-blank string. A set is accepted and stored as a frozenset; an empty set states that the worker holds no role. None means not known: a run whose level has an allowance restricted to a role then has a missing_fact blocker, and its amounts leave the allowance out.

contribution_history ContributionHistory | None

First enrolment in a mandatory pension scheme and contributory option, from which the engine derives whether the IVS massimale applies. None means not known: a run whose INPS base crosses the massimale then has an undetermined contribution and a missing_fact blocker.

sector EmploymentSector | None

Private or public sector of the employment, for the regimes restricted to one sector. None means not known: those regimes are then unknown and the result provisional. It is not derived from the CCNL: a public employer may apply a private CCNL.

pension_fund PensionFundEnrolment | NoPensionFund | None

Enrolment in a complementary pension fund of the CCNL, or :class:~ccnl_engine.pension_fund.inputs.NoPensionFund to state that the worker is not enrolled: no fund contribution is computed, and on a CCNL that has funds the pension_fund_contribution capability records the reason not_enrolled. None means not known: on every CCNL but domestic work the contributions are undetermined and the run has a missing_fact blocker.

tfr_fund TfrFundBalance | None

TFR fund at 31 December of the year before the run, the base of the revaluation at 31 December (art. 2120 c. 4 c.c.). None means not known: the December run then has a missing_fact blocker, unless the employment starts in the year of the run (no fund to revalue).

tfr_treasury_fund bool | None

Whether the TFR not paid to a pension fund is paid to the Fondo Tesoreria INPS (L. 296/2006 art. 1 c. 756): the employer is obliged by its size and the worker is not excluded (DM 30 gennaio 2007 art. 1 cc. 5-8). None means not known: a run that accrues TFR in the company then has a missing_fact blocker. Domestic work and the public administrations are outside the Fondo: True there raises InvalidInputError, None and False keep the TFR in the company.

erc_amount Decimal | None

Annual Elemento di Raccordo Contrattuale of the CCNL grafici editoriali (renewal of 19 January 2021), frozen in December 2020; zero when the worker has none. It is paid with the tredicesima, by its months, and sets the Byblos employer rate (1.4% with one, 1.9% without). None means not known, zero for an employment that started after December 2020: an enrolled run, or a run paying the tredicesima, on that CCNL has a missing_fact blocker.

public_end_of_service PublicEndOfService | None

End-of-service regime of a public employee (TFS, TFR at INPS or TFR at the employer), which sets the contributions to INPS Gestione Dipendenti Pubblici and whether the run accrues the TFR. None means not known: a run on a CCNL of the public administrations has a missing_fact blocker.

Raises:

Type Description
InvalidInputError

When a field is not of its type, a role is not a non-blank string, weekly_hours exceeds full_time_weekly_hours, or category or sector names no known value.

check_seniority_in(year, month)

Reject a seniority whose recognised service starts after a month.

The run of the month ages :attr:seniority to it; checking on the input rejects a seniority that cannot be aged to the first run before any calculation, with :class:~ccnl_engine.errors.InvalidInputError.

Parameters:

Name Type Description Default
year int

Year of the competence month of the run.

required
month int

Competence month of the run, 1-12.

required

ccnl_engine.EmployerProfile dataclass

The employer of the worker being paid.

The only employer model of the payroll pipeline. The INPS classification of the employer follows from the CCNL, so the headcount is the only contribution fact the employer declares.

Attributes:

Name Type Description
headcount Headcount

Employer headcount, used to select the INPS contribution tier. Required: no size is assumed.

activity EmployerActivity | None

Activity of the employer, for the regimes that exclude some activities. None means not known: the night, holiday and shift substitute tax (L. 199/2025 art. 1 c. 11) excludes the activities of c. 18, so its eligibility is then unknown.

public_life_insurance bool | None

Whether a public employer enrols its staff in the Assicurazione Sociale Vita (ex ENPDEP): every "ente dotato di personalità giuridica di diritto pubblico" except the State, the Province, the Comuni and the enti di assistenza e beneficenza (INPS circ. 104/2014). None takes the value the CCNL fixes; when it fixes none, a run of the public administrations has a missing_fact blocker.

fis_reduction bool | None

Whether an employer of the fondo di integrazione salariale with on average up to five employees has its rate cut by 40% for not having applied for the assegno di integrazione salariale in the last twenty-four months (D.Lgs. 148/2015 art. 29 c. 8-bis). None means not known: a run of such an employer has a missing_fact blocker and is charged the full rate.

cigs_indotto bool | None

Whether a craft firm with more than fifteen employees works in the indotto of a firm with the prevailing management influence, owing the CIGS contribution (D.Lgs. 148/2015 art. 20 c. 1 lett. b, art. 23 c. 1). None means not known: a run of such an employer has a missing_fact issue and is charged without it.

provincial_pay_element bool | None

Whether a provincial pay element of the CCNL (a terzo elemento provinciale) is in force where the worker works, replacing the national element the CCNL pays only in its absence (Commercio Art. 215). None means not known: a level with such a national element leaves it out and has a missing_fact blocker.

agricultural_zone AgriculturalZone | None

Zone of the land of an agricultural employer, which cuts its INPS contributions by 68% in a zona svantaggiata and 75% in a zona particolarmente svantaggiata (INPS circ. 43/2026 par. 7). None means not known: an agricultural run is charged the full rates and has a missing_fact blocker.

Raises:

Type Description
InvalidInputError

When headcount is not a :class:Headcount, activity is not an :class:EmployerActivity value, agricultural_zone not an :class:AgriculturalZone value or public_life_insurance, fis_reduction or provincial_pay_element is not a bool.

ccnl_engine.Headcount dataclass

Employer headcount used to select INPS contribution tiers.

At least one: the worker being paid is an employee of the employer.

Attributes:

Name Type Description
value int

Number of employees, >= 1.

Raises:

Type Description
InvalidInputError

When value is not an int or is below 1.

ccnl_engine.CompetenceYearPlan dataclass

The runs of one competence year, their facts and when each is paid.

The runs follow from the calendar and the employment period: the twelve months and the extra months of :attr:year. Each run takes its :class:PeriodFacts from :attr:periods and, when it has no entry, from :attr:default_facts. Each run is paid on :attr:payment_day of its own month unless :attr:payment_dates says otherwise; the payment date sets the tax year of the run (TUIR art. 51 c. 1), so December paid on 13 January of the next year is income of the next tax year.

Attributes:

Name Type Description
year int

The competence year of the runs.

employment Employment

Contract, level and worker facts.

employer EmployerProfile

The employer. Required: its headcount selects the INPS rate tier.

prior_year PriorYearTaxFacts

Prior-year income and waivers. Defaults to unknown income and no waiver.

current_year CurrentYearTaxFacts | None

Income beyond this employment of the tax year of the runs, read by the family deductions; runs paid in another tax year ignore it. Its INPS base of other employments counts toward the massimale of the runs of the same competence year. None means not known.

periods RunKeyed[PeriodFacts]

Facts per run, keyed by run id ("2026-12-thirteenth", any run kind) or by month number (1-12, the regular run of the month). :attr:facts_by_run holds them keyed by run id. The plan keeps a read-only copy: changing the mapping passed in, or mutating this one, cannot change the runs it calculates. An entry replaces :attr:default_facts for its run: repeat the jurisdiction and family in it, e.g. with dataclasses.replace(default_facts, events=...).

default_facts PeriodFacts

Facts of every run without an entry in :attr:periods, extra-month runs included. Must carry no event.

calendar_override CalendarOverride | None

A calendar that replaces the CCNL standard one, with its reason. None runs the standard calendar. An override that drops or lowers an extra month the CCNL grants, or does not match its reason, raises when the year is calculated.

payment_day int

Day of the run month on which a run is paid, 1-28, unless :attr:payment_dates names its date or the CCNL fixes the day of its quattordicesima (Commercio: 1 July) and the plan has no :attr:calendar_override.

payment_dates RunKeyed[date]

Payment date per run, keyed like :attr:periods: {12: date(2027, 1, 13)} pays the December salary on 13 January 2027; an employer that pays in arrears names every month. A date before the first day of the run month is rejected.

opening_state PeriodState | None

State the first run opens with, read by calculate_competence_year. None is the zero state, the fact only for an employment whose stated start falls in :attr:year; otherwise the runs have a missing_fact opening_state blocker. Pass close_tax_year() of the previous tax year, imported balances, or the next_opening_state of the previous competence year when its December was paid in this tax year. A state that already closed some runs of :attr:year with the same payment resumes after them. Leave it None in a TaxYearPlan, which carries its own.

Raises:

Type Description
InvalidInputError

When a field is not of its type, a key of :attr:periods or :attr:payment_dates is not a month or a run id of :attr:year, two keys name the same run, :attr:default_facts carries events, a payment date precedes its run month, or payment_day is outside 1-28.

facts_by_run property

Entries of :attr:periods keyed by run id, e.g. "2026-03-regular".

dated_runs property

Run ids :attr:payment_dates names.

facts_for(run)

Return the facts of run.

Returns:

Type Description
PeriodFacts

The entry of :attr:periods for the run, else

PeriodFacts

attr:default_facts.

payment_for(run)

Return the payment of run: the run and the day it is paid.

Returns:

Type Description
PaymentId

The entry of :attr:payment_dates for the run, else

PaymentId

attr:payment_day of the run month.

ccnl_engine.TaxYearPlan dataclass

Every payment of one tax year, drawn from its competence years.

The payments of the tax year are the runs of :attr:competence_years whose payment date falls in :attr:tax_year under the cassa allargata rule (paid by 12 January for a period of the year before: that year), plus the payments already closed in :attr:opening_state. They are computed in order of payment date, ties in run order. The conguaglio (art. 23 c. 3 DPR 600/1973) falls on the last payment of the tax year: a late December paid on 13 January comes before the standard runs, a late payment in July among them, one paid after the tredicesima after them, and the conguaglio follows in every case.

Attributes:

Name Type Description
tax_year int

The tax year.

competence_years tuple[CompetenceYearPlan, ...]

Plans of the competence years paid in the tax year, at most one per year, none after :attr:tax_year: usually the year before (for a December paid in January) and the tax year itself. Their own opening_state must be None.

opening_state PeriodState | None

State the first payment opens with: None (the zero state) only for an employment whose stated start falls in the plans, else the payments have a missing_fact opening_state blocker; close_tax_year() of the previous tax year, imported balances, or a state of :attr:tax_year that already closed some of the payments; those are not computed again (resume after a retry).

current_year CurrentYearTaxFacts | None

Income of :attr:tax_year beyond this employment and the INPS base of the other employments, read by every payment in place of the current_year of the competence years. None keeps theirs.

Raises:

Type Description
InvalidInputError

When a field is not of its type, there is no competence year, two plans share a year, a plan is of a year after :attr:tax_year or carries an opening state, or :attr:current_year is of another tax year.

Year calendar

CompetenceYearPlan derives the calendar from the CCNL when calendar_override is omitted. A different calendar is accepted only as a validated CalendarOverride.

Results

What a result says about its own reliability (assurance, blockers, decisions, the capability report) is described in ccnl_engine.results.

ccnl_engine.PeriodResult dataclass

Result of one period-first payroll calculation.

Attributes:

Name Type Description
period_id PeriodId

The competence period, identical to the request.

payment_date date

Payment date, identical to the request.

period_gross Decimal

Contractual gross entitlement for this period (sum of CASH_EARNINGS ledger entries). This is the theoretical wage the worker is entitled to before absence deductions.

period_net Decimal

Net pay for this period only.

period_employer_cost Decimal

Employer cost net of unpaid absences: period_gross - unpaid_absence_deduction + employer_contributions + bilateral_fund_employer + tfr_accrual + non_cash_benefits + pension_fund_employer + pension_fund_tfr + tfr_treasury_fund. It leaves out the INAIL premium, which rests on the tariff rate of the employer, and IRAP. It is complete within that perimeter only when :attr:is_employer_cost_complete: an amount the CCNL owes for every worker that the engine does not compute (a health fund) leaves it short.

unpaid_absence_deduction Decimal

Sum of EMPLOYEE_DEDUCTIONS ledger entries. Represents wages not paid due to unpaid absences or sickness. Zero when no absences are present.

closing_state PeriodState

State after closing this period: the tax year state and the obligations. Pass as opening_state to the next run of the same tax year, or to :func:~ccnl_engine.year.tax_year.closing.rules.close_tax_year after the last run of the year.

pay_items tuple[PayItem, ...]

All pay items produced for this period.

ledger_entries tuple[LedgerEntry, ...]

All ledger entries posted for this period.

contribution_breakdown ContributionBreakdown

Per-component INPS breakdown for audit and compliance tracing.

benefit_breakdown BenefitBreakdown

Per-axis fringe/welfare benefit breakdown for audit and cost-centre reporting.

capability_report CapabilityReport

Gaps between the capability catalog and what the run executed, with the provenance of the rules each capability read and the values the caller supplied.

issues tuple[CalculationIssue, ...]

Conditions that lower the reliability of this result, in the order they were raised. Empty when every capability decided from known rules and facts.

decisions tuple[CalculationDecision, ...]

What the capabilities that record a decision decided in this run, e.g. the eligibility of a pay item for a preferential tax regime, in the order they were taken.

rulesets tuple[RulesetAssurance, ...]

Assurance of the rulesets the run read: the CCNL, and each tax, INPS and surtax ruleset a payable rule came from, with identity, hash, readiness and confidence.

mode EngineMode

Payability policy of the engine that produced the result; operational adds a blocker for every ruleset short of production.

limitations tuple[ModelLimitation, ...]

Model limitations that concern the run (see :class:~ccnl_engine.limitation.models.ModelLimitation); an open one with a monetary impact blocks the amounts.

Whether the amounts can be paid is :attr:is_payable: the net pay (:attr:is_net_pay_payable) and the employer cost (:attr:is_employer_cost_complete) both reliable. Why not is :attr:blockers; all come from :attr:assurance.

assurance property

Assurance derived from what the run recorded and the mode.

It is derived on access, so an issue added to the result later (e.g. a partial month of a year) is reflected.

paid_gross property

Gross actually paid: period_gross less the unpaid absences.

period_gross is the contractual pay of the period with the earnings of its events (sick pay included) before the deduction of the days not paid; this is what the payslip pays as gross.

is_payable property

Whether nothing blocks the amounts of this result.

is_net_pay_payable property

Whether no blocker leaves the net pay of this result unreliable.

is_employer_cost_complete property

Whether no blocker leaves the employer cost of this result short.

blockers property

Every reason the amounts of this result cannot be paid.

remittance_summary()

Return the tax and credit amounts of the run by F24 codice tributo.

IRPEF withheld, surtax, substitute and separate taxes, credits paid and recovered, IRPEF refunded and recoveries carried for lack of pay, one line per account and code (see :func:~ccnl_engine.ledger.remittance.models.remittance_summary).

Returns:

Type Description
tuple[RemittanceLine, ...]

The lines of the run, uncoded ones included.

ccnl_engine.CompetenceYearResult dataclass

Bases: PaymentsResult

Results of the runs of one competence year, in payment order.

The runs paid in the competence year come first and the last of them settles the conguaglio of that tax year, which is then closed; the runs paid in the next tax year (a December paid after 12 January) follow and open it.

Attributes:

Name Type Description
year int

The competence year.

calendar WorkCalendar

The calendar the year ran on: the CCNL standard calendar, or the accepted override.

calendar_override CalendarOverride | None

The override that replaced the standard calendar, with its reason and note, or None when the standard applied.

next_opening_state property

State to open the next competence year with.

close_tax_year() of :attr:closing_state when the last payment settled its tax year; otherwise the closing state itself, a state of the next tax year that already holds the late payments.

ccnl_engine.TaxYearResult dataclass

Bases: PaymentsResult

Results of every payment of one tax year, in payment order.

Attributes:

Name Type Description
tax_year int

The tax year.

payments tuple[PaymentId, ...]

Every payment of the tax year in payment order: those the opening state had already closed, then those computed.

conguaglio property

The payment that settled the conguaglio, None when none did.

next_opening_state property

close_tax_year() of :attr:closing_state: the next tax year.

The assurance of a competence or tax year is incremental: assurance, is_payable, blockers and rulesets assess the payments computed by the call, listed in assessed_payments. A payment the opening state already closed (a resumed or retried plan, a late December carried in from the previous competence year) is vouched for by the result of the call that computed it. A call that computed no payment assessed nothing: it is not payable, with missing evidence and a rule_source_weak blocker (and in operational mode a ruleset_not_production blocker).

A competence or tax year does not compute a run whose competence date has no base salary of the CCNL level in the bundle. The run is listed in uncovered_runs as an UncoveredRun (its payment, the fields of the MissingRuleError it would raise, and that error as error) and adds a run_not_computed blocker whose detail is the run id; the other runs are computed on a withholding schedule without it, so the year is partial and not payable. A year in which no run has a base salary raises the MissingRuleError of its first run.

Errors

Every error is exported at the root: see Errors.

Versions

ccnl_engine.engine_version = '0.6.0' module-attribute

ccnl_engine.bundle_version = '2026.3' module-attribute