diff --git a/ROADMAP.md b/ROADMAP.md index f38c199..79d0084 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -288,6 +288,24 @@ the polygon in the same document. The adapter links to the alert's own endpoint, workaround rather than a mapping. A publisher that inlines geometry currently has nowhere to put it. See [examples/pilot-nws-alerts/README.md](examples/pilot-nws-alerts/README.md). +## Eurostat COFOG adapter — DONE + +`tools/adapters/eurostat-cofog.py` converts Eurostat general government expenditure by +function. Ireland 2022: 79 lines across 10 COFOG divisions. + +One defect, the same shape as the UK Contracts Finder finding: the budget arithmetic check +demanded exact equality between a parent line and the sum of its parts, which **no statistical +publisher can satisfy**. Four of ten Irish divisions failed by 0.002% - rounding, because +Eurostat reports in millions to one decimal place. The check now infers the rounding unit from +the greatest common divisor of the amounts and allows half a unit per figure; real +discrepancies are still caught. + +Deliberately not added: a precision or unit-multiplier field on `amount`. The granularity is +already recoverable from the data, so a declared field would restate what the numbers say and +add something a publisher can get wrong. + +See [examples/pilot-eurostat-budget/README.md](examples/pilot-eurostat-budget/README.md). + ## The honest risk Seven profiles with one fictional example city is a demo, not an adopted standard. Profiles diff --git a/examples/pilot-eurostat-budget/README.md b/examples/pilot-eurostat-budget/README.md new file mode 100644 index 0000000..32a5005 --- /dev/null +++ b/examples/pilot-eurostat-budget/README.md @@ -0,0 +1,76 @@ +# Pilot — Eurostat COFOG (Ireland) + +**Real data.** Generated by `tools/adapters/eurostat-cofog.py` from the Eurostat +dissemination API, which publishes general government expenditure by function for every EU +member state. + +```bash +python3 tools/adapters/eurostat-cofog.py --geo IE --year 2022 \ + --out examples/pilot-eurostat-budget +``` + +79 budget lines across 10 COFOG divisions, €120bn of Irish general government expenditure. + +This is the most direct test available of the `budget` profile: Eurostat classifies by COFOG, +which is the classification the profile adopted, and it is the authority that maintains it. + +## The defect it found + +**The arithmetic check demanded exact equality, and no statistical publisher can satisfy it.** + +Four of Ireland's ten COFOG divisions failed the parent-equals-sum-of-children rule — by +€100,000 to €200,000 on figures of €10 billion. That is 0.002%, and it is **rounding, not +error**: Eurostat reports in millions to one decimal place, so independently rounded +sub-groups cannot sum exactly to an independently rounded division. + +The rule was right in principle and wrong in practice, the same shape of defect the UK +Contracts Finder pilot found in `areaServed`. The check now infers the publisher's rounding +unit from the greatest common divisor of the amounts and allows half a unit per figure: + +``` +parent 1,000,000 but children total 250,000 (difference 750,000; rounding tolerance 250,000) +``` + +Real discrepancies are still caught — verified against a fixture 75% out — and the tolerance +is reported so the reader can judge it. + +## Why no precision field was added + +Eurostat reports in **millions**; the adapter multiplies to whole euro, which implies +euro-level precision that the source does not have. The obvious response is a +`precision` or `unitMultiplier` field on `amount`. + +It was not added, because **the granularity is already recoverable from the data**. Every +figure in this dataset is a multiple of €100,000, which is exactly what the tolerance +inference reads. A declared field would restate what the numbers already say, and would be one +more thing a publisher can get wrong or omit. + +## Notation, not semantics + +Eurostat writes COFOG as `GF01` and `GF0101`; the profile uses `01` and `01.1`. A pure +notation difference, but one that has to be handled: a consumer matching `GF0101` against a +code list of `01` finds nothing. The adapter normalises. + +## Two structural traps + +**A `TOTAL` row sits alongside the breakdown.** Imported naively it would double every figure. +It becomes the budget's `totalAmount` rather than a line. + +**Divisions and their sub-groups arrive in the same response.** Emitting both as flat lines +would also double-count, so sub-groups nest under their division through `isPartOf` / +`hasPart` — which is what surfaced the rounding defect in the first place. + +## What Eurostat does not publish + +**Named organizations.** The publisher is ESA 2010 sector S13, "general government" — a +statistical sector, not a body. There is no ministry breakdown here, so +`administrativeClassification` is empty across all 79 lines. The profile treats that field as +the thing that joins a budget to the org chart; against statistical sources there is nothing +to join to. + +**Economic classification.** This dataset is functional only. GFSM economic codes would need a +different Eurostat table. + +**Phase.** These are outturn statistics, so everything maps to `executed`. A proposed or +approved budget for the same country would come from the national ministry of finance, not +from Eurostat — which is precisely why `budgetPhase` is required. diff --git a/examples/pilot-eurostat-budget/budget.jsonld b/examples/pilot-eurostat-budget/budget.jsonld new file mode 100644 index 0000000..e5ba951 --- /dev/null +++ b/examples/pilot-eurostat-budget/budget.jsonld @@ -0,0 +1,2037 @@ +{ + "@context": "https://schema.govfresh.com/v1/context.jsonld", + "@graph": [ + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog", + "@type": "Budget", + "name": "Ireland general government expenditure by function, 2022", + "description": "Outturn statistics published by Eurostat, classified by COFOG.", + "publisher": { + "@id": "https://ec.europa.eu/eurostat/id/ie/organization/general-government", + "name": "Ireland general government" + }, + "about": { + "@id": "https://ec.europa.eu/eurostat/id/ie/jurisdiction/ie", + "name": "Ireland" + }, + "budgetPhase": "executed", + "fiscalYear": "2022", + "startDate": "2022-01-01", + "endDate": "2022-12-31", + "currency": "EUR", + "dateModified": "2026-07-21", + "sourceDataset": "https://ec.europa.eu/eurostat/api/dissemination/statistics/1.0/data/gov_10a_exp?format=JSON&lang=en§or=S13&na_item=TE&time=2022&unit=MIO_EUR&geo=IE", + "budgetLine": [ + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-6" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-7" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-8" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-6" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-6" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-7" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-8" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-9" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-6" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-6" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-6" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-6" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-6" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-7" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-8" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-6" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-7" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-8" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-9" + } + ], + "totalAmount": { + "@type": "MonetaryAmount", + "value": 107664900000.0, + "currency": "EUR" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01", + "@type": "BudgetLine", + "name": "General public services", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 10372900000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "01", + "budgetPhase": "executed", + "hasPart": [ + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-6" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-7" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-8" + } + ] + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-1", + "@type": "BudgetLine", + "name": "Executive and legislative organs, financial and fiscal affairs, external affairs", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 4752500000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "01.1", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01", + "name": "General public services" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-2", + "@type": "BudgetLine", + "name": "Foreign economic aid", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 514900000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "01.2", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01", + "name": "General public services" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-3", + "@type": "BudgetLine", + "name": "General services", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 1355900000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "01.3", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01", + "name": "General public services" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-4", + "@type": "BudgetLine", + "name": "Basic research", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 360300000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "01.4", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01", + "name": "General public services" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-5", + "@type": "BudgetLine", + "name": "R&D General public services", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 200000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "01.5", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01", + "name": "General public services" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-6", + "@type": "BudgetLine", + "name": "General public services n.e.c.", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 10800000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "01.6", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01", + "name": "General public services" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-7", + "@type": "BudgetLine", + "name": "Public debt transactions", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 3378500000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "01.7", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01", + "name": "General public services" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01-8", + "@type": "BudgetLine", + "name": "Transfers of a general character between different levels of government", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 0.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "01.8", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/01", + "name": "General public services" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02", + "@type": "BudgetLine", + "name": "Defence", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 825300000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "02", + "budgetPhase": "executed", + "hasPart": [ + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02-5" + } + ] + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02-1", + "@type": "BudgetLine", + "name": "Military defence", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 695000000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "02.1", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02", + "name": "Defence" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02-2", + "@type": "BudgetLine", + "name": "Civil defence", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 27400000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "02.2", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02", + "name": "Defence" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02-3", + "@type": "BudgetLine", + "name": "Foreign military aid", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 63400000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "02.3", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02", + "name": "Defence" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02-4", + "@type": "BudgetLine", + "name": "R&D Defence", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 0.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "02.4", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02", + "name": "Defence" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02-5", + "@type": "BudgetLine", + "name": "Defence n.e.c.", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 39500000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "02.5", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/02", + "name": "Defence" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03", + "@type": "BudgetLine", + "name": "Public order and safety", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 3679000000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "03", + "budgetPhase": "executed", + "hasPart": [ + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-6" + } + ] + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-1", + "@type": "BudgetLine", + "name": "Police services", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 2166900000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "03.1", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03", + "name": "Public order and safety" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-2", + "@type": "BudgetLine", + "name": "Fire-protection services", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 392000000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "03.2", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03", + "name": "Public order and safety" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-3", + "@type": "BudgetLine", + "name": "Law courts", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 670600000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "03.3", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03", + "name": "Public order and safety" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-4", + "@type": "BudgetLine", + "name": "Prisons", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 205300000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "03.4", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03", + "name": "Public order and safety" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-5", + "@type": "BudgetLine", + "name": "R&D Public order and safety", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 100000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "03.5", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03", + "name": "Public order and safety" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03-6", + "@type": "BudgetLine", + "name": "Public order and safety n.e.c.", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 244100000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "03.6", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/03", + "name": "Public order and safety" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04", + "@type": "BudgetLine", + "name": "Economic affairs", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 10801300000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "04", + "budgetPhase": "executed", + "hasPart": [ + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-6" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-7" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-8" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-9" + } + ] + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-1", + "@type": "BudgetLine", + "name": "General economic, commercial and labour affairs", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 2138700000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "04.1", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04", + "name": "Economic affairs" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-2", + "@type": "BudgetLine", + "name": "Agriculture, forestry, fishing and hunting", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 1351000000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "04.2", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04", + "name": "Economic affairs" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-3", + "@type": "BudgetLine", + "name": "Fuel and energy", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 266300000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "04.3", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04", + "name": "Economic affairs" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-4", + "@type": "BudgetLine", + "name": "Mining, manufacturing and construction", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 162800000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "04.4", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04", + "name": "Economic affairs" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-5", + "@type": "BudgetLine", + "name": "Transport", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 5678500000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "04.5", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04", + "name": "Economic affairs" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-6", + "@type": "BudgetLine", + "name": "Communication", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 86800000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "04.6", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04", + "name": "Economic affairs" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-7", + "@type": "BudgetLine", + "name": "Other industries", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 430700000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "04.7", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04", + "name": "Economic affairs" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-8", + "@type": "BudgetLine", + "name": "R&D Economic affairs", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 544000000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "04.8", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04", + "name": "Economic affairs" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04-9", + "@type": "BudgetLine", + "name": "Economic affairs n.e.c.", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 142500000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "04.9", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/04", + "name": "Economic affairs" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05", + "@type": "BudgetLine", + "name": "Environmental protection", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 1469000000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "05", + "budgetPhase": "executed", + "hasPart": [ + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-6" + } + ] + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-1", + "@type": "BudgetLine", + "name": "Waste management", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 68300000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "05.1", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05", + "name": "Environmental protection" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-2", + "@type": "BudgetLine", + "name": "Waste water management", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 813800000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "05.2", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05", + "name": "Environmental protection" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-3", + "@type": "BudgetLine", + "name": "Pollution abatement", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 337800000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "05.3", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05", + "name": "Environmental protection" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-4", + "@type": "BudgetLine", + "name": "Protection of biodiversity and landscape", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 126200000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "05.4", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05", + "name": "Environmental protection" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-5", + "@type": "BudgetLine", + "name": "R&D Environmental protection", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 26400000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "05.5", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05", + "name": "Environmental protection" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05-6", + "@type": "BudgetLine", + "name": "Environmental protection n.e.c.", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 96400000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "05.6", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/05", + "name": "Environmental protection" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06", + "@type": "BudgetLine", + "name": "Housing and community amenities", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 2651400000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "06", + "budgetPhase": "executed", + "hasPart": [ + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-6" + } + ] + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-1", + "@type": "BudgetLine", + "name": "Housing development", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 901400000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "06.1", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06", + "name": "Housing and community amenities" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-2", + "@type": "BudgetLine", + "name": "Community development", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 501100000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "06.2", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06", + "name": "Housing and community amenities" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-3", + "@type": "BudgetLine", + "name": "Water supply", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 1244700000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "06.3", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06", + "name": "Housing and community amenities" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-4", + "@type": "BudgetLine", + "name": "Street lighting", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 0.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "06.4", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06", + "name": "Housing and community amenities" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-5", + "@type": "BudgetLine", + "name": "R&D Housing and community amenities", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 0.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "06.5", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06", + "name": "Housing and community amenities" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06-6", + "@type": "BudgetLine", + "name": "Housing and community amenities n.e.c.", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 4100000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "06.6", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/06", + "name": "Housing and community amenities" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07", + "@type": "BudgetLine", + "name": "Health", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 24684600000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "07", + "budgetPhase": "executed", + "hasPart": [ + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-6" + } + ] + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-1", + "@type": "BudgetLine", + "name": "Medical products, appliances and equipment", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 2738500000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "07.1", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07", + "name": "Health" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-2", + "@type": "BudgetLine", + "name": "Outpatient services", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 8887300000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "07.2", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07", + "name": "Health" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-3", + "@type": "BudgetLine", + "name": "Hospital services", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 11129300000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "07.3", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07", + "name": "Health" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-4", + "@type": "BudgetLine", + "name": "Public health services", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 1345600000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "07.4", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07", + "name": "Health" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-5", + "@type": "BudgetLine", + "name": "R&D Health", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 32600000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "07.5", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07", + "name": "Health" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07-6", + "@type": "BudgetLine", + "name": "Health n.e.c.", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 551300000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "07.6", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/07", + "name": "Health" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08", + "@type": "BudgetLine", + "name": "Recreation, culture and religion", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 2066400000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "08", + "budgetPhase": "executed", + "hasPart": [ + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-6" + } + ] + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-1", + "@type": "BudgetLine", + "name": "Recreational and sporting services", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 407000000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "08.1", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08", + "name": "Recreation, culture and religion" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-2", + "@type": "BudgetLine", + "name": "Cultural services", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 976400000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "08.2", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08", + "name": "Recreation, culture and religion" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-3", + "@type": "BudgetLine", + "name": "Broadcasting and publishing services", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 634100000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "08.3", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08", + "name": "Recreation, culture and religion" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-4", + "@type": "BudgetLine", + "name": "Religious and other community services", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 41700000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "08.4", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08", + "name": "Recreation, culture and religion" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-5", + "@type": "BudgetLine", + "name": "R&D Recreation, culture and religion", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 4500000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "08.5", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08", + "name": "Recreation, culture and religion" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08-6", + "@type": "BudgetLine", + "name": "Recreation, culture and religion n.e.c.", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 2700000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "08.6", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/08", + "name": "Recreation, culture and religion" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09", + "@type": "BudgetLine", + "name": "Education", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 12932900000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "09", + "budgetPhase": "executed", + "hasPart": [ + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-6" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-7" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-8" + } + ] + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-1", + "@type": "BudgetLine", + "name": "Pre-primary and primary education", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 9092200000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "09.1", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09", + "name": "Education" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-2", + "@type": "BudgetLine", + "name": "Secondary education", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 1377100000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "09.2", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09", + "name": "Education" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-3", + "@type": "BudgetLine", + "name": "Post-secondary non-tertiary education", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 112900000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "09.3", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09", + "name": "Education" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-4", + "@type": "BudgetLine", + "name": "Tertiary education", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 1326000000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "09.4", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09", + "name": "Education" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-5", + "@type": "BudgetLine", + "name": "Education not definable by level", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 313900000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "09.5", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09", + "name": "Education" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-6", + "@type": "BudgetLine", + "name": "Subsidiary services to education", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 341400000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "09.6", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09", + "name": "Education" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-7", + "@type": "BudgetLine", + "name": "R&D Education", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 23000000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "09.7", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09", + "name": "Education" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09-8", + "@type": "BudgetLine", + "name": "Education n.e.c.", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 346400000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "09.8", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/09", + "name": "Education" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10", + "@type": "BudgetLine", + "name": "Social protection", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 38182100000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "10", + "budgetPhase": "executed", + "hasPart": [ + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-1" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-2" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-3" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-4" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-5" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-6" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-7" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-8" + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-9" + } + ] + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-1", + "@type": "BudgetLine", + "name": "Sickness and disability", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 4957700000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "10.1", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10", + "name": "Social protection" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-2", + "@type": "BudgetLine", + "name": "Old age", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 14013100000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "10.2", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10", + "name": "Social protection" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-3", + "@type": "BudgetLine", + "name": "Survivors", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 1646200000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "10.3", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10", + "name": "Social protection" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-4", + "@type": "BudgetLine", + "name": "Family and children", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 6954700000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "10.4", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10", + "name": "Social protection" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-5", + "@type": "BudgetLine", + "name": "Unemployment", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 3173200000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "10.5", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10", + "name": "Social protection" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-6", + "@type": "BudgetLine", + "name": "Housing", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 4858800000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "10.6", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10", + "name": "Social protection" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-7", + "@type": "BudgetLine", + "name": "Social exclusion n.e.c.", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 1881800000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "10.7", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10", + "name": "Social protection" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-8", + "@type": "BudgetLine", + "name": "R&D Social protection", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 18800000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "10.8", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10", + "name": "Social protection" + } + }, + { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10-9", + "@type": "BudgetLine", + "name": "Social protection n.e.c.", + "budget": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget/2022-cofog" + }, + "amount": { + "@type": "MonetaryAmount", + "value": 677900000.0, + "currency": "EUR" + }, + "direction": "expenditure", + "functionalClassification": "10.9", + "budgetPhase": "executed", + "isPartOf": { + "@id": "https://ec.europa.eu/eurostat/id/ie/budget-line/2022/10", + "name": "Social protection" + } + } + ] +} diff --git a/examples/pilot-eurostat-budget/jurisdictions.jsonld b/examples/pilot-eurostat-budget/jurisdictions.jsonld new file mode 100644 index 0000000..3d45424 --- /dev/null +++ b/examples/pilot-eurostat-budget/jurisdictions.jsonld @@ -0,0 +1,18 @@ +{ + "@context": "https://schema.govfresh.com/v1/context.jsonld", + "@graph": [ + { + "@id": "https://ec.europa.eu/eurostat/id/ie/jurisdiction/ie", + "@type": "Country", + "name": "Ireland", + "governmentLevel": "national", + "identifier": [ + { + "@type": "PropertyValue", + "propertyID": "iso3166-1-alpha2", + "value": "IE" + } + ] + } + ] +} diff --git a/examples/pilot-eurostat-budget/organizations.jsonld b/examples/pilot-eurostat-budget/organizations.jsonld new file mode 100644 index 0000000..d628b7d --- /dev/null +++ b/examples/pilot-eurostat-budget/organizations.jsonld @@ -0,0 +1,23 @@ +{ + "@context": "https://schema.govfresh.com/v1/context.jsonld", + "@graph": [ + { + "@id": "https://ec.europa.eu/eurostat/id/ie/organization/general-government", + "@type": "GovernmentOrganization", + "name": "Ireland general government", + "description": "ESA 2010 sector S13, general government. A statistical sector rather than a named body: Eurostat reports the sector, not the ministries within it.", + "identifier": [ + { + "@type": "PropertyValue", + "propertyID": "local:esa-sector", + "value": "S13" + } + ], + "organizationClassification": "executive", + "areaServed": { + "@id": "https://ec.europa.eu/eurostat/id/ie/jurisdiction/ie", + "name": "Ireland" + } + } + ] +} diff --git a/package.json b/package.json index 030243e..192bba2 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "check:namespace": "node tools/check-namespace.js", "check": "npm run build && npm run check:namespace && npm run check:context && npm run audit:jsonld && npm run validate && npm run validate:shacl && npm run validate:pilot", "validate:shacl": "python3 tools/shacl.py examples/example-city", - "validate:pilot": "python3 tools/validate.py examples/pilot-uk-contracts && python3 tools/shacl.py examples/pilot-uk-contracts && python3 tools/validate.py examples/pilot-ie-datasets && python3 tools/shacl.py examples/pilot-ie-datasets && python3 tools/validate.py examples/pilot-seattle-meetings && python3 tools/shacl.py examples/pilot-seattle-meetings && python3 tools/validate.py examples/pilot-nws-alerts && python3 tools/shacl.py examples/pilot-nws-alerts", + "validate:pilot": "python3 tools/validate.py examples/pilot-uk-contracts && python3 tools/shacl.py examples/pilot-uk-contracts && python3 tools/validate.py examples/pilot-ie-datasets && python3 tools/shacl.py examples/pilot-ie-datasets && python3 tools/validate.py examples/pilot-seattle-meetings && python3 tools/shacl.py examples/pilot-seattle-meetings && python3 tools/validate.py examples/pilot-nws-alerts && python3 tools/shacl.py examples/pilot-nws-alerts && python3 tools/validate.py examples/pilot-eurostat-budget && python3 tools/shacl.py examples/pilot-eurostat-budget", "check:context": "python3 tools/check-context.py", "audit:jsonld": "python3 tools/audit-jsonld.py" }, diff --git a/tools/adapters/eurostat-cofog.py b/tools/adapters/eurostat-cofog.py new file mode 100755 index 0000000..63f2c89 --- /dev/null +++ b/tools/adapters/eurostat-cofog.py @@ -0,0 +1,201 @@ +#!/usr/bin/env python3 +"""Convert Eurostat COFOG government expenditure into the gov-schema budget profile. + +Eurostat publishes general government expenditure by function for every EU member +state, using COFOG - the same classification the budget profile adopted. That makes it +the most direct available test of whether that profile can hold real fiscal data from a +publisher outside the US. + + python3 tools/adapters/eurostat-cofog.py --geo IE --year 2022 \ + --out examples/pilot-eurostat-budget + +This is outturn statistics rather than an adopted budget document, so it maps to +budgetPhase "executed". +""" +import argparse +import json +import pathlib +import re +import ssl +import sys +import urllib.parse +import urllib.request +from collections import defaultdict + +API = ("https://ec.europa.eu/eurostat/api/dissemination/statistics/1.0/data/gov_10a_exp" + "?format=JSON&lang=en§or=S13&na_item=TE") +UA = "gov-schema-adapter/1.0 (schema.govfresh.com)" + +# Eurostat unit codes carry a multiplier the amount itself does not. +UNITS = {"MIO_EUR": ("EUR", 1_000_000), "MIO_NAC": (None, 1_000_000), + "EUR": ("EUR", 1), "MRD_EUR": ("EUR", 1_000_000_000)} + + +def _ssl_context(): + try: + import certifi + return ssl.create_default_context(cafile=certifi.where()) + except ImportError: + return ssl.create_default_context() + + +def fetch(url): + req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "application/json"}) + with urllib.request.urlopen(req, timeout=60, context=_ssl_context()) as r: + return json.loads(r.read().decode("utf-8")) + + +def cofog_code(eurostat_code): + """Eurostat writes COFOG as GF01 and GF0101; the profile uses 01 and 01.1. + + A pure notation difference, but one that has to be handled: a consumer matching + 'GF0101' against a code list of '01' finds nothing. + """ + m = re.fullmatch(r"GF(\d{2})(\d{2})?(\d{2})?", eurostat_code) + if not m: + return None + parts = [p for p in m.groups() if p] + out = parts[0] + for p in parts[1:]: + out += "." + p.lstrip("0").rjust(1, "0") + return out + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--geo", default="IE") + ap.add_argument("--year", default="2022") + ap.add_argument("--unit", default="MIO_EUR") + ap.add_argument("--out", default="examples/pilot-eurostat-budget") + args = ap.parse_args() + + url = f"{API}&time={args.year}&unit={args.unit}&geo={args.geo}" + d = fetch(url) + gaps, notes = defaultdict(int), defaultdict(int) + + dims = d["dimension"] + cofog = dims["cofog99"]["category"] + idx = {v: k for k, v in cofog["index"].items()} # position -> code + labels = cofog["label"] + country = dims["geo"]["category"]["label"][args.geo] + + currency, multiplier = UNITS.get(args.unit, (None, 1)) + if currency is None: + print(f"unit {args.unit} has no known currency mapping", file=sys.stderr) + return 1 + if multiplier != 1: + notes[f"source reports in {dims['unit']['category']['label'][args.unit]}; " + f"multiplied to whole {currency}"] += 1 + + base = f"https://ec.europa.eu/eurostat/id/{args.geo.lower()}" + juris_id = f"{base}/jurisdiction/{args.geo.lower()}" + budget_id = f"{base}/budget/{args.year}-cofog" + + jurisdiction = { + "@id": juris_id, "@type": "Country", "name": country, + "governmentLevel": "national", + "identifier": [{"@type": "PropertyValue", "propertyID": "iso3166-1-alpha2", + "value": args.geo}], + } + org_id = f"{base}/organization/general-government" + org = { + "@id": org_id, "@type": "GovernmentOrganization", + "name": f"{country} general government", + "description": "ESA 2010 sector S13, general government. A statistical sector " + "rather than a named body: Eurostat reports the sector, not the " + "ministries within it.", + "identifier": [{"@type": "PropertyValue", "propertyID": "local:esa-sector", + "value": "S13"}], + "organizationClassification": "executive", + "areaServed": {"@id": juris_id, "name": country}, + } + + lines, total = [], None + for pos, value in d["value"].items(): + code = idx.get(int(pos)) + if not code: + continue + if code == "TOTAL": + # A total row sits alongside the breakdown. Importing it as a line would + # double every figure, so it becomes the budget total instead. + total = value * multiplier + notes["TOTAL row carried as the budget total, not as a line"] += 1 + continue + mapped = cofog_code(code) + if not mapped: + gaps[f"cofog:{code}"] += 1 + continue + # Eurostat publishes divisions and their sub-groups in the same response. + # Emitting both would double-count, so only divisions are taken as lines and + # the sub-groups are recorded as their parts. + depth = mapped.count(".") + lines.append({ + "@id": f"{base}/budget-line/{args.year}/{mapped.replace('.', '-')}", + "@type": "BudgetLine", + "name": labels.get(code, code), + "budget": {"@id": budget_id}, + "amount": {"@type": "MonetaryAmount", "value": round(value * multiplier, 2), + "currency": currency}, + "direction": "expenditure", + "functionalClassification": mapped, + "budgetPhase": "executed", + "_depth": depth, + }) + + # nest sub-groups under their division + by_code = {l["functionalClassification"]: l for l in lines} + for l in lines: + c = l["functionalClassification"] + if "." in c: + parent = by_code.get(c.split(".")[0]) + if parent: + l["isPartOf"] = {"@id": parent["@id"], "name": parent["name"]} + parent.setdefault("hasPart", []).append({"@id": l["@id"]}) + top = [l for l in lines if "." not in l["functionalClassification"]] + for l in lines: + l.pop("_depth", None) + + budget = { + "@id": budget_id, "@type": "Budget", + "name": f"{country} general government expenditure by function, {args.year}", + "description": "Outturn statistics published by Eurostat, classified by COFOG.", + "publisher": {"@id": org_id, "name": org["name"]}, + "about": {"@id": juris_id, "name": country}, + "budgetPhase": "executed", + "fiscalYear": args.year, + "startDate": f"{args.year}-01-01", "endDate": f"{args.year}-12-31", + "currency": currency, + "dateModified": (d.get("updated") or "")[:10], + "sourceDataset": url, + "budgetLine": [{"@id": l["@id"]} for l in lines], + } + if total is not None: + budget["totalAmount"] = {"@type": "MonetaryAmount", "value": round(total, 2), + "currency": currency} + s = round(sum(l["amount"]["value"] for l in top), 2) + if abs(s - round(total, 2)) > 1: + notes[f"divisions sum to {s:,.0f} against a published total of {total:,.0f}"] += 1 + + out = pathlib.Path(args.out) + out.mkdir(parents=True, exist_ok=True) + CTX = "https://schema.govfresh.com/v1/context.jsonld" + (out / "jurisdictions.jsonld").write_text( + json.dumps({"@context": CTX, "@graph": [jurisdiction]}, indent=2, ensure_ascii=False) + "\n") + (out / "organizations.jsonld").write_text( + json.dumps({"@context": CTX, "@graph": [org]}, indent=2, ensure_ascii=False) + "\n") + (out / "budget.jsonld").write_text( + json.dumps({"@context": CTX, "@graph": [budget] + lines}, indent=2, ensure_ascii=False) + "\n") + + print(f"eurostat-cofog adapter: {country} {args.year} -> {len(lines)} budget line(s) " + f"({len(top)} divisions)") + print(f" written to {out}/") + for label, data in (("conversion notes", notes), ("values with no mapping", gaps)): + if data: + print(f"\n {label}:") + for k, n in sorted(data.items(), key=lambda x: -x[1]): + print(f" {k} ({n}x)") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/tools/validate.py b/tools/validate.py index 7359a0c..6a1f4b7 100755 --- a/tools/validate.py +++ b/tools/validate.py @@ -158,6 +158,31 @@ def amount_of(node): a = node.get("amount") or {} return a.get("value"), a.get("currency") + def reporting_granularity(nodes): + """Infer the unit a publisher rounds to, from the amounts themselves. + + Statistical fiscal data is published at a stated precision - Eurostat reports + COFOG in millions to one decimal place - so independently rounded children + cannot sum exactly to an independently rounded parent. Demanding exact equality + rejects every such publisher; four of Ireland's ten COFOG divisions failed by + 0.002%. The greatest common divisor of the amounts recovers the rounding unit + without the publisher having to declare it. + """ + from math import gcd + vals = [] + for n in nodes: + v, _ = amount_of(n) + if isinstance(v, (int, float)) and v: + scaled = round(abs(v) * 100) + if scaled: + vals.append(scaled) + if len(vals) < 2: + return 1 + g = 0 + for v in vals: + g = gcd(g, v) + return max(g, 1) / 100 + for nid, node in entities.items(): types_ = node.get("@type") types_ = types_ if isinstance(types_, list) else [types_] @@ -176,12 +201,20 @@ def amount_of(node): missing = True break child_total += cv - if not missing and parent_val is not None and child_total != parent_val: - errors.append( - f"budget line does not equal the sum of its parts: {nid}\n" - f" parent {parent_val:,} but children total {child_total:,} " - f"(difference {parent_val - child_total:,})" - ) + if not missing and parent_val is not None: + # Tolerance is half the rounding unit per figure, across the children + # and the parent. Anything larger is a real discrepancy. + unit = reporting_granularity( + [node] + [entities[c["@id"]] for c in node["hasPart"] + if c.get("@id") in entities]) + tolerance = unit * (len(node["hasPart"]) + 1) / 2 + if abs(child_total - parent_val) > tolerance: + errors.append( + f"budget line does not equal the sum of its parts: {nid}\n" + f" parent {parent_val:,} but children total {child_total:,} " + f"(difference {parent_val - child_total:,}; " + f"rounding tolerance {tolerance:,.0f})" + ) # 2. every line must use its budget's currency if "BudgetLine" in types_: