diff --git a/.gitignore b/.gitignore index ac851e7..5769c6f 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,10 @@ datasets/current/procurement/contracts.trig # bulk 2014-2020 EU-funds contracts (~26k, ~29 MB) — regenerate with `make -C etl eu-funds` datasets/current/eu-funds/contracts.trig +# bulk public-sector invoice aggregates (buyer-supplier-year, from ~14.4M invoices) — +# regenerate with `make -C etl public-spending` +datasets/current/public-spending/aggregates.trig + # VTEK browser harvests (SKAIDRIS lobbying, PINREG private interests) — re-harvest with the # harvest-vtek skill, never edit; data/institution-aliases.csv (curated) IS committed etl/vtek/data/*.json diff --git a/CLAUDE.md b/CLAUDE.md index e76cff0..4dd04cd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -69,6 +69,15 @@ make -C etl/eu-funds # 2014-2020 EU structural-funds implementation co # code with amounts. Repayments/irregularities are NOT modelled # (their keys are a hash of an unpublished id). contracts.trig is # gitignored bulk output (~29 MB). In `make all`. +make -C etl/public-spending # opt-in, NOT in `make all`: public-sector invoice totals per + # buyer-supplier-year (NBFC nbfc/viesojo_sektoriaus_saskaitos via + # get.data.gov.lt). ltlod-public-spending streams ~14.4M invoices + # (Saskaitos) + ~32M party rows (SaskaituSalys), keyset-paginated, + # into a temporary on-disk SQLite db and aggregates there (the + # party rows can't be windowed by invoice year, so the whole table + # is read — ~40-90 min fetch). Buyer (Pirkėjas) + supplier + # (Tiekėjas) link by bare JAR code; party names are pseudonymised + # (from the register). aggregates.trig is gitignored bulk output. make -C etl land-acquisitions # NŽT applications to acquire agricultural/forest land (Spinta, # ~140k rows) + JAR names for the code check (547k rows); legal-entity # applications per document (applications.trig, ~430k quads, gitignored), @@ -449,7 +458,7 @@ since the rows differ in the image cell. `etl/officials/`, legal-entity registration / deregistration, PINREG ties, insolvency proceedings (start → end instants); tax arrears snapshots (day); declarations, the - natural-person land totals and taxes paid per year (years). Not yet: + natural-person land totals, taxes paid per year and public-sector invoice aggregates (years). Not yet: admin-unit validity. Days that were public holidays carry `dct:type` → `taxonomies/holidays/{slug}/#this`, matched in `calendar.rq` from `etl/calendar/data/holidays.csv` (rules: fixed date / Easter + offset, Easter @@ -696,6 +705,16 @@ dangle until the full JAR register is loaded — expected. Gitignored bulk outpu Repayments and irregularities are not modelled: their `project_hash`/`project_hash_id` keys hash an unpublished internal SFMIS id — tested against every published id (code, `_id`, `project_id`, `Contract._id`) under md5/sha*/crc/blake, salted, prefix/suffix, 0 matches. 2021-2027 not on Spinta. +Public spending (`public-spending/`, 2026-10-25 NBFC feeds, opt-in): from 14 438 763 invoices +(Saskaitos) ⋈ 32 244 372 party rows (SaskaituSalys), streamed into SQLite and aggregated, +aggregates.trig = 432 570 (buyer, supplier, year) documents at the default MIN_TOTAL=1000 EUR +floor (the full set is ~3.9M; 63 % are zero-total credit-note/VAT pairs). The join is +`SaskaituSalys.sf_id` = `Saskaitos.sf_id` normalized to an `LT` prefix; years restricted to the +calendar's 1977-2027 (28 malformed-date rows dropped). riot validates, 0 blank nodes, 0 dangling +calendar years; `ltlod:spendingBuyer`/`ltlod:spendingSupplier` links into `legal-entities/` dangle +until the full JAR register is loaded — expected. Gitignored bulk output (~418 MB); NOT in `make +all` (the ~46M-row fetch is ~40-90 min). SHACL is not run over all 432k graphs by default (not in +CI, like other bulk outputs). `python3 queries/render-examples.py` re-runs all example queries end-to-end. Name-based person links, audited 2026-10-21 (`make -C etl/audit score` over the 400-link sample in `etl/audit/reviews/`, verdicts filled; 0 wrong in 50 means precision >= 92.9 %; the `links` column is the diff --git a/README.md b/README.md index fbf8fba..b09db61 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ kalba (kaip SQL reliacinėms DB). Pavyzdžiai — [žemiau](#ką-jau-galima-atsa | [`taxes`](etl/taxes/) (failai `taxpayers.trig` ir `taxes-paid.trig` neįtraukiami į git — sugeneruojami `make -C etl taxes`; į git įtraukiamas tik kubo aprašas `dataset.trig`) | 178 177 juridinių asmenų mokesčių įrašai (dviejų VMI srautų sąjunga): 30 764 turi dabartinę mokestinę nepriemoką (bendra, pradelsta, atidėta, atidėta pradelsta — EUR, su registracijos savivaldybe ir VMI skelbimo diena kalendoriuje), 620 689 (juridinis asmuo, metai) sumokėtų mokesčių stebėjimai 2022–2026 m. (175 198 skirtingi asmenys); mokesčių mokėtojas susietas su JAR įrašu (`ltlod:taxpayer`) — jungiasi su pirkimų tiekėjais, Sodros darbdaviais ir kampanijų aukotojais per tą patį kodą | [VMI](https://get.data.gov.lt/datasets/gov/vmi/ja_nepriemokos/:ns) per get.data.gov.lt (`vmi/ja_nepriemokos` nepriemokos ⋈ `vmi/ja_mokesciai` sumokėti mokesčiai, pagal JAR kodą; Valstybės duomenų agentūra, CC BY 4.0) | | [`insolvency-cases`](datasets/current/insolvency/) | 6 412 įmonių nemokumo bylų: 6 254 bankrotai (iš jų 834 pripažinti tyčiniais) ir 158 restruktūrizavimai; kiekviena byla susieta su JAR įrašu (`ltlod:insolvent`), savivaldybe ir kalendoriaus dienomis (pradžia ir pabaiga — `time:Interval`); nurodomas apygardos teismas, bankroto iniciatorius ir ne teismo / supaprastinto / tyčinio bankroto požymiai. Bankrotų ir restruktūrizavimų ataskaitiniai duomenys — nuo 2020 m., tyčinių bankrotų sąrašas — nuo 1994 m. | [AVNT](https://get.data.gov.lt/datasets/gov/avnt/imoniu_bankrotas/:ns) per get.data.gov.lt (`avnt/imoniu_bankrotas` + `avnt/imoniu_restrukturizavimas` + `avnt/tyciniai_bankrotai`; Valstybės duomenų agentūra, CC BY 4.0) | | [`eu-funds`](etl/eu-funds/) (failas neįtraukiamas į git — sugeneruojamas `make -C etl eu-funds`) | 25 978 Europos Sąjungos struktūrinių fondų (2014–2020 m.) finansavimo sutarčių: kiekviena susieta su paramos gavėju (`ltlod:beneficiary`) ir projekto partneriais (JAR pagal įmonės kodą), savivaldybe ir pradžios diena kalendoriuje; ~685 turi formalų projekto kodą su skirtomis ES bei bendromis lėšomis (EUR), likusios — finansinių priemonių išmokos (be kodo). Lėšų grąžinimai ir pažeidimai neįtraukti — jų šaltinio raktas yra neskelbiamo vidinio identifikatoriaus maiša; 2021–2027 m. duomenų dar nėra | [Finansų ministerija](https://get.data.gov.lt/datasets/gov/finmin/sutartys/:ns) per get.data.gov.lt (`finmin/sutartys` ⋈ `finmin/paraiskos`; Valstybės duomenų agentūra, CC BY 4.0) | +| [`public-spending`](etl/public-spending/) (failas neįtraukiamas į git — sugeneruojamas `make -C etl public-spending`) | viešojo sektoriaus gautų sąskaitų faktūrų suvestinės: ~14,4 mln. sąskaitų (`Saskaitos`), suvestų pagal pirkėją, tiekėją ir metus (sąskaitų skaičius, suma su PVM ir be PVM). Pirkėjas (`ltlod:spendingBuyer`) ir tiekėjas (`ltlod:spendingSupplier`) susieti su JAR įrašu pagal kodą; sąskaitos šalių pavadinimai šaltinyje užšifruoti, todėl imami iš registro. Apima ir smulkius, žemiau pirkimų ribų esančius pirkimus | [Valstybės iždas (NBFC)](https://get.data.gov.lt/datasets/gov/nbfc/viesojo_sektoriaus_saskaitos/:ns) per get.data.gov.lt (`Saskaitos` ⋈ `SaskaituSalys`; Valstybės duomenų agentūra, CC BY 4.0) | | [`land-acquisitions`](datasets/current/land-acquisitions/) (juridinių asmenų prašymų failas neįtraukiamas į git — sugeneruojamas `make -C etl land-acquisitions`) | prašymai Nacionalinei žemės tarnybai leisti įsigyti žemės ūkio ar miškų ūkio paskirties žemės (nuo 2023 m.): 17 842 juridinių asmenų prašymai po vieną — su NŽT sprendimu, prašomu ir jau valdomu plotu, savivaldybe, pateikimo ir sprendimo dienomis, susieti su juridiniu asmeniu, jei NŽT nurodytas pavadinimas atitinka JAR kodą; 121 869 fizinių asmenų prašymai — tik suskaičiuoti pagal savivaldybę, metus ir paskirtį (447 suvestinės, mažiau nei 3 prašymų langeliai praleisti), nes NŽT jų kodus ir vardus užšifruoja | [NŽT](https://get.data.gov.lt/datasets/gov/nzt/paraiskos/Paraiska) per get.data.gov.lt; pavadinimų patikra — pagal JAR | | [`calendar`](etl/calendar/) (failas neįtraukiamas į git — sugeneruojamas `make -C etl/calendar`) | kalendorius nuo 1977-01-01 (anksčiausia JAR registracija) iki kitų metų pabaigos: metai, mėnesiai ir dienos (2027 m. imtinai — 51 metai, 612 mėnesių, 18 627 dienos), valstybinių švenčių dienos pažymėtos; visos kitų rinkinių datos (posėdžiai, balsavimai, kadencijų, sesijų ir narysčių pradžios bei pabaigos, juridinių asmenų įregistravimas ir išregistravimas, deklaracijų ataskaitiniai metai) susietos su kalendoriaus diena ar metais (`dct:temporal`) | sugeneruojama ETL metu; šventės — pagal Švenčių dienų įstatymą ir Darbo kodeksą, su kiekvienos šventės galiojimo datomis ([`etl/calendar/data/holidays.csv`](etl/calendar/data/holidays.csv)) | | [`taxonomies`](datasets/current/taxonomies/) | 27 SKOS klasifikatorių: administracinių vienetų lygiai, teisinės formos (iš JAR), statusai, pareigų/padalinių/vietovių/gatvių tipai, Seimo veiklos (sesijų ir posėdžių) tipai, balsavimo būdai, klausimų svarstymo stadijos, deklaruojamo turto rūšys, VMI deklaruojančiųjų pareigybių grupės, valstybinės šventės, žemės paskirtys, NŽT sprendimai dėl žemės įsigijimo, pareiškėjo kodo patikros rezultatai, švietimo įstaigų tipai, kultūros paveldo apsaugos statusai, reikšmingumo lygmenys, objektų rūšys ir vertingųjų savybių pobūdis, lobistinės veiklos sritys, ryšių su juridiniais asmenimis pobūdžiai, asmenų susiejimo būdai, nemokumo bylų rūšys, bankroto iniciatoriai, apygardos teismai | JAR + išvesta iš duomenų | @@ -140,6 +141,8 @@ graph LR insolvency -->|sdmx-dimension:refArea| admin eufunds[ES fondų finansavimas] -->|ltlod:beneficiary · JAR kodas| legal eufunds -->|sdmx-dimension:refArea| admin + pubspend[viešojo sektoriaus sąskaitos] -->|ltlod:spendingBuyer / spendingSupplier · JAR kodas| legal + pubspend -->|dct:temporal| calendar land[prašymai įsigyti žemės] -->|ltlod:applicant · patikrinus pavadinimą| legal land -->|schema:location| admin sittings[plenariniai posėdžiai] -->|eli-dl:forms_part_of| sessions[sesijos] @@ -193,6 +196,7 @@ Principas: **pirmiausia W3C standartai → tada srities žodynai (ES SEMIC, OP k | Juridinių asmenų mokesčiai (VMI) | W3C [Data Cube](https://www.w3.org/TR/vocab-data-cube/) (`qb:DataSet`, `qb:Observation`) + SDMX-RDF `sdmx-dimension:refArea` (savivaldybė); `ltlod:taxpayer` → juridinis asmuo (JAR kodas); nepriemokos momentinė nuotrauka (`#this`) — `dct:temporal` → kalendoriaus diena, matai `ltlod:arrears`, `ltlod:overdueArrears`, `ltlod:deferredArrears`, `ltlod:deferredOverdueArrears`; sumokėti mokesčiai (`#paid-{metai}`) — `dct:temporal` → kalendoriaus metai, matas `ltlod:taxesPaid` (visi — EUR) | | Nemokumo bylos (AVNT) | `ltlod:InsolvencyProceeding` — viena byla viename dokumente; `dct:type` → nemokumo rūšis (bankrotas / restruktūrizavimas), `ltlod:insolvent` → juridinis asmuo (JAR kodas), `sdmx-dimension:refArea` → savivaldybė, `ltlod:court` → apygardos teismas, `ltlod:initiatedBy` → bankroto iniciatorius; bylos eiga — W3C [Time](https://www.w3.org/TR/owl-time/) `time:hasTime` → `time:Interval` (`#start` → `#end` `time:Instant` → kalendoriaus diena); loginiai požymiai `ltlod:outOfCourt`, `ltlod:simplified`, `ltlod:intentional` | | ES fondų finansavimas 2014–2020 (Finansų ministerija) | `ltlod:EUFundingContract` — viena įgyvendinimo sutartis viename dokumente; `dct:identifier` → projekto kodas, `ltlod:beneficiary` → paramos gavėjas, `ltlod:fundingPartner` → projekto partneriai (JAR kodas), `sdmx-dimension:refArea` → savivaldybė; matai `ltlod:euAmount` / `ltlod:totalAmount` / `ltlod:decidedEuAmount` (EUR); `dct:date` + `dct:temporal` → pradžios diena; loginiai požymiai `ltlod:stateAid` / `ltlod:deMinimisAid`. Nėra W3C/ES RDF žodyno sanglaudos projektams — tai `ltlod:` kaskados pabaiga | +| Viešojo sektoriaus sąskaitos (NBFC) | `ltlod:SpendingAggregate` — viena pirkėjo–tiekėjo–metų suvestinė viename dokumente; `ltlod:spendingBuyer` / `ltlod:spendingSupplier` → juridinis asmuo (JAR kodas), `dct:date` `xsd:gYear` + `dct:temporal` → kalendoriaus metai; matai `ltlod:invoiceCount`, `ltlod:billedTotal` (su PVM) / `ltlod:billedNet` (be PVM), EUR. Grynai suvestinė (~14,4 mln. sąskaitų per daug, kad kiekviena būtų atskiras dokumentas; šalių pavadinimai užšifruoti) — tai `ltlod:` kaskados pabaiga | | Asmenys | FOAF (+ suderinama su [Core Person 2.0](https://semiceu.github.io/Core-Person-Vocabulary/releases/2.00/)) | | Klasifikatoriai | [SKOS](https://www.w3.org/TR/skos-primer/) | | Bendrasis fallback | [schema.org](https://schema.org/) — tik kur W3C/ES termino nėra: galiojimo ir gyvavimo datos (`schema:validFrom`/`validThrough`, `schema:foundingDate`/`dissolutionDate`), `schema:PoliticalParty`, `schema:EventSeries`/`schema:Event` (sesijos, posėdžiai) | @@ -253,6 +257,9 @@ make -C eu-funds # ES struktūrinių fondų (2014–2020 m. # per get.data.gov.lt (finmin); ~26 tūkst. sutarčių, susietų su # paramos gavėjais ir partneriais (JAR), savivaldybe ir # kalendoriumi; failas neįtraukiamas į git +make -C public-spending # neprivaloma (nėra `make` sąraše): viešojo sektoriaus sąskaitų + # suvestinės pagal pirkėją–tiekėją–metus iš ~14,4 mln. sąskaitų + # (NBFC); ~40–90 min. atsiuntimas; failas neįtraukiamas į git make -C sodra # Sodros darbdavių duomenys iš naršykle atsisiųstų # data/monthly-{metai}.csv.zip (atvira.sodra.lt saugo Cloudflare; # SODRA_MONTHS=12 — kiek paskutinių mėnesių; @@ -455,7 +462,10 @@ Daugiau klausimų, į kuriuos duomenys jau atsako (visi su užklausomis ir pilna - kuriose savivaldybėse iškelta daugiausia bankroto bylų ir kaip jų skaičius kito pagal metus; - kurių politikų deklaruoti juridiniai asmenys gavo 2014–2020 m. ES struktūrinių fondų paramą (privatūs interesai × ES fondai per JAR kodą), ir kurios įmonės gavo ir ES paramą, ir laimėjo - viešuosius pirkimus (ES fondai × pirkimai per JAR kodą). + viešuosius pirkimus (ES fondai × pirkimai per JAR kodą); +- kuriems tiekėjams viešasis sektorius sumoka daugiausia smulkiomis sąskaitomis, kurių bendra + suma viršija viešųjų pirkimų ribą, nors pirkimų registre jų nėra (viešojo sektoriaus sąskaitos + × pirkimai per JAR kodą). Turto deklaracijų pjūviai pagal partiją, kadencijos pokyčius, turtą užsienyje ir dalyvavimą balsavimuose — duomenų istorijoje „Seimo turtas 2024“ (`app/stories/seimo-turtas-2024.ttl`). diff --git a/app/ns.ttl b/app/ns.ttl index b3151ad..50c0c2b 100644 --- a/app/ns.ttl +++ b/app/ns.ttl @@ -1199,6 +1199,44 @@ ltlod:implementationTill a owl:DatatypeProperty ; rdfs:range xsd:date ; rdfs:isDefinedBy : . +# Public-sector invoice aggregates (etl/public-spending/): buyer-supplier-year invoice totals. +# Buyer and supplier each link to the legal entity, so each has its own inverse view. +ltlod:SpendingAggregate a owl:Class ; + rdfs:label "Viešojo sektoriaus sąskaitų suvestinė"@lt, "Public-sector invoice aggregate"@en ; + rdfs:isDefinedBy : . + +ltlod:spendingBuyer a owl:ObjectProperty ; + rdfs:label "Pirkėjas"@lt, "Buyer"@en ; + rdfs:domain ltlod:SpendingAggregate ; + rdfs:range rov:RegisteredOrganization ; + ldh:inverseView :SpendingAsBuyer ; + rdfs:isDefinedBy : . + +ltlod:spendingSupplier a owl:ObjectProperty ; + rdfs:label "Tiekėjas"@lt, "Supplier"@en ; + rdfs:domain ltlod:SpendingAggregate ; + rdfs:range rov:RegisteredOrganization ; + ldh:inverseView :SpendingAsSupplier ; + rdfs:isDefinedBy : . + +ltlod:invoiceCount a owl:DatatypeProperty ; + rdfs:label "Sąskaitų skaičius"@lt, "Invoice count"@en ; + rdfs:domain ltlod:SpendingAggregate ; + rdfs:range xsd:integer ; + rdfs:isDefinedBy : . + +ltlod:billedTotal a owl:DatatypeProperty ; + rdfs:label "Sąskaitų suma su PVM, EUR"@lt, "Total billed incl. VAT, EUR"@en ; + rdfs:domain ltlod:SpendingAggregate ; + rdfs:range xsd:decimal ; + rdfs:isDefinedBy : . + +ltlod:billedNet a owl:DatatypeProperty ; + rdfs:label "Sąskaitų suma be PVM, EUR"@lt, "Net billed excl. VAT, EUR"@en ; + rdfs:domain ltlod:SpendingAggregate ; + rdfs:range xsd:decimal ; + rdfs:isDefinedBy : . + # the observation month as a literal (xsd:gYearMonth), for sorting dct:date a owl:DatatypeProperty ; rdfs:label "Mėnuo"@lt, "Month"@en ; @@ -1360,7 +1398,7 @@ eli-dl:had_voter_abstention a owl:ObjectProperty ; # person/facility through the instant. dct:temporal a owl:ObjectProperty ; rdfs:label "Laikas"@lt, "Time"@en ; - rdfs:domain [ owl:unionOf ( schema:Event eli-dl:Vote eli-dl:Activity eli-dl:DraftLegislationWork time:Instant ltlod:AssetDeclaration ltlod:CampaignDonation ltlod:CampaignExpense epo:Contract ltlod:LobbyingDeclaration ltlod:Lobbyist qb:Observation ltlod:LandAcquisitionApplication ltlod:LandAcquisitionDecision ltlod:EUFundingContract ) ] ; + rdfs:domain [ owl:unionOf ( schema:Event eli-dl:Vote eli-dl:Activity eli-dl:DraftLegislationWork time:Instant ltlod:AssetDeclaration ltlod:CampaignDonation ltlod:CampaignExpense epo:Contract ltlod:LobbyingDeclaration ltlod:Lobbyist qb:Observation ltlod:LandAcquisitionApplication ltlod:LandAcquisitionDecision ltlod:EUFundingContract ltlod:SpendingAggregate ) ] ; rdfs:range dct:PeriodOfTime ; ldh:inverseView :DaySittings, :DayVotes, :DayAgendaItems, :DayBills, :DayTerms, :DaySessions, :DayMembershipsBegan, :DayMembershipsEnded, :YearDeclarations, :DayRegistrations, :DayDeregistrations, :DayElections, :DayCampaignDonations, :DayCampaignExpenses, :DayFacilityRegistrations, :DayContracts, :DayLobbying, :DayLobbyistRegistrations, :DayInterestTies, :MonthEmployers, :DayLandApplications, :DayLandDecisions, :YearLandTotals, :DayInsolvencyProceedings, :DayEUFunding ; rdfs:isDefinedBy : . @@ -4209,6 +4247,57 @@ ORDER BY ?title """ ; rdfs:isDefinedBy : . +# Public-sector invoice aggregates (etl/public-spending/). A legal entity's buyer-supplier-year +# invoice totals, as the buyer (money it paid out) and as the supplier (money it billed the +# public sector); newest year first. No calendar-year view — a year spans millions of pairs. +:SpendingAsBuyer a ldh:View ; + dct:title "Viešojo sektoriaus sąskaitos (pirkėjas)"@lt, "Public-sector invoices (buyer)"@en ; + spin:query :SelectSpendingAsBuyer ; + ac:mode ac:TableMode ; + ldh:showWhenEmpty false ; + rdfs:isDefinedBy : . + +:SelectSpendingAsBuyer a sp:Select ; + rdfs:label "Select the legal entity's invoice aggregates as buyer" ; + sp:text """ +PREFIX dct: +PREFIX ltlod: +SELECT DISTINCT ?aggregate +WHERE + { GRAPH ?graph + { ?aggregate ltlod:spendingBuyer $about ; + a ltlod:SpendingAggregate ; + dct:date ?year + } + } +ORDER BY DESC(?year) +""" ; + rdfs:isDefinedBy : . + +:SpendingAsSupplier a ldh:View ; + dct:title "Viešojo sektoriaus sąskaitos (tiekėjas)"@lt, "Public-sector invoices (supplier)"@en ; + spin:query :SelectSpendingAsSupplier ; + ac:mode ac:TableMode ; + ldh:showWhenEmpty false ; + rdfs:isDefinedBy : . + +:SelectSpendingAsSupplier a sp:Select ; + rdfs:label "Select the legal entity's invoice aggregates as supplier" ; + sp:text """ +PREFIX dct: +PREFIX ltlod: +SELECT DISTINCT ?aggregate +WHERE + { GRAPH ?graph + { ?aggregate ltlod:spendingSupplier $about ; + a ltlod:SpendingAggregate ; + dct:date ?year + } + } +ORDER BY DESC(?year) +""" ; + rdfs:isDefinedBy : . + :MonthEmployers a ldh:View ; dct:title "Darbdaviai (Sodra)"@lt, "Employers (Sodra)"@en ; spin:query :SelectMonthEmployers ; diff --git a/app/public-spending.ttl b/app/public-spending.ttl new file mode 100644 index 0000000..d72e60e --- /dev/null +++ b/app/public-spending.ttl @@ -0,0 +1,55 @@ +@prefix dh: . +@prefix ldh: . +@prefix ac: . +@prefix rdf: . +@prefix dct: . +@prefix sp: . +@prefix spin: . + +<> a dh:Container ; + dct:title "Viešojo sektoriaus sąskaitos"@lt, "Public-sector invoices"@en ; + rdf:_1 <#intro> ; + rdf:_2 <#chart-top-block> . + +# rdf:_1..2 — intro + the largest single buyer→supplier invoice flows. No children listing +# (millions of buyer-supplier-year aggregates); an aggregate is reached from its buyer and +# its supplier legal-entity pages. + +<#intro> a ldh:XHTML ; + rdf:value """
+

Viešojo sektoriaus subjektų gautų sąskaitų faktūrų duomenys (Valstybės iždas, NBFC) — ~14,4 mln. sąskaitų, suvestų pagal pirkėją, tiekėją ir metus. Kiekviena suvestinė susieta su pirkėju ir tiekėju Juridinių asmenų registre (pagal įmonės kodą); sąskaitos šalių pavadinimai šaltinyje užšifruoti, todėl vardai imami iš registro.

+

Šie duomenys apima ir smulkius, žemiau viešųjų pirkimų ribų esančius pirkimus, kurių nematyti pirkimų registre — todėl pravartu lyginti su `procurement` rinkiniu. Suvestinė — ne atskira sąskaita: tai visų metų sąskaitų tarp dviejų subjektų suma ir skaičius.

+
"""^^rdf:XMLLiteral . + +<#chart-top-block> a ldh:Object ; + rdf:value <#chart-top> . + +<#chart-top> a ldh:ResultSetChart ; + dct:title "Didžiausi vienų metų pirkėjo–tiekėjo srautai"@lt, "Largest single buyer–supplier flows in a year"@en ; + spin:query <#chart-top-query> ; + ldh:chartType ac:Table ; + ldh:categoryVarName "pora" ; + ldh:seriesVarName "suma_eur" ; + ldh:seriesVarName "saskaitos" . + +<#chart-top-query> a sp:Select ; + dct:title "Didžiausios vienų metų sąskaitų sumos tarp pirkėjo ir tiekėjo"@lt, "The largest buyer-supplier invoice totals in a single year"@en ; + sp:text """PREFIX dct: +PREFIX ltlod: + +# The largest single buyer-supplier-year totals (one aggregate document), by the amount billed +# incl. VAT. The parties are shown by their JAR codes (the pair's document); names resolve on +# the linked legal-entities/ pages. +SELECT ?pora ?suma_eur ?saskaitos +WHERE +{ + GRAPH ?graph + { + ?aggregate a ltlod:SpendingAggregate ; + dct:title ?pora ; + ltlod:billedTotal ?suma_eur ; + ltlod:invoiceCount ?saskaitos . + } +} +ORDER BY DESC(?suma_eur) +LIMIT 20""" . diff --git a/app/stories/es-fondai-politiku-imones.ttl b/app/stories/es-fondai-politiku-imones.ttl new file mode 100644 index 0000000..7ea3ea5 --- /dev/null +++ b/app/stories/es-fondai-politiku-imones.ttl @@ -0,0 +1,155 @@ +@prefix dh: . +@prefix ldh: . +@prefix ac: . +@prefix rdf: . +@prefix dct: . +@prefix foaf: . +@prefix schema: . +@prefix sp: . +@prefix spin: . +@prefix xsd: . + +# A data story (see app/stories.ttl). The 2014-2020 EU funds and the PINREG ties are stable; the +# 12-month procurement window is current data, so the procurement figures are as of the 2026-10 +# datasets (stated in the method). + +<> a dh:Item ; + dct:title "ES fondai: politikų įmonės ir du pinigų srautai"@lt, "EU funds: politicians' companies and two money streams"@en ; + dct:description "2014–2020 m. ES fondų parama, sujungta su viešaisiais pirkimais ir politikų privačių interesų deklaracijomis — per įmonės kodą."@lt, "2014-2020 EU structural funds linked with public procurement and politicians' private-interest declarations — by company code."@en ; + foaf:primaryTopic <#this> ; + rdf:_1 <#lede> ; + rdf:_2 <#both-intro> ; + rdf:_3 <#both-block> ; + rdf:_4 <#politicians-intro> ; + rdf:_5 <#politicians-block> ; + rdf:_6 <#method> . + +<#this> a schema:Article ; + dct:title "ES fondai: politikų įmonės ir du pinigų srautai"@lt, "EU funds: politicians' companies and two money streams"@en ; + dct:description "2014–2020 m. ES fondų parama, sujungta su viešaisiais pirkimais ir politikų privačiais interesais."@lt, "2014-2020 EU funds linked with procurement and politicians' private interests."@en ; + schema:headline "ES fondai: politikų įmonės ir du pinigų srautai"@lt ; + schema:datePublished "2026-10-26"^^xsd:date ; + schema:inLanguage "lt" . + +<#lede> a ldh:XHTML ; + rdf:value """
+

2014–2020 m. Europos Sąjungos struktūrinių fondų parama (eu-funds) tą patį juridinį asmenį sujungia su viešaisiais pirkimais ir su politikų privačių interesų deklaracijomis (VTEK PINREG) — vis per tą patį Juridinių asmenų registro kodą. Taip matome, kurios įmonės gauna iš valstybės dviem srautais ir kurios iš jų susijusios su politikais.

+

Platus viešųjų pinigų pėdsakas savaime nėra pažeidimas — daug stambiausių gavėjų yra savivaldybių ar valstybės įmonės. Bet derinius ir ryšius verta turėti žemėlapyje. Didžioji dalis ES fondų įrašų — finansinių priemonių išmokos be atskiro projekto kodo ir be paskelbtos sumos; sumos žinomos tik maždaug 685 koduotiems projektams.

+
"""^^rdf:XMLLiteral . + +<#both-intro> a ldh:XHTML ; + rdf:value """
+

Du pinigų srautai tai pačiai įmonei

+

Daugiausia ES fondų tarp įmonių, kurios kartu laimėjo ir viešųjų pirkimų, gavo UAB „Vilniaus kogeneracinė jėgainė“ — apie 138 mln. Eur ES lėšų dviem projektams ir dar 6,6 mln. Eur viešųjų pirkimų sutarčių. Kiti stambūs gavėjai — daugiausia viešojo sektoriaus subjektai: bibliotekų asociacija (apie 26,8 mln. Eur ES), Vidaus vandens kelių direkcija (23,3 mln. Eur), regioniniai atliekų tvarkymo centrai. Lentelėje — ES fondų suma, projektų skaičius, pirkimų sutarčių skaičius ir jų vertė.

+
"""^^rdf:XMLLiteral . + +<#both-block> a ldh:Object ; + rdf:value <#both> . + +<#both> a ldh:ResultSetChart ; + dct:title "Įmonės, gavusios ir ES fondų, ir viešųjų pirkimų"@lt, "Companies with both EU funds and public contracts"@en ; + spin:query <#both-query> ; + ldh:chartType ac:Table ; + ldh:categoryVarName "imone" ; + ldh:seriesVarName "es_eur" ; + ldh:seriesVarName "es_projektai" ; + ldh:seriesVarName "pirkimai" ; + ldh:seriesVarName "pirkimu_verte_eur" . + +<#both-query> a sp:Select ; + dct:title "Įmonės, gavusios ir 2014–2020 m. ES fondų paramą, ir viešųjų pirkimų sutarčių"@lt, "Companies with both 2014-2020 EU funds and public contracts"@en ; + sp:text """PREFIX epo: +PREFIX skos: +PREFIX ltlod: + +# Companies that both received EU structural funds (as beneficiary) and won public contracts. +SELECT ?imone ?es_projektai ?es_eur ?pirkimai ?pirkimu_verte_eur +WHERE +{ + { + SELECT ?org (COUNT(DISTINCT ?contract) AS ?es_projektai) (SUM(?eu) AS ?es_eur) + WHERE + { + GRAPH ?fundingGraph + { + ?contract a ltlod:EUFundingContract ; + ltlod:beneficiary ?org . + OPTIONAL { ?contract ltlod:euAmount ?eu } + } + } + GROUP BY ?org + } + { + SELECT ?org (COUNT(DISTINCT ?pc) AS ?pirkimai) (ROUND(SUM(?value)) AS ?pirkimu_verte_eur) + WHERE + { + GRAPH ?contractGraph + { + ?pc epo:bindsContractor/epo:playedBy ?org ; + epo:hasContractValue/epo:hasAmountValue ?value . + } + } + GROUP BY ?org + } + GRAPH ?entityGraph { ?org skos:prefLabel ?imone } +} +ORDER BY DESC(?es_eur) +LIMIT 15""" . + +<#politicians-intro> a ldh:XHTML ; + rdf:value """
+

Politikų įmonės

+

Vienuolika dabartinių ir buvusių Seimo narių privačių interesų deklaracijose nurodė nuosavybės ar valdymo ryšį su įmone, kuri gavo 2014–2020 m. ES fondų paramą. Vienintelis su paskelbta ES suma — Vitalijus Mitrofanovas, UAB „Akmenės laisvoji ekonominė zona“ valdybos narys (apie 2,7 mln. Eur ES lėšų). Likusieji susiję su įmonėmis, gavusiomis finansinių priemonių išmokas be paskelbtos sumos. Ryšys su ES lėšas gavusia įmone — ką verta pasitikrinti, ne išvada: dalis šių ryšių — pareiginiai (pvz., narystė laisvųjų ekonominių zonų ar vietos veiklos grupių valdybose). Lentelėje — Seimo narys, įmonė, ryšio pobūdis, projektų skaičius ir ES suma (jei paskelbta).

+
"""^^rdf:XMLLiteral . + +<#politicians-block> a ldh:Object ; + rdf:value <#politicians> . + +<#politicians> a ldh:ResultSetChart ; + dct:title "Politikų įmonės, gavusios ES fondų paramą"@lt, "Politicians' companies that received EU funds"@en ; + spin:query <#politicians-query> ; + ldh:chartType ac:Table ; + ldh:categoryVarName "seimo_narys" ; + ldh:seriesVarName "imone" ; + ldh:seriesVarName "rysys" ; + ldh:seriesVarName "projektai" ; + ldh:seriesVarName "es_eur" . + +<#politicians-query> a sp:Select ; + dct:title "Seimo narių deklaruotos įmonės, gavusios 2014–2020 m. ES fondų paramą"@lt, "Seimas members' declared companies that received 2014-2020 EU funds"@en ; + sp:text """PREFIX foaf: +PREFIX org: +PREFIX skos: +PREFIX ltlod: + +# Officials whose declared ownership/control tie is to a company that received EU funds. +SELECT ?seimo_narys ?imone ?rysys (COUNT(DISTINCT ?contract) AS ?projektai) (SUM(?eu) AS ?es_eur) +WHERE +{ + GRAPH ?interestGraph + { + ?tie ltlod:interestOrganization ?org ; + org:member ?person ; + org:role ?role ; + ltlod:organizationName ?imone . + } + GRAPH ?roleGraph { ?role skos:notation ?roleCode ; skos:prefLabel ?rysys . FILTER(LANG(?rysys) = "lt") } + FILTER(?roleCode IN ("akcininkas", "dalininkas", "savininkas", "vadovas", + "vadovas-ar-jo-pavaduotojas", "valdybos-narys", "kolegialaus-valdymo-organo-narys", + "pirmininkas", "pirmininkas-ar-jo-pavaduotojas")) + GRAPH ?contractGraph + { + ?contract a ltlod:EUFundingContract ; + ltlod:beneficiary ?org . + OPTIONAL { ?contract ltlod:euAmount ?eu } + } + GRAPH ?personGraph { ?person foaf:name ?seimo_narys } +} +GROUP BY ?seimo_narys ?imone ?rysys +ORDER BY DESC(?es_eur) DESC(?projektai)""" . + +<#method> a ldh:XHTML ; + rdf:value """
+

Kaip tai suskaičiuota

+

Paramos gavėjas, pirkimų tiekėjas ir deklaruoto intereso įmonė — tas pats Juridinių asmenų registro įrašas (pagal įmonės kodą). ES fondai — 2014–2020 m. Finansų ministerijos duomenys (eu-funds): sumos žinomos tik koduotiems projektams, likę įrašai — finansinių priemonių išmokos be sumos. Lėšų grąžinimai ir nustatyti pažeidimai neįtraukti — jų šaltinio raktas yra neskelbiamo vidinio identifikatoriaus maiša. Viešieji pirkimai — paskutinių 12 mėn. langas (procurement-contracts; pirkimų skaičiai — 2026 m. spalio duomenų). Privatūs interesai — VTEK PINREG (interest-declarations); imami tik nuosavybės ir valdymo ryšiai, ne darbovietės ar eilinė narystė.

+
"""^^rdf:XMLLiteral . diff --git a/app/stories/rangovai-skolos-bankrotai.ttl b/app/stories/rangovai-skolos-bankrotai.ttl new file mode 100644 index 0000000..b02cd06 --- /dev/null +++ b/app/stories/rangovai-skolos-bankrotai.ttl @@ -0,0 +1,140 @@ +@prefix dh: . +@prefix ldh: . +@prefix ac: . +@prefix rdf: . +@prefix dct: . +@prefix foaf: . +@prefix schema: . +@prefix sp: . +@prefix spin: . +@prefix xsd: . + +# A data story (see app/stories.ttl). The arrears snapshot and the 12-month procurement window +# are current data, so the figures quoted in the text are as of the 2026-10 datasets (stated in +# the method); the insolvency register and its dates are historical and stable. + +<> a dh:Item ; + dct:title "Rangovai: skolos ir bankrotai"@lt, "Contractors: debts and insolvency"@en ; + dct:description "Kurie viešųjų pirkimų tiekėjai skolingi valstybei mokesčių arba eina per nemokumą — sujungus pirkimus su VMI nepriemokomis ir nemokumo byla."@lt, "Which public contractors owe the state tax or are going through insolvency — procurement linked with VMI arrears and the insolvency register."@en ; + foaf:primaryTopic <#this> ; + rdf:_1 <#lede> ; + rdf:_2 <#arrears-intro> ; + rdf:_3 <#arrears-block> ; + rdf:_4 <#insolvency-intro> ; + rdf:_5 <#insolvency-block> ; + rdf:_6 <#both-intro> ; + rdf:_7 <#method> . + +<#this> a schema:Article ; + dct:title "Rangovai: skolos ir bankrotai"@lt, "Contractors: debts and insolvency"@en ; + dct:description "Kurie viešųjų pirkimų tiekėjai skolingi valstybei mokesčių arba eina per nemokumą."@lt, "Which public contractors owe the state tax or are going through insolvency."@en ; + schema:headline "Rangovai: skolos ir bankrotai"@lt ; + schema:datePublished "2026-10-26"^^xsd:date ; + schema:inLanguage "lt" . + +<#lede> a ldh:XHTML ; + rdf:value """
+

Viešųjų pirkimų įstatymas draudžia sudaryti sutartį su tiekėju, turinčiu pradelstą įsiskolinimą valstybės biudžetui ar „Sodrai“. Bet įsiskolinimas gali atsirasti ir po sutarties. Sujungę viešųjų pirkimų tiekėjus su VMI mokestinėmis nepriemokomis ir įmonių nemokumo byla — visus per tą patį Juridinių asmenų registro kodą — matome, kurie valstybės rangovai šiuo metu skolingi mokesčių arba eina per bankrotą ar restruktūrizavimą.

+

Pradelsta nepriemoka ir viešųjų pirkimų langas (paskutiniai 12 mėn., sutartys nuo 10 000 Eur) — dabartiniai duomenys; nemokumo bylos — istorinės. Skolinga ar nemoki įmonė nebūtinai pažeidė sutartį: nepriemoka gali būti vėlesnė už sutartį, o restruktūrizuojama įmonė toliau veikia. Tai — ką verta pasitikrinti, ne išvada.

+
"""^^rdf:XMLLiteral . + +<#arrears-intro> a ldh:XHTML ; + rdf:value """
+

Rangovai su pradelsta mokestine nepriemoka

+

Viešųjų pirkimų tiekėjų, kurie šiuo metu turi pradelstą mokestinę nepriemoką — 852, bendra pradelsta suma — apie 3,8 mln. Eur. Didžiausią pradelstą nepriemoką turi UAB „Egmila“ (apie 270 tūkst. Eur), tačiau jos viešoji sutartis nedidelė. Įdomesni tie, kurie derina stambią nepriemoką su stambiomis sutartimis: UAB „Gigas“ — apie 250 tūkst. Eur pradelstos nepriemokos ir 13 sutarčių už 17,5 mln. Eur; UAB saugos tarnyba „Argus“ — 233 tūkst. Eur ir 19 sutarčių. Stulpelyje — pradelsta nepriemoka, Eur.

+
"""^^rdf:XMLLiteral . + +<#arrears-block> a ldh:Object ; + rdf:value <#arrears> . + +<#arrears> a ldh:ResultSetChart ; + dct:title "Viešųjų pirkimų tiekėjai su didžiausia pradelsta nepriemoka"@lt, "Public contractors with the largest overdue tax arrears"@en ; + spin:query <#arrears-query> ; + ldh:chartType ac:BarChart ; + ldh:categoryVarName "rangovas" ; + ldh:seriesVarName "nepriemoka_eur" . + +<#arrears-query> a sp:Select ; + dct:title "Pradelsta mokestinė nepriemoka — viešųjų pirkimų tiekėjai"@lt, "Overdue tax arrears of public contractors"@en ; + sp:text """PREFIX dct: +PREFIX qb: +PREFIX epo: +PREFIX skos: +PREFIX ltlod: + +# Public contractors with a current overdue tax arrears, by the overdue amount. +SELECT ?rangovas ?nepriemoka_eur +WHERE +{ + { SELECT DISTINCT ?contractor WHERE { GRAPH ?cg { ?c epo:bindsContractor/epo:playedBy ?contractor } } } + GRAPH ?taxGraph + { + ?observation ltlod:taxpayer ?contractor ; + a qb:Observation ; + ltlod:overdueArrears ?nepriemoka_eur . + } + FILTER(?nepriemoka_eur > 0) + GRAPH ?entityGraph { ?contractor skos:prefLabel ?rangovas } +} +ORDER BY DESC(?nepriemoka_eur) +LIMIT 15""" . + +<#insolvency-intro> a ldh:XHTML ; + rdf:value """
+

Rangovai nemokumo registre

+

Devyni pastarųjų 12 mėn. viešųjų pirkimų tiekėjai yra ar buvo nemokumo byloje. Daugiausia viešųjų sutarčių tarp jų laimėjo UAB „Alkesta“ — 54 sutartys už 49,2 mln. Eur, nuo 2022 m. lapkričio restruktūrizuojama. Restruktūrizuojama įmonė toliau veikia ir dalyvauja pirkimuose, tad tai dar ne požymis, kad sutartys neįvykdytos — bet finansiškai sunkus rangovas vertas dėmesio. Lentelėje — laimėtų sutarčių vertė, jų skaičius, bylos rūšis ir pradžia.

+
"""^^rdf:XMLLiteral . + +<#insolvency-block> a ldh:Object ; + rdf:value <#insolvency> . + +<#insolvency> a ldh:ResultSetChart ; + dct:title "Viešųjų pirkimų tiekėjai nemokumo registre"@lt, "Public contractors in the insolvency register"@en ; + spin:query <#insolvency-query> ; + ldh:chartType ac:Table ; + ldh:categoryVarName "rangovas" ; + ldh:seriesVarName "sutarciu_verte_eur" ; + ldh:seriesVarName "sutartys" ; + ldh:seriesVarName "rusis" ; + ldh:seriesVarName "pradzia" . + +<#insolvency-query> a sp:Select ; + dct:title "Viešųjų pirkimų tiekėjai, esantys nemokumo byloje"@lt, "Public contractors that are in an insolvency proceeding"@en ; + sp:text """PREFIX dct: +PREFIX epo: +PREFIX skos: +PREFIX ltlod: + +# Public contractors that appear in the insolvency register, with their won-contract value. +SELECT ?rangovas (SUM(?value) AS ?sutarciu_verte_eur) (COUNT(DISTINCT ?contract) AS ?sutartys) ?rusis ?pradzia +WHERE +{ + GRAPH ?contractGraph + { + ?contract epo:bindsContractor/epo:playedBy ?company ; + epo:hasContractValue/epo:hasAmountValue ?value . + } + GRAPH ?proceedingGraph + { + ?proceeding ltlod:insolvent ?company ; + a ltlod:InsolvencyProceeding ; + dct:date ?pradzia ; + dct:type ?typeConcept . + } + GRAPH ?typeGraph { ?typeConcept skos:prefLabel ?rusis . FILTER(LANG(?rusis) = "lt") } + GRAPH ?entityGraph { ?company skos:prefLabel ?rangovas } +} +GROUP BY ?company ?rangovas ?rusis ?pradzia +ORDER BY DESC(?sutarciu_verte_eur)""" . + +<#both-intro> a ldh:XHTML ; + rdf:value """
+

Ir skolingi, ir nemokūs

+

Trys viešųjų pirkimų tiekėjai vienu metu ir turi pradelstą mokestinę nepriemoką, ir yra nemokumo byloje — stipriausias finansinio sunkumo derinys. Ryškiausias — UAB „Egmila“: apie 270 tūkst. Eur pradelstos nepriemokos ir restruktūrizavimo byla. Tokių atvejų nedaug, bet būtent juos verta pasitikrinti pirmiausia: valstybė perka iš įmonės, kuri kartu jai skolinga ir nepajėgi atsiskaityti su kreditoriais.

+
"""^^rdf:XMLLiteral . + +<#method> a ldh:XHTML ; + rdf:value """
+

Kaip tai suskaičiuota

+

Tiekėjas, mokesčių mokėtojas ir nemoki įmonė — tas pats Juridinių asmenų registro įrašas (pagal įmonės kodą), tad jungimas nereikalauja papildomo žinyno. Viešieji pirkimai — paskutinių 12 mėn. langas, sutartys nuo 10 000 Eur (procurement-contracts). Mokestinė nepriemoka — dabartinė VMI momentinė nuotrauka (taxes): rodoma pradelsta nepriemoka, ne bendra. Nemokumo bylos — AVNT duomenys (insolvency-cases), bankrotai ir restruktūrizavimai nuo 2020 m. Skaičiai tekste — 2026 m. spalio duomenų; nepriemoka ir pirkimų langas kinta, todėl grafikai gali rodyti vėlesnius skaičius.

+
"""^^rdf:XMLLiteral . diff --git a/app/stories/saskaitu-skaidymas.ttl b/app/stories/saskaitu-skaidymas.ttl new file mode 100644 index 0000000..743b99c --- /dev/null +++ b/app/stories/saskaitu-skaidymas.ttl @@ -0,0 +1,134 @@ +@prefix dh: . +@prefix ldh: . +@prefix ac: . +@prefix rdf: . +@prefix dct: . +@prefix foaf: . +@prefix schema: . +@prefix sp: . +@prefix spin: . +@prefix xsd: . + +# A data story (see app/stories.ttl). The invoice aggregates are the whole public-sector +# invoice history (not a rolling window); the 12-month procurement window is current data, so +# the "no procurement contract" figures are as of the 2026-10 datasets (stated in the method). + +<> a dh:Item ; + dct:title "Smulkios sąskaitos, dideli pinigai"@lt, "Small invoices, big money"@en ; + dct:description "Viešojo sektoriaus sąskaitos faktūros atskleidžia smulkius pirkimus, kurių nematyti viešųjų pirkimų registre — sujungus su pirkimais per įmonės kodą."@lt, "Public-sector invoices reveal small purchases invisible to the procurement register — linked with procurement by company code."@en ; + foaf:primaryTopic <#this> ; + rdf:_1 <#lede> ; + rdf:_2 <#suppliers-intro> ; + rdf:_3 <#suppliers-block> ; + rdf:_4 <#flows-intro> ; + rdf:_5 <#flows-block> ; + rdf:_6 <#method> . + +<#this> a schema:Article ; + dct:title "Smulkios sąskaitos, dideli pinigai"@lt, "Small invoices, big money"@en ; + dct:description "Viešojo sektoriaus sąskaitos, kurių nematyti viešųjų pirkimų registre."@lt, "Public-sector invoices invisible to the procurement register."@en ; + schema:headline "Smulkios sąskaitos, dideli pinigai"@lt ; + schema:datePublished "2026-10-26"^^xsd:date ; + schema:inLanguage "lt" . + +<#lede> a ldh:XHTML ; + rdf:value """
+

Viešieji pirkimai parodo stambias sutartis, bet ne smulkius, žemiau skelbimo ribos esančius pirkimus. Juos atskleidžia viešojo sektoriaus sąskaitos faktūros (Valstybės iždas) — apie 14,4 mln. sąskaitų, suvestų pagal pirkėją, tiekėją ir metus. Sujungę šias suvestines su viešaisiais pirkimais per tą patį Juridinių asmenų registro kodą, matome, kiek viešųjų pinigų tiekėjams nuteka smulkiomis sąskaitomis, be jokios pirkimo sutarties registre.

+

Stambiausi sąskaitų srautai — valstybės finansiniai pervedimai (iždo, fondų), ne prekių ar paslaugų pirkimai, todėl čia žiūrime į tiekėjus, apmokamus daug mažų sąskaitų (vidutinė sąskaita — mažiau nei 10 000 Eur). Daug tokių tiekėjų — maisto, medicinos ar energijos tiekėjai, teikiantys nuolatines paslaugas pagal preliminariąsias sutartis; tai teisėta. Bet mastas rodo, kiek pirkimų vyksta pro pirkimų registrą.

+
"""^^rdf:XMLLiteral . + +<#suppliers-intro> a ldh:XHTML ; + rdf:value """
+

Tiekėjai be pirkimo sutarties

+

Tiekėjų, kuriems viešasis sektorius sumokėjo bent 30 000 Eur per ne mažiau kaip 10 smulkių (vidutiniškai iki 10 000 Eur) sąskaitų, tačiau kurie neturi nė vienos viešųjų pirkimų sutarties registre — 2 015, jiems iš viso apmokėta apie 920 mln. Eur. Daugiausia gavo UAB „Scandi Standard - Baltics“ — apie 81 mln. Eur per 25 tūkst. sąskaitų (vidutiniškai ~3 200 Eur), UAB „Medikona“ (50,6 mln. Eur) ir „Energijos tiekimas“ UAB (41 mln. Eur). Tai daugiausia maisto, medicinos ir energijos tiekėjai — nuolatinis tiekimas, bet pirkimų registre jų nėra. Stulpelyje — apmokėta suma, Eur.

+
"""^^rdf:XMLLiteral . + +<#suppliers-block> a ldh:Object ; + rdf:value <#suppliers> . + +<#suppliers> a ldh:ResultSetChart ; + dct:title "Daugiausiai smulkiomis sąskaitomis apmokami tiekėjai be pirkimo sutarties"@lt, "Top suppliers paid via small invoices with no procurement contract"@en ; + spin:query <#suppliers-query> ; + ldh:chartType ac:BarChart ; + ldh:categoryVarName "tiekejas" ; + ldh:seriesVarName "suma_eur" . + +<#suppliers-query> a sp:Select ; + dct:title "Tiekėjai, apmokami smulkiomis sąskaitomis, be viešųjų pirkimų sutarties"@lt, "Suppliers paid via small invoices with no procurement contract"@en ; + sp:text """PREFIX epo: +PREFIX skos: +PREFIX ltlod: + +# Suppliers paid >= 30 000 EUR over >= 10 small invoices (average under 10 000 EUR) across all +# years, that hold no public-procurement contract. The inner query groups per supplier first, so +# the procurement check runs only over those few thousand suppliers, not every aggregate. +SELECT ?tiekejas ?suma_eur ?saskaitos +WHERE +{ + { + SELECT ?supplier (ROUND(SUM(?total)) AS ?suma_eur) (SUM(?n) AS ?saskaitos) + WHERE + { + GRAPH ?spendingGraph + { + ?aggregate a ltlod:SpendingAggregate ; + ltlod:spendingSupplier ?supplier ; + ltlod:billedTotal ?total ; + ltlod:invoiceCount ?n . + } + } + GROUP BY ?supplier + HAVING (SUM(?total) >= 30000 && SUM(?n) >= 10 && (SUM(?total) / SUM(?n)) < 10000) + } + FILTER NOT EXISTS { GRAPH ?contractGraph { ?contract epo:bindsContractor/epo:playedBy ?supplier } } + GRAPH ?entityGraph { ?supplier skos:prefLabel ?tiekejas } +} +ORDER BY DESC(?suma_eur) +LIMIT 20""" . + +<#flows-intro> a ldh:XHTML ; + rdf:value """
+

Didžiausi vienų metų srautai

+

Vienos poros — pirkėjo ir tiekėjo — vienų metų sąskaitų sumos irgi pasako nemažai: pastovus, stambus srautas tarp dviejų subjektų dažnai reiškia preliminariąją sutartį arba nuolatinį tiekėją. Lentelėje — didžiausios vienų metų sumos tarp pirkėjo ir tiekėjo (su PVM), sąskaitų skaičius ir metai; abu subjektai rodomi kodais, vardai atsiveria jų registro puslapiuose.

+
"""^^rdf:XMLLiteral . + +<#flows-block> a ldh:Object ; + rdf:value <#flows> . + +<#flows> a ldh:ResultSetChart ; + dct:title "Didžiausios vienų metų pirkėjo–tiekėjo sąskaitų sumos"@lt, "Largest single buyer–supplier invoice totals in a year"@en ; + spin:query <#flows-query> ; + ldh:chartType ac:Table ; + ldh:categoryVarName "pora" ; + ldh:seriesVarName "suma_eur" ; + ldh:seriesVarName "saskaitos" ; + ldh:seriesVarName "metai" . + +<#flows-query> a sp:Select ; + dct:title "Didžiausios vienų metų sąskaitų sumos tarp pirkėjo ir tiekėjo (be stambiausių finansinių pervedimų)"@lt, "The largest buyer-supplier invoice totals in a single year (excluding the largest financial transfers)"@en ; + sp:text """PREFIX dct: +PREFIX ltlod: + +# The largest single buyer-supplier-year totals among the small-invoice flows (average invoice +# under 10 000 EUR), which filters out the state financial transfers that dominate by value. +SELECT ?pora ?suma_eur ?saskaitos ?metai +WHERE +{ + GRAPH ?graph + { + ?aggregate a ltlod:SpendingAggregate ; + dct:title ?pora ; + dct:date ?metai ; + ltlod:billedTotal ?suma_eur ; + ltlod:invoiceCount ?saskaitos . + } + FILTER(?saskaitos >= 10 && (?suma_eur / ?saskaitos) < 10000) +} +ORDER BY DESC(?suma_eur) +LIMIT 20""" . + +<#method> a ldh:XHTML ; + rdf:value """
+

Kaip tai suskaičiuota

+

Sąskaitų tiekėjas ir pirkimų tiekėjas — tas pats Juridinių asmenų registro įrašas (pagal įmonės kodą). Sąskaitos — Valstybės iždo (NBFC) viešojo sektoriaus sąskaitų faktūrų duomenys (public-spending), suvesti pagal pirkėją, tiekėją ir metus; skelbiamos poros, kurių metinė suma su PVM ≥ 1 000 Eur (atmetus ~63 % nulinės sumos kreditinių/PVM įrašų). Šalių pavadinimai šaltinyje užšifruoti, todėl imami iš registro. Viešieji pirkimai — paskutinių 12 mėn. langas (procurement-contracts), todėl „be pirkimo sutarties“ — 2026 m. spalio būsena. Didelis smulkių sąskaitų srautas nėra pažeidimas — dažnai tai preliminariosios sutartys ar komunalinės paslaugos; bet jis rodo, kiek pirkimų lieka už pirkimų registro ribų.

+
"""^^rdf:XMLLiteral . diff --git a/etl/Makefile b/etl/Makefile index 7e89a98..0b7971d 100644 --- a/etl/Makefile +++ b/etl/Makefile @@ -3,9 +3,10 @@ # make # everything, in dependency order # make BASE=https://my-ldh-instance.example/ # custom base URI # make admin-units | seimas | officials | declarations | legal-entities | facilities | procurement | vtek | land-acquisitions | taxonomies | calendar | elections -# make sodra # opt-in: needs the browser-harvested Sodra zips in sodra/data/ +# make sodra # opt-in: needs the browser-harvested Sodra zips in sodra/data/ +# make public-spending # opt-in: ~46M-row public-sector invoice fetch (~40-90 min) -DOMAINS := taxonomies calendar admin-units seimas officials declarations legal-entities elections facilities procurement vtek land-acquisitions taxes insolvency eu-funds sodra +DOMAINS := taxonomies calendar admin-units seimas officials declarations legal-entities elections facilities procurement vtek land-acquisitions taxes insolvency eu-funds public-spending sodra .PHONY: all clean $(DOMAINS) @@ -23,6 +24,8 @@ DOMAINS := taxonomies calendar admin-units seimas officials declarations legal-e # municipalities; a plain Spinta fetch, committed output # eu-funds after legal-entities and admin-units — contracts link to beneficiaries/partners # (by bare JAR code) and municipalities; a plain Spinta fetch, gitignored bulk output +# public-spending — NOT in `all`: a ~46M-row fetch (~40-90 min) of the public-sector invoice +# feeds, aggregated per buyer-supplier-year; run on demand (make -C etl public-spending) all: taxonomies calendar admin-units seimas officials declarations legal-entities elections facilities procurement vtek land-acquisitions taxes insolvency eu-funds $(DOMAINS): diff --git a/etl/ONTOLOGY-NOTES.md b/etl/ONTOLOGY-NOTES.md index 878bf86..237892e 100644 --- a/etl/ONTOLOGY-NOTES.md +++ b/etl/ONTOLOGY-NOTES.md @@ -105,6 +105,7 @@ authority table except for settlements. Each `time:Interval` has `time:hasBeginn | Legal-entity taxes (VMI) | W3C **Data Cube** (`qb:DataSet` + `qb:DataStructureDefinition`, `qb:Observation`) + **SDMX-RDF** `sdmx-dimension:refArea` (→ the registration municipality, AR `sav_kodas`); custom dimension **`ltlod:taxpayer`** (→ `legal-entities/{ja_kodas}/#this`); the arrears snapshot (`#this`) carries `dct:temporal` → the calendar **day** (+ `dct:date` `xsd:date`) and measures **`ltlod:arrears`**, **`ltlod:overdueArrears`**, **`ltlod:deferredArrears`**, **`ltlod:deferredOverdueArrears`** (EUR); taxes paid (`#paid-{yyyy}`) carry `dct:temporal` → the calendar **year** (+ `dct:date` `xsd:gYear`) and measure **`ltlod:taxesPaid`** (EUR) | The two VMI feeds (current arrears per entity; taxes paid per entity per year) are both observations keyed on the taxpayer, so Data Cube is the same fit as the Sodra employer figures, and the taxpayer document reuses the shape (`#this` the arrears snapshot — the document topic, present even for an entity that owes nothing but paid tax — plus one `#paid-{yyyy}` observation per reporting year). No W3C/EU/SDMX measure exists for tax arrears or taxes paid, hence `ltlod:` (typed `qb:MeasureProperty` in `ns.ttl`, all EUR). `ltlod:taxpayer` links by bare JAR code, so it joins procurement contractors, Sodra employers and campaign donors with no lookup; it dangles until the full JAR register is loaded. Amounts are kept as VMI publishes them; a measure absent (not zero) means VMI publishes no value. The calendar day (one publication date, tens of thousands of entities) and year (every taxpaying company) carry the `dct:temporal` link but get no calendar listing — neither population fits a calendar page's budget, unlike a day's procurement contracts. | | Insolvency (AVNT bankruptcy / restructuring) | custom **`ltlod:InsolvencyProceeding`** (one per proceeding); `dct:type` → `taxonomies/insolvency-types/` (`bankrotas` / `restrukturizavimas`); **`ltlod:insolvent`** → `legal-entities/{imones_kodas}/#this` (+ `ltlod:companyCode`/`ltlod:companyName` literals); `sdmx-dimension:refArea` → the municipality; **`ltlod:court`** → `taxonomies/courts/` (5 apygardos teismai), **`ltlod:initiatedBy`** → `taxonomies/insolvency-initiators/`; lifecycle as W3C **Time** `time:hasTime` → `time:Interval` (`#period`) → `#start` / `#end` `time:Instant` → `dct:temporal` calendar day (begin always, end when the proceeding closed); boolean flags **`ltlod:outOfCourt`**, **`ltlod:simplified`**, **`ltlod:intentional`** + `ltlod:intentionalDate` / `ltlod:liquidationDate` / `ltlod:deregistrationDate` literals | No W3C/EU/schema.org vocabulary for insolvency proceedings (ePO covers procurement only; the EU has no insolvency ontology), so the proceeding class is the `ltlod:` end of the cascade, but its shape reuses the project's norms: the legal-entity link by bare code (dangles until the full JAR loads), the municipality by AR `sav_kodas`, and the period as the same `time:hasTime` interval as Seimas terms and legal-entity registration, so a day page reaches the proceeding through its `#start`/`#end` instant. The AVNT **territory code** (`teritorijos_kodas`, a 4-digit `26XX` statistical code, 7-digit for sub-municipal rows) crosswalks to the AR `sav_kodas` by its last two digits — `2611`→`11` Alytus, `2641`→`41` Vilnius r. — with one hardcoded exception (`2601`→`13`, Vilnius city) and one defunct code with no current municipality (`2651`, the Marijampolė district abolished in 2000); the start date coalesces `bankroto_data` (court) with `ne_teismo_tvarka` (out-of-court). The three sources overlap: `BankrotoAtaskaitosDatos` (2020+, full fields) carries the intentional-bankruptcy date inline, and `TycinisBankrotas` (1994–2025) adds the ~630 intentional bankruptcies that predate 2020 as their own proceedings (its court/dates only); `...Finansai` financials are **left out** — their `eil_nr` key joins to no company code in the report tables. | | EU structural funds 2014-2020 (finmin) | custom **`ltlod:EUFundingContract`** (one per implementation contract); `dct:identifier` → the project code (coded ones); **`ltlod:beneficiary`** → `legal-entities/{executor_code}/#this` (+ `ltlod:beneficiaryCode`/`ltlod:beneficiaryName`), **`ltlod:fundingPartner`** → the partners; `sdmx-dimension:refArea` → the municipality; measures `ltlod:euAmount` / `ltlod:totalAmount` / `ltlod:decidedEuAmount` (EUR); `dct:date` + `dct:temporal` → the start day; `ltlod:implementationFrom`/`Till` date literals; booleans `ltlod:stateAid` / `ltlod:deMinimisAid` | No W3C/EU RDF vocabulary for cohesion-fund projects dereferences (EU Kohesio is an app, not a published ontology; ePO is procurement-only), so the class is the `ltlod:` end of the cascade; the beneficiary/partner links reuse the bare-JAR-code join (dangle until the full register loads) and the municipality the AR `sav_kodas` (crosswalked from the free-text name). One `Contract` per document keyed by the Spinta `_id` (no business key: most records are code-less financial-instrument payouts, e.g. partial interest compensation to SMEs; only ~685 carry a formal project code with amounts via the `paraiskos/Project` ref and a `ConFinSource` breakdown). Partners and fin sources join by `Contract._id`. **Repayments and irregularities (`sutartys/Repayment`, `kontroles_veiksmai/Suspicion`) are not modelled**: they are keyed by an opaque `project_hash`/`project_hash_id` that is a hash of an unpublished internal SFMIS id — tested 2026-10-25, it matches no standard hash (md5/sha*/crc/blake, salted, prefix/suffix) of any published id (code, `_id`, `project_id`, `Contract._id`), so repayments and pažeidimai cannot be attributed to a beneficiary. The 2021-2027 programme is not on Spinta. | +| Public-sector invoices (NBFC) | custom **`ltlod:SpendingAggregate`** (one per buyer-supplier-year); **`ltlod:spendingBuyer`** / **`ltlod:spendingSupplier`** → `legal-entities/{code}/#this`; `dct:date` `xsd:gYear` + `dct:temporal` → the calendar **year**; measures `ltlod:invoiceCount`, `ltlod:billedTotal` (incl. VAT) / `ltlod:billedNet` (excl. VAT), EUR | No W3C/EU vocabulary models invoice spending between two organisations over a period; a Data Cube with two organisation dimensions plus a year would fit but needs a DSD per pair-measure and buys little here, so the aggregate is a plain `ltlod:` class with the two party links (each carrying its own inverse view, buyer / supplier). The grain is an **aggregate**, not an invoice: the source is ~14.4M invoices (`Saskaitos`) and ~32M party rows (`SaskaituSalys`), far too many to publish one document each, and the party names are pseudonymised — so ETL sums them per (buyer JAR, supplier JAR, year). The join is `SaskaituSalys.sf_id` = `Saskaitos.sf_id` normalized to an `LT` prefix (the source spells it inconsistently); the party side cannot be windowed by invoice year (`SaskaituSalys.data` is a 2020-era registration date), so the whole table is streamed into SQLite and joined there. Parties without a JAR code (pseudonymised natural persons, foreign parties) are dropped. Gitignored bulk output. These small, sub-threshold invoices are what the procurement register does not show — hence the `suppliers-under-threshold` cross-domain case. | | Validity dates | `schema:validFrom` / `schema:validThrough` (admin units), `schema:foundingDate` / `schema:dissolutionDate` (legal entities) | No EU RDF term for registry lifecycle dates (INSPIRE models them as `beginLifespanVersion` in GML only). | ## Legacy vocabulary disposition (2012 datasets) diff --git a/etl/URI-SCHEME.md b/etl/URI-SCHEME.md index 6f112a4..571e333 100644 --- a/etl/URI-SCHEME.md +++ b/etl/URI-SCHEME.md @@ -101,6 +101,7 @@ None exists yet; the subdomain naming rule is still open. | `taxes/dataset/` | fixed slug (never collides: taxpayer slugs are digits) | `qb:DataSet`s (`#this` arrears, `#paid` taxes paid per year) + their `qb:DataStructureDefinition`s | generated (`etl/taxes/mappings/dataset.rq`), committed | | `insolvency-cases/{imones_kodas}-{start}/` | legal-entity code + the proceeding's start date (`305544521-2024-09-04`) | `ltlod:InsolvencyProceeding` (`ltlod:insolvent` → `legal-entities/{imones_kodas}/#this`) | AVNT via get.data.gov.lt (bankruptcies `avnt/imoniu_bankrotas` + restructurings `avnt/imoniu_restrukturizavimas` + intentional `avnt/tyciniai_bankrotai`, `ltlod-insolvency`); committed | | `eu-funds/{_id}/` | the source Spinta `_id` (no business key — most records are code-less instrument payouts) | `ltlod:EUFundingContract` (`ltlod:beneficiary`/`ltlod:fundingPartner` → `legal-entities/{code}/#this`) | 2014-2020 EU structural funds, Finance Ministry via get.data.gov.lt (`finmin/sutartys/Contract` ⋈ `ConPartner`/`ConFinSource` ⋈ `finmin/paraiskos/Project`, `ltlod-eu-funds`); gitignored bulk output | +| `public-spending/{buyer}-{supplier}-{year}/` | buyer JAR code + supplier JAR code + invoice year | `ltlod:SpendingAggregate` (`ltlod:spendingBuyer`/`ltlod:spendingSupplier` → `legal-entities/{code}/#this`) | public-sector invoice totals, State Treasury (NBFC) via get.data.gov.lt (`nbfc/viesojo_sektoriaus_saskaitos`: `Saskaitos` ⋈ `SaskaituSalys`, aggregated by `ltlod-public-spending`); gitignored bulk output | | `constituencies/{kadencijos_id}-{nr}/` | Seimas term id + single-member electoral-district number (districts are redrawn every election, so the number alone is ambiguous) | `ltlod:ElectoralDistrict` | apps.lrs.lt members feed (`išrinkimo_būdas`) — **not** an admin unit, own container | | `elections/{slug}/` | `seimas-{year}` — the election type and year (one Seimas election per year at most; a future municipal/presidential/EP pipeline adds its own prefix) | `ltlod:Election` + `schema:Event` | VRK results map (ArcGIS feature services), `etl/elections/data/elections.csv` for dates and terms | | `election-results/{election}-{nr}/` | election slug + single-member constituency number (`seimas-2024-1`); the constituency is `constituencies/{kadencijos_id}-{nr}/`, the term derived from the election | `ltlod:ConstituencyContest` | VRK results map, `LRS_{year}_V_T1/T2_APG` + `LRS_{year}_D_APG` layers | diff --git a/etl/public-spending/Makefile b/etl/public-spending/Makefile new file mode 100644 index 0000000..2752b85 --- /dev/null +++ b/etl/public-spending/Makefile @@ -0,0 +1,38 @@ +include ../config.mk + +# Public-sector invoice totals from the State Treasury (NBFC) open data on get.data.gov.lt +# (datasets/gov/nbfc/viesojo_sektoriaus_saskaitos): ~14.4M invoices (Saskaitos) joined to their +# ~32M party rows (SaskaituSalys) and aggregated per (buyer, supplier, year). ltlod-public-spending +# streams both feeds (keyset-paginated) into a temporary on-disk SQLite db and aggregates there — +# the party rows cannot be windowed by invoice year, so the whole table is read (~40-90 min fetch). +# Buyer and supplier link to legal-entities/{code}/#this by the bare JAR code. Gitignored bulk output. +# make -C etl/public-spending + +CACHE := cache +OUT := ../../datasets/current/public-spending + +# only publish a (buyer, supplier, year) whose billed total (incl. VAT) reaches MIN_TOTAL EUR; +# the default drops the ~63% zero-total credit-note/VAT pairs and the long tail of trivial flows +# (~3.9M aggregates -> ~433k). Lower it (MIN_TOTAL=0) for the complete set. +MIN_TOTAL ?= 1000 + +.PHONY: all clean FORCE +all: $(OUT)/aggregates.trig + +$(CACHE)/aggregates.csv: FORCE + @mkdir -p $(CACHE) + uv run --project ../tools ltlod-public-spending --min-total $(MIN_TOTAL) \ + --output $(CACHE)/aggregates.csv --db $(CACHE)/pubspend.sqlite + +$(CACHE)/%.nt: $(CACHE)/%.csv + $(LIB)/csv2rdf.sh $< $(BASE) > $@ + +$(OUT)/aggregates.trig: $(CACHE)/aggregates.nt mappings/aggregates.rq + @mkdir -p $(OUT) + $(LIB)/graphify.sh mappings/aggregates.rq $(BASE) $< > $@ + JVM_ARGS=-Xmx8g $(LIB)/validate.sh $@ $(BASE) $$(($$(wc -l < $(CACHE)/aggregates.csv) - 1)) + +clean: + rm -rf $(CACHE) + +FORCE: diff --git a/etl/public-spending/mappings/aggregates.rq b/etl/public-spending/mappings/aggregates.rq new file mode 100644 index 0000000..38a4803 --- /dev/null +++ b/etl/public-spending/mappings/aggregates.rq @@ -0,0 +1,58 @@ +PREFIX dct: +PREFIX foaf: +PREFIX xsd: +PREFIX ltlod: + +PREFIX dh: +PREFIX sioc: + +# Public-sector invoice totals per (buyer, supplier, year), aggregated by ltlod-public-spending +# from the ~14.4M invoices of nbfc/viesojo_sektoriaus_saskaitos. One ltlod:SpendingAggregate per +# document, keyed by {buyer}-{supplier}-{year}. Buyer and supplier link to legal-entities/{code}/ +# #this by the bare JAR code (the source pseudonymises the party names, so names come from the +# register, not here). The year is a calendar year (dct:temporal). Amounts in EUR: the total +# billed (incl. VAT) and the net (excl. VAT); plus the invoice count. +CONSTRUCT +{ + GRAPH ?graph + { + ?graph a dh:Item ; + dct:created ?now ; + sioc:has_container ?container ; + dct:title ?title ; + foaf:primaryTopic ?this . + + ?this a ltlod:SpendingAggregate ; + dct:title ?title ; + ltlod:spendingBuyer ?buyer ; + ltlod:spendingSupplier ?supplier ; + dct:date ?yearLit ; + dct:temporal ?yearDoc ; + ltlod:invoiceCount ?invoices ; + ltlod:billedTotal ?total ; + ltlod:billedNet ?net . + } +} +WHERE +{ + ?row <#buyer_code> ?buyerCode ; + <#supplier_code> ?supplierCode ; + <#year> ?year ; + <#invoices> ?invoicesRaw ; + <#total_eur> ?totalRaw ; + <#net_eur> ?netRaw . + + BIND(uri(concat(str($base), "public-spending/")) AS ?container) + BIND(uri(concat(str($base), "public-spending/", ?buyerCode, "-", ?supplierCode, "-", ?year, "/")) AS ?graph) + BIND(uri(concat(str(?graph), "#this")) AS ?this) + BIND(uri(concat(str($base), "legal-entities/", ?buyerCode, "/#this")) AS ?buyer) + BIND(uri(concat(str($base), "legal-entities/", ?supplierCode, "/#this")) AS ?supplier) + BIND(STRDT(?year, xsd:gYear) AS ?yearLit) + BIND(uri(concat(str($base), "calendar/", ?year, "/#this")) AS ?yearDoc) + BIND(STRDT(?invoicesRaw, xsd:integer) AS ?invoices) + BIND(STRDT(?totalRaw, xsd:decimal) AS ?total) + BIND(STRDT(?netRaw, xsd:decimal) AS ?net) + BIND(STRLANG(CONCAT("Sąskaitos ", ?buyerCode, " – ", ?supplierCode, " (", ?year, ")"), "lt") AS ?title) + + BIND(NOW() AS ?now) +} diff --git a/etl/shapes/public-spending.ttl b/etl/shapes/public-spending.ttl new file mode 100644 index 0000000..cda3999 --- /dev/null +++ b/etl/shapes/public-spending.ttl @@ -0,0 +1,27 @@ +# SHACL shapes for public-sector invoice aggregates (datasets/current/public-spending/*.trig, +# etl/public-spending/mappings/aggregates.rq). One ltlod:SpendingAggregate per document, keyed +# by buyer-supplier-year; every one carries both parties (JAR codes), the calendar year, the +# invoice count and the billed / net totals. + +PREFIX sh: +PREFIX rdf: +PREFIX xsd: +PREFIX dct: +PREFIX ltlod: +PREFIX : + +:SpendingAggregateShape a sh:NodeShape ; + sh:targetClass ltlod:SpendingAggregate ; + sh:property + [ sh:path dct:title ; sh:datatype rdf:langString ; + sh:languageIn ("lt") ; sh:minCount 1 ; sh:maxCount 1 ] , + [ sh:path ltlod:spendingBuyer ; sh:nodeKind sh:IRI ; sh:minCount 1 ; sh:maxCount 1 ; + sh:pattern "/legal-entities/[^/]+/#this$" ] , + [ sh:path ltlod:spendingSupplier ; sh:nodeKind sh:IRI ; sh:minCount 1 ; sh:maxCount 1 ; + sh:pattern "/legal-entities/[^/]+/#this$" ] , + [ sh:path dct:date ; sh:datatype xsd:gYear ; sh:minCount 1 ; sh:maxCount 1 ] , + [ sh:path dct:temporal ; sh:nodeKind sh:IRI ; sh:minCount 1 ; sh:maxCount 1 ; + sh:pattern "/calendar/[0-9]{4}/#this$" ] , + [ sh:path ltlod:invoiceCount ; sh:datatype xsd:integer ; sh:minCount 1 ; sh:maxCount 1 ] , + [ sh:path ltlod:billedTotal ; sh:datatype xsd:decimal ; sh:minCount 1 ; sh:maxCount 1 ] , + [ sh:path ltlod:billedNet ; sh:datatype xsd:decimal ; sh:minCount 1 ; sh:maxCount 1 ] . diff --git a/etl/tools/pyproject.toml b/etl/tools/pyproject.toml index 612db00..d3586c1 100644 --- a/etl/tools/pyproject.toml +++ b/etl/tools/pyproject.toml @@ -28,6 +28,7 @@ ltlod-sodra = "ltlod_etl.sodra:main" ltlod-land = "ltlod_etl.land_acquisitions:main" ltlod-insolvency = "ltlod_etl.insolvency:main" ltlod-eu-funds = "ltlod_etl.eu_funds:main" +ltlod-public-spending = "ltlod_etl.public_spending:main" ltlod-taxes = "ltlod_etl.taxes:main" ltlod-audit = "ltlod_etl.audit:main" diff --git a/etl/tools/src/ltlod_etl/public_spending.py b/etl/tools/src/ltlod_etl/public_spending.py new file mode 100644 index 0000000..4d0cf8e --- /dev/null +++ b/etl/tools/src/ltlod_etl/public_spending.py @@ -0,0 +1,162 @@ +"""Aggregate public-sector invoices (get.data.gov.lt, nbfc/viesojo_sektoriaus_saskaitos) into +buyer-supplier-year totals for CSV2RDF: + + aggregates.csv buyer_code,supplier_code,year,invoices,total_eur,net_eur + +The source is huge — ~14.4M invoices (Saskaitos) and ~32M invoice-party rows (SaskaituSalys) — +and the party rows cannot be windowed by invoice year (their `data` is a 2020-era registration +date, unrelated to the invoice date), so the whole party table must be read to attribute each +invoice to its buyer and supplier. Both feeds are therefore streamed, keyset-paginated on _id, +into a temporary on-disk SQLite database and joined/aggregated there (low memory for tens of +millions of rows). + +Join (verified 2026-10-25): SaskaituSalys.sf_id = Saskaitos.sf_id normalized to an "LT" prefix +(the source spells it inconsistently); tipas "Pirkėjas" is the buyer, "Tiekėjas" the supplier, +each identified by validus_jar_kodas (a JAR code). Party names (pavadinimas) are pseudonymised +in the source, so names are not taken from here — they come from legal-entities/ by the code. +Rows without a JAR code (natural persons, pseudonymised; foreign parties) are dropped. One +output row per (buyer JAR, supplier JAR, invoice year): the invoice count, the total billed +(bendra_sf_suma, incl. VAT) and the net total (suma_be_pvm). +""" + +import argparse +import csv +import io +import os +import sqlite3 +import sys +import tempfile +import time + +import httpx + +API = "https://get.data.gov.lt/datasets/gov/nbfc/viesojo_sektoriaus_saskaitos" +PAGE = 50000 + + +def norm_sf(sf: str) -> str: + sf = (sf or "").strip() + return sf[2:] if sf.startswith("LT") else sf + + +def stream(client: httpx.Client, model: str, select: str, handle) -> int: + """Keyset-paginate a model on _id, passing each page's rows to `handle`. Lossless even if a + page is truncated by the export size cap (the next page resumes after the last _id).""" + rows = 0 + last = "" + while True: + q = f"select(_id,{select})&sort(_id)&limit({PAGE})" + if last: + q += f"&_id>'{last}'" + url = f"{API}/{model}/:format/csv?{q}" + page = None + for attempt in range(5): + try: + r = client.get(url) + if r.status_code == 200 and r.text.startswith("_id"): + page = list(csv.DictReader(io.StringIO(r.text))) + break + print(f"WARN {model}: HTTP {r.status_code}", file=sys.stderr) + except httpx.HTTPError as e: + print(f"WARN {model}: {e}", file=sys.stderr) + time.sleep(5 * 2 ** attempt) + else: + sys.exit(f"ERROR: {model} kept failing: {url[:160]}") + if not page: + break + handle(page) + rows += len(page) + last = page[-1]["_id"] + if rows % 500000 < PAGE: + print(f" {model}: {rows} rows", file=sys.stderr) + if not rows: + sys.exit(f"ERROR: {model} returned no rows") + print(f" {model}: {rows} rows total", file=sys.stderr) + return rows + + +def main() -> None: + ap = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + ap.add_argument("--output", required=True, help="output: one row per buyer-supplier-year") + ap.add_argument("--db", help="SQLite work file (default: a temp file, removed after)") + ap.add_argument("--min-total", type=float, default=1000.0, + help="only publish a (buyer, supplier, year) whose billed total (incl. VAT) " + "reaches this many EUR (default 1000; drops the ~63%% of zero-total " + "credit-note/VAT pairs and the long tail of trivial flows)") + ap.add_argument("--reaggregate", action="store_true", + help="skip the fetch and re-aggregate an existing --db (e.g. a new --min-total)") + args = ap.parse_args() + + db_path = args.db or tempfile.mktemp(suffix=".sqlite", prefix="pubspend-") + con = sqlite3.connect(db_path) + if not args.reaggregate: + con.executescript(""" + PRAGMA journal_mode=OFF; PRAGMA synchronous=OFF; + DROP TABLE IF EXISTS party; DROP TABLE IF EXISTS invoice; + CREATE TABLE party (sf TEXT, tipas TEXT, jar TEXT, PRIMARY KEY (sf, tipas)) WITHOUT ROWID; + CREATE TABLE invoice (sf TEXT, year TEXT, gross REAL, net REAL); + """) + + def put_parties(page): + batch = [] + for r in page: + jar = (r.get("validus_jar_kodas") or "").strip() + tipas = (r.get("tipas") or "").strip() + if not jar or tipas not in ("Pirkėjas", "Tiekėjas"): + continue + batch.append((norm_sf(r.get("sf_id", "")), tipas, jar)) + # first party per (sf, tipas) wins (an invoice has one buyer and one supplier) + con.executemany("INSERT OR IGNORE INTO party VALUES (?,?,?)", batch) + + def put_invoices(page): + batch = [] + for r in page: + d = (r.get("israsymo_data") or "").strip() + if len(d) < 4: + continue + def num(v): + v = (v or "").strip() + try: + return float(v) + except ValueError: + return 0.0 + batch.append((norm_sf(r.get("sf_id", "")), d[:4], + num(r.get("bendra_sf_suma")), num(r.get("suma_be_pvm")))) + con.executemany("INSERT INTO invoice VALUES (?,?,?,?)", batch) + + if not args.reaggregate: + with httpx.Client(timeout=600, follow_redirects=True) as client: + print("streaming invoice parties (SaskaituSalys, ~32M)…", file=sys.stderr) + stream(client, "SaskaituSalys", "sf_id,tipas,validus_jar_kodas", put_parties) + con.commit() + print("streaming invoices (Saskaitos, ~14.4M)…", file=sys.stderr) + stream(client, "Saskaitos", "sf_id,israsymo_data,bendra_sf_suma,suma_be_pvm", put_invoices) + con.commit() + + print("indexing + aggregating…", file=sys.stderr) + con.execute("CREATE INDEX IF NOT EXISTS i_inv_sf ON invoice (sf)") + cur = con.execute(""" + SELECT b.jar, s.jar, i.year, COUNT(*), ROUND(SUM(i.gross), 2), ROUND(SUM(i.net), 2) + FROM invoice i + JOIN party b ON b.sf = i.sf AND b.tipas = 'Pirkėjas' + JOIN party s ON s.sf = i.sf AND s.tipas = 'Tiekėjas' + -- only years the calendar covers (1977-2027); drops malformed/implausible invoice dates + WHERE i.year >= '1977' AND i.year <= '2027' + GROUP BY b.jar, s.jar, i.year + HAVING ROUND(SUM(i.gross), 2) >= ? + """, (args.min_total,)) + n = 0 + with open(args.output, "w", newline="") as f: + w = csv.writer(f) + w.writerow(["buyer_code", "supplier_code", "year", "invoices", "total_eur", "net_eur"]) + for buyer, supplier, year, invoices, gross, net in cur: + w.writerow([buyer, supplier, year, invoices, gross, net]) + n += 1 + con.close() + if not args.db: + os.unlink(db_path) + print(f"aggregates: {n} (buyer, supplier, year) rows (>= {args.min_total:g} EUR)", file=sys.stderr) + + +if __name__ == "__main__": + main() diff --git a/queries/EXAMPLES.md b/queries/EXAMPLES.md index 13f1360..dcf4d2a 100644 --- a/queries/EXAMPLES.md +++ b/queries/EXAMPLES.md @@ -3668,6 +3668,173 @@ Rezultatai: +## Tiekėjai, apmokami smulkiomis sąskaitomis be pirkimo + +**Į kokį klausimą atsako:** kuriems tiekėjams viešasis sektorius per metus sumoka daug smulkių (žemiau pirkimų ribos) sąskaitų, nors viešųjų pirkimų registre jie neturi sutarties? + +**Kaip veikia:** sąskaitų tiekėjas (`ltlod:spendingSupplier`) ir pirkimų tiekėjas (`epo:playedBy`) — tas pats `legal-entities/{jar}/#this` IRI. Atrenkamos poros, kuriose per metus ≥ 30 000 EUR per ≥ 10 sąskaitų, kurių vidurkis < 10 000 EUR, ir patikrinama, ar nėra pirkimo sutarties. Pirkimo skaidymas į mažas sąskaitas išvengia pirkimų registro — tad tai signalas tikrinti (nors taip atsiskaitoma ir pagal preliminariąsias sutartis, ir už komunalines paslaugas). Užklausa kerta `public-spending` ir `procurement` rinkinius. + +```sparql +# Cross-domain: public-sector invoices × procurement (via the JAR code). +# Suppliers the public sector pays a lot through MANY SMALL invoices — averaging below the +# public-procurement publication threshold — yet who hold no published procurement contract. +# Buying in sub-threshold invoices keeps a purchase out of the procurement register, so this +# pairs the invoice aggregates (ltlod:spendingSupplier) against the contractors (epo:playedBy); +# both are the same legal-entities/{jar}/#this IRI. A large small-invoice total with no contract +# is worth a look, not a verdict (framework contracts and utilities — food, medical, energy +# supply — also bill this way). Per supplier: the total billed over >= 10 invoices averaging under +# 10 000 EUR, >= 30 000 EUR in all, excluding any public contractor. The supplier is grouped first, +# so the procurement check runs only over the few thousand matching suppliers, not every aggregate. +# Needs the public-spending and procurement datasets: make -C etl public-spending procurement +PREFIX epo: +PREFIX skos: +PREFIX ltlod: + +SELECT ?supplierName ?billed_eur ?invoices (ROUND(?billed_eur / ?invoices) AS ?avg_eur) +WHERE +{ + { + SELECT ?supplier (ROUND(SUM(?total)) AS ?billed_eur) (SUM(?n) AS ?invoices) + WHERE + { + GRAPH ?spendingGraph + { + ?aggregate a ltlod:SpendingAggregate ; + ltlod:spendingSupplier ?supplier ; + ltlod:billedTotal ?total ; + ltlod:invoiceCount ?n . + } + } + GROUP BY ?supplier + HAVING (SUM(?total) >= 30000 && SUM(?n) >= 10 && (SUM(?total) / SUM(?n)) < 10000) + } + FILTER NOT EXISTS { GRAPH ?contractGraph { ?contract epo:bindsContractor/epo:playedBy ?supplier } } + GRAPH ?entityGraph { ?supplier skos:prefLabel ?supplierName } +} +ORDER BY DESC(?billed_eur) +``` + +Rezultatai: + +| supplierName | billed_eur | invoices | avg_eur | +|---|---|---|---| +| UAB Scandi Standard - Baltics | 81053727.0 | 25406 | 3190.0 | +| Uždaroji akcinė bendrovė "MEDIKONA" | 50620137.0 | 18875 | 2682.0 | +| Energijos tiekimas UAB | 41110475.0 | 8098 | 5077.0 | +| Uždaroji akcinė bendrovė "Interlux" | 37966280.0 | 5391 | 7043.0 | +| Uždaroji akcinė bendrovė "GRAINA" | 26883039.0 | 4659 | 5770.0 | +| Akcinė bendrovė "Kelmės pieninė" | 21881605.0 | 4226 | 5178.0 | +| Valstybės įmonė Valstybės žemės fondas | 20138939.0 | 3656 | 5508.0 | +| Uždaroji akcinė bendrovė "Riamona" | 17963321.0 | 6199 | 2898.0 | +| "Swedbank lizingas", UAB | 16564191.0 | 3000 | 5521.0 | +| Uždaroji akcinė bendrovė "NORGAUDA" | 15176722.0 | 3891 | 3900.0 | +| UŽDAROJI AKCINĖ BENDROVĖ "DELTA" TURIZMO CENTRAS | 15110018.0 | 3017 | 5008.0 | +| UAB "Eletis Medica" | 14553402.0 | 7429 | 1959.0 | +| UAB "Sistemų valdymo konsultacijos" | 11120551.0 | 1578 | 7047.0 | +| UAB "Klaipėdos mėsinė" | 10341718.0 | 10226 | 1011.0 | +| UAB Energetikos paslaugų ir rangos organizacija | 9622865.0 | 1983 | 4853.0 | +| UAB "AMIC Lietuva" | 9074320.0 | 1377 | 6590.0 | +| AB "INTER RAO Lietuva" | 8782191.0 | 1273 | 6899.0 | +| Uždaroji akcinė bendrovė "ELEKTRIFIKACIJOS DARBAI" | 7002675.0 | 1670 | 4193.0 | +| Uždaroji akcinė bendrovė "Sentencija" | 6543713.0 | 848 | 7717.0 | +| Uždaroji akcinė bendrovė "Armetlina" | 5929436.0 | 6755 | 878.0 | +| UAB GPAIS | 5605718.0 | 1712 | 3274.0 | +| Uždaroji akcinė bendrovė "Saugos paslaugos" | 5211936.0 | 725 | 7189.0 | +| UAB "ELEKTROS PAJĖGOS" | 4894095.0 | 645 | 7588.0 | +| Uždaroji akcinė bendrovė "BERLIN CHEMIE MENARINI BALTIC" | 4714243.0 | 754 | 6252.0 | +| UAB "FORTRAKAS" | 4643569.0 | 555 | 8367.0 | +| Kauno skalbykla, UAB | 4490299.0 | 685 | 6555.0 | +| Uždaroji akcinė bendrovė "OZAS" | 4209671.0 | 483 | 8716.0 | +| UAB "Sinerta LDC" | 4096260.0 | 676 | 6060.0 | +| Uždaroji akcinė bendrovė "AAA WRISLIT" | 4051039.0 | 857 | 4727.0 | +| UAB "Intersera" | 3713979.0 | 642 | 5785.0 | +| … |   |  |  | + + + +## Politikų įmonės, apmokamos viešojo sektoriaus + +**Į kokį klausimą atsako:** kurių politikų deklaruoti juridiniai asmenys gauna pinigų iš viešojo sektoriaus pagal sąskaitas faktūras? + +**Kaip veikia:** privataus intereso ryšio įmonė (`ltlod:interestOrganization`) ir sąskaitų tiekėjas (`ltlod:spendingSupplier`) — tas pats `legal-entities/{jar}/#this` IRI. Imami tik nuosavybės ar valdymo ryšiai; sąskaitų sumos ir skaičiai susumuojami. Užklausa kerta `vtek` ir `public-spending` rinkinius. + +```sparql +# VTEK private interests × public-sector invoices (via the JAR code): officials whose declared +# ownership or control tie is to a company that bills the public sector. The interest tie's +# organization (ltlod:interestOrganization) and the invoice supplier (ltlod:spendingSupplier) are +# the same legal-entities/{jar}/#this IRI, so they join with no lookup. A politician with a stake +# in a company paid by the public sector is worth a look — a flag, not a verdict. Only ownership +# and control ties. Billed totals and invoice counts are summed across the company's years. +# Needs the vtek, public-spending and the full JAR register loaded. +PREFIX foaf: +PREFIX org: +PREFIX skos: +PREFIX ltlod: + +SELECT ?official ?entity ?tie_role (SUM(?billed) AS ?billed_eur) (SUM(?n) AS ?invoices) +WHERE +{ + GRAPH ?interestGraph + { + ?tie ltlod:interestOrganization ?org ; + org:member ?person ; + org:role ?role ; + ltlod:organizationName ?entity . + } + GRAPH ?roleGraph { ?role skos:notation ?roleCode ; skos:prefLabel ?tie_role . FILTER(LANG(?tie_role) = "lt") } + FILTER(?roleCode IN ("akcininkas", "dalininkas", "savininkas", "vadovas", + "vadovas-ar-jo-pavaduotojas", "valdybos-narys", "kolegialaus-valdymo-organo-narys", + "pirmininkas", "pirmininkas-ar-jo-pavaduotojas")) + GRAPH ?spendingGraph + { + ?aggregate ltlod:spendingSupplier ?org ; + ltlod:billedTotal ?billed ; + ltlod:invoiceCount ?n . + } + GRAPH ?personGraph { ?person foaf:name ?official } +} +GROUP BY ?official ?entity ?tie_role +ORDER BY DESC(?billed_eur) +``` + +Rezultatai: + +| official | entity | tie_role | billed_eur | invoices | +|---|---|---|---|---| +| Vidmantas Kanopa | Uždaroji akcinė bendrovė "Daivida" | Akcininkas | 51612710.57 | 30163 | +| Vytautas. Gapšys | AB "Ignitis grupė" | Akcininkas | 10083697.54 | 886 | +| Kristijonas Bartoševičius | Lietuvos gretutinių teisių asociacija | Kolegialaus valdymo organo narys | 913262.75 | 97 | +| Lina Šukytė-Korsakė | VšĮ Klaipėdos turizmo informacijos centras | Kolegialaus valdymo organo narys | 654820.4 | 88 | +| Kęstutis Masiulis | Mykolo Romerio universitetas | Kolegialaus valdymo organo narys | 451465.52 | 120 | +| Remigijus Žemaitaitis | UAB "Pamario starta" | Akcininkas | 190811.86 | 512 | +| Linas Kukuraitis | Viešoji įstaiga Pal. J. Matulaičio socialinis centras | Dalininkas | 99756.26 | 15 | +| Remigijus Žemaitaitis | UAB "STATYK PATS" | Akcininkas | 88323.03 | 328 | +| Darius Jasaitis | Lietuvos kurortų asociacija | Vadovas | 83998.0 | 16 | +| Eugenijus Jovaiša | Uždaroji akcinė bendrovė "ELEKTRONINĖS LEIDYBOS NAMAI" | Akcininkas | 81652.54 | 6 | +| Ausma Miškinienė | Lietuvos savivaldybių asociacija | Kolegialaus valdymo organo narys | 78290.57 | 13 | +| Nijolė Dirginčienė | Lietuvos savivaldybių asociacija | Kolegialaus valdymo organo narys | 78290.57 | 13 | +| Rimantas Klipčius | Lietuvos savivaldybių asociacija | Kolegialaus valdymo organo narys | 78290.57 | 13 | +| Rūta Matulaitienė | Lietuvos savivaldybių asociacija | Kolegialaus valdymo organo narys | 78290.57 | 13 | +| Šarūnas Vaitkus | Lietuvos savivaldybių asociacija | Kolegialaus valdymo organo narys | 78290.57 | 13 | +| Arvydas Vaitkus | Viešoji įstaiga Klaipėdos universiteto ligoninė | Kolegialaus valdymo organo narys | 70311.1 | 74 | +| Lina Šukytė-Korsakė | Viešoji įstaiga "Klaipėdos šventės" | Kolegialaus valdymo organo narys | 56552.22 | 12 | +| Lina Šukytė-Korsakė | Viešoji įstaiga "KLAIPĖDOS IRKLAVIMO CENTRAS" | Kolegialaus valdymo organo narys | 42608.95 | 5 | +| Andrius Šatevičius | Lietuvos kurortų asociacija | Vadovas | 41999.0 | 8 | +| Kęstutis Tubis | Lietuvos kurortų asociacija | Kolegialaus valdymo organo narys | 41999.0 | 8 | +| Nijolė Dirginčienė | Lietuvos kurortų asociacija | Vadovas | 41999.0 | 8 | +| Nijolė Guobienė | Lietuvos kurortų asociacija | Vadovas | 41999.0 | 8 | +| Valerijus Makūnas | Lietuvos kurortų asociacija | Kolegialaus valdymo organo narys | 41999.0 | 8 | +| Valdas Majauskas | Viešoji įstaiga Kauno regiono plėtros agentūra | Kolegialaus valdymo organo narys | 31931.0 | 11 | +| Ignas Vėgėlė | UAB "Internetinė prekyba" | Akcininkas | 25095.4 | 7 | +| Andrius Palionis | UAB "BTN" | Akcininkas | 25047.98 | 7 | +| Kęstutis Tubis | Lietuvos miško ir žemės savininkų asociacija | Kolegialaus valdymo organo narys | 22600.0 | 2 | +| Andrius Kubilius | Viešoji įstaiga Rytų Europos studijų centras | Kolegialaus valdymo organo narys | 18945.8 | 5 | +| Giedrimas Jeglinskas | UAB Unmanned Defense Systems | Akcininkas | 14580.0 | 3 | +| Giedrimas Jeglinskas | UAB Unmanned Defense Systems | Valdybos narys | 14580.0 | 3 | +| … |   |  |  |  | + + + ## Naujos įmonės be darbuotojų, siekiančios įsigyti žemės **Į kokį klausimą atsako:** kurios nuo 2020 m. įregistruotos bendrovės, neturinčios apdraustųjų darbuotojų, prašė leidimo įsigyti daugiausia žemės ūkio ar miško paskirties žemės? diff --git a/queries/pinreg-ties-public-spending.rq b/queries/pinreg-ties-public-spending.rq new file mode 100644 index 0000000..9fa5e00 --- /dev/null +++ b/queries/pinreg-ties-public-spending.rq @@ -0,0 +1,36 @@ +# VTEK private interests × public-sector invoices (via the JAR code): officials whose declared +# ownership or control tie is to a company that bills the public sector. The interest tie's +# organization (ltlod:interestOrganization) and the invoice supplier (ltlod:spendingSupplier) are +# the same legal-entities/{jar}/#this IRI, so they join with no lookup. A politician with a stake +# in a company paid by the public sector is worth a look — a flag, not a verdict. Only ownership +# and control ties. Billed totals and invoice counts are summed across the company's years. +# Needs the vtek, public-spending and the full JAR register loaded. +PREFIX foaf: +PREFIX org: +PREFIX skos: +PREFIX ltlod: + +SELECT ?official ?entity ?tie_role (SUM(?billed) AS ?billed_eur) (SUM(?n) AS ?invoices) +WHERE +{ + GRAPH ?interestGraph + { + ?tie ltlod:interestOrganization ?org ; + org:member ?person ; + org:role ?role ; + ltlod:organizationName ?entity . + } + GRAPH ?roleGraph { ?role skos:notation ?roleCode ; skos:prefLabel ?tie_role . FILTER(LANG(?tie_role) = "lt") } + FILTER(?roleCode IN ("akcininkas", "dalininkas", "savininkas", "vadovas", + "vadovas-ar-jo-pavaduotojas", "valdybos-narys", "kolegialaus-valdymo-organo-narys", + "pirmininkas", "pirmininkas-ar-jo-pavaduotojas")) + GRAPH ?spendingGraph + { + ?aggregate ltlod:spendingSupplier ?org ; + ltlod:billedTotal ?billed ; + ltlod:invoiceCount ?n . + } + GRAPH ?personGraph { ?person foaf:name ?official } +} +GROUP BY ?official ?entity ?tie_role +ORDER BY DESC(?billed_eur) diff --git a/queries/render-examples.py b/queries/render-examples.py index 7116c83..1d6ef54 100644 --- a/queries/render-examples.py +++ b/queries/render-examples.py @@ -530,6 +530,25 @@ "— tas pats `legal-entities/{jar}/#this` IRI, nukaltas iš JAR kodo. Platus viešųjų pinigų " "pėdsakas savaime nėra pažeidimas, bet derinį verta žemėlapyje matyti. Užklausa kerta " "`eu-funds` ir `procurement` rinkinius."), + ("suppliers-under-threshold.rq", + "Tiekėjai, apmokami smulkiomis sąskaitomis be pirkimo", + "**Į kokį klausimą atsako:** kuriems tiekėjams viešasis sektorius per metus sumoka daug " + "smulkių (žemiau pirkimų ribos) sąskaitų, nors viešųjų pirkimų registre jie neturi " + "sutarties?\n\n" + "**Kaip veikia:** sąskaitų tiekėjas (`ltlod:spendingSupplier`) ir pirkimų tiekėjas " + "(`epo:playedBy`) — tas pats `legal-entities/{jar}/#this` IRI. Atrenkamos poros, kuriose per " + "metus ≥ 30 000 EUR per ≥ 10 sąskaitų, kurių vidurkis < 10 000 EUR, ir patikrinama, ar nėra " + "pirkimo sutarties. Pirkimo skaidymas į mažas sąskaitas išvengia pirkimų registro — tad tai " + "signalas tikrinti (nors taip atsiskaitoma ir pagal preliminariąsias sutartis, ir už " + "komunalines paslaugas). Užklausa kerta `public-spending` ir `procurement` rinkinius."), + ("pinreg-ties-public-spending.rq", + "Politikų įmonės, apmokamos viešojo sektoriaus", + "**Į kokį klausimą atsako:** kurių politikų deklaruoti juridiniai asmenys gauna pinigų iš " + "viešojo sektoriaus pagal sąskaitas faktūras?\n\n" + "**Kaip veikia:** privataus intereso ryšio įmonė (`ltlod:interestOrganization`) ir sąskaitų " + "tiekėjas (`ltlod:spendingSupplier`) — tas pats `legal-entities/{jar}/#this` IRI. Imami tik " + "nuosavybės ar valdymo ryšiai; sąskaitų sumos ir skaičiai susumuojami. Užklausa kerta `vtek` " + "ir `public-spending` rinkinius."), ("land-new-companies.rq", "Naujos įmonės be darbuotojų, siekiančios įsigyti žemės", "**Į kokį klausimą atsako:** kurios nuo 2020 m. įregistruotos bendrovės, neturinčios " diff --git a/queries/suppliers-under-threshold.rq b/queries/suppliers-under-threshold.rq new file mode 100644 index 0000000..2757372 --- /dev/null +++ b/queries/suppliers-under-threshold.rq @@ -0,0 +1,37 @@ +# Cross-domain: public-sector invoices × procurement (via the JAR code). +# Suppliers the public sector pays a lot through MANY SMALL invoices — averaging below the +# public-procurement publication threshold — yet who hold no published procurement contract. +# Buying in sub-threshold invoices keeps a purchase out of the procurement register, so this +# pairs the invoice aggregates (ltlod:spendingSupplier) against the contractors (epo:playedBy); +# both are the same legal-entities/{jar}/#this IRI. A large small-invoice total with no contract +# is worth a look, not a verdict (framework contracts and utilities — food, medical, energy +# supply — also bill this way). Per supplier: the total billed over >= 10 invoices averaging under +# 10 000 EUR, >= 30 000 EUR in all, excluding any public contractor. The supplier is grouped first, +# so the procurement check runs only over the few thousand matching suppliers, not every aggregate. +# Needs the public-spending and procurement datasets: make -C etl public-spending procurement +PREFIX epo: +PREFIX skos: +PREFIX ltlod: + +SELECT ?supplierName ?billed_eur ?invoices (ROUND(?billed_eur / ?invoices) AS ?avg_eur) +WHERE +{ + { + SELECT ?supplier (ROUND(SUM(?total)) AS ?billed_eur) (SUM(?n) AS ?invoices) + WHERE + { + GRAPH ?spendingGraph + { + ?aggregate a ltlod:SpendingAggregate ; + ltlod:spendingSupplier ?supplier ; + ltlod:billedTotal ?total ; + ltlod:invoiceCount ?n . + } + } + GROUP BY ?supplier + HAVING (SUM(?total) >= 30000 && SUM(?n) >= 10 && (SUM(?total) / SUM(?n)) < 10000) + } + FILTER NOT EXISTS { GRAPH ?contractGraph { ?contract epo:bindsContractor/epo:playedBy ?supplier } } + GRAPH ?entityGraph { ?supplier skos:prefLabel ?supplierName } +} +ORDER BY DESC(?billed_eur)