from typing import Annotated, List, Literal, Optional from pydantic import BaseModel, Field, field_validator class SortableMixin(BaseModel): sortProperty: Annotated[ Optional[str], Field(default=None, description="Attribute to sort records by") ] = None sortDirection: Annotated[ Literal["ASC", "DESC"], Field(default="ASC", description="Sort direction: 'ASC' (default) or 'DESC'") ] = "ASC" class PaginatedRequest(SortableMixin): page: Annotated[ Optional[int], Field(default=None, ge=0, description="Page number, starts at 0 (not 1)") ] = None size: Annotated[ Optional[int], Field(default=None, ge=1, description="Number of records per page") ] = None #################################################################################################################### # .../v1/sud — Courts #################################################################################################################### class CourtSearch(PaginatedRequest): """List of courts with optional filters. GET /v1/sud""" query: Annotated[ Optional[str], Field(default=None, description="Search term or phrase") ] = None typSuduFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Court type facet filter, e.g. ['Okresný súd', 'Krajský súd']") ] = None krajFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Region facet filter, e.g. ['Bratislavský kraj']") ] = None okresFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="District facet filter, e.g. ['Okres Bratislava I']") ] = None zahrnutZaniknuteSudy: Annotated[ Optional[bool], Field(default=None, description="True = include dissolved courts, False = active only") ] = None indexDatumOd: Annotated[ Optional[str], Field(default=None, description="Index date from, format DD.MM.YYYY") ] = None indexDatumDo: Annotated[ Optional[str], Field(default=None, description="Index date to, format DD.MM.YYYY") ] = None class CourtByID(BaseModel): """Single court by ID. GET /v1/sud/{id}""" id: Annotated[str, Field(description="Court identifier, e.g. 'sud_175'")] @field_validator("id") @classmethod def normalize(cls, v: str) -> str: v = v.strip() return f"sud_{v}" if v.isdigit() else v class CourtAutocomplete(BaseModel): """Autocomplete for court names. GET /v1/sud/autocomplete PREFERRED tool when searching court by name — use before CourtSearch. """ query: Annotated[Optional[str], Field(default=None, description="Partial court name")] = None limit: Annotated[Optional[int], Field(default=None, ge=1, description="Maximum number of results")] = None #################################################################################################################### # .../v1/sudca — Judges #################################################################################################################### class JudgeSearch(PaginatedRequest): """List of judges with optional filters. GET /v1/sudca""" query: Annotated[ Optional[str], Field(default=None, description="Search term or phrase") ] = None funkciaFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Function facet filter, e.g. ['Sudca', 'Predseda', 'Podpredseda']") ] = None typSuduFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Court type facet filter") ] = None krajFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Region facet filter, e.g. ['Bratislavský kraj']") ] = None okresFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="District facet filter") ] = None stavZapisuFacetFilter: Annotated[ Optional[List[str]], Field( default=None, description=( "Registration status filter. Do not translate values: " "'label.sudca.aktivny', 'label.sudca.odvolany', " "'label.sudca.vymazany', " "'label.sudca.prerusenie vykonu - poberatel', " "'label.sudca.prerusenie vykonu - ina funkce'" ) ) ] = None guidSud: Annotated[ Optional[str], Field(default=None, description="Court identifier, e.g. 'sud_100'") ] = None indexDatumOd: Annotated[ Optional[str], Field(default=None, description="Index date from, format DD.MM.YYYY") ] = None indexDatumDo: Annotated[ Optional[str], Field(default=None, description="Index date to, format DD.MM.YYYY") ] = None class JudgeByID(BaseModel): """Single judge by ID. GET /v1/sudca/{id}""" id: Annotated[str, Field(description="Judge identifier, e.g. 'sudca_1'")] @field_validator("id") @classmethod def normalize(cls, v: str) -> str: v = v.strip() return f"sudca_{v}" if v.isdigit() else v class JudgeAutocomplete(BaseModel): """Autocomplete for judge names. GET /v1/sudca/autocomplete PREFERRED tool when searching judge by name — use before JudgeSearch. """ query: Annotated[ Optional[str], Field(default=None, description="Partial judge name") ] = None guidSud: Annotated[ Optional[str], Field(default=None, description="Court identifier to narrow results, e.g. 'sud_100'") ] = None limit: Annotated[ Optional[int], Field(default=None, ge=1, description="Maximum number of results") ] = None #################################################################################################################### # .../v1/rozhodnutie — Decisions #################################################################################################################### class DecisionSearch(PaginatedRequest): """List of court decisions with optional filters. GET /v1/rozhodnutie""" query: Annotated[Optional[str], Field(default=None, description="Search term or phrase")] = None typSuduFacetFilter: Annotated[Optional[List[str]], Field(default=None, description="Court type facet filter")] = None krajFacetFilter: Annotated[Optional[List[str]], Field(default=None, description="Region facet filter")] = None okresFacetFilter: Annotated[Optional[List[str]], Field(default=None, description="District facet filter")] = None oblastPravnejUpravyFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Legal area facet filter") ] = None podOblastPravnejUpravyFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Legal sub-area facet filter") ] = None formaRozhodnutiaFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Decision form facet filter, e.g. ['Uznesenie', 'Rozsudok', 'Platobný rozkaz']") ] = None povahaRozhodnutiaFacetFilter: Annotated[ Optional[str], Field(default=None, description="Decision nature facet filter") ] = None odkazovanePredpisy: Annotated[ Optional[str], Field(default=None, description="Referenced legal regulations") ] = None vydaniaOd: Annotated[Optional[str], Field(default=None, description="Issued date from, format YYYY-MM-DD")] = None vydaniaDo: Annotated[Optional[str], Field(default=None, description="Issued date to, format YYYY-MM-DD")] = None ecli: Annotated[ Optional[str], Field(default=None, description="ECLI identifier, e.g. 'ECLI:SK:OSPO:1965:8114010264.1'") ] = None spisovaZnacka: Annotated[ Optional[str], Field(default=None, description="Case reference number, e.g. '7C/221/1991'") ] = None cisloSpisu: Annotated[Optional[str], Field(default=None, description="Case file number")] = None guidSudca: Annotated[Optional[str], Field(default=None, description="Judge identifier, e.g. 'sudca_1'")] = None guidSud: Annotated[Optional[str], Field(default=None, description="Court identifier, e.g. 'sud_100'")] = None indexDatumOd: Annotated[Optional[str], Field(default=None, description="Index date from, format DD.MM.YYYY")] = None indexDatumDo: Annotated[Optional[str], Field(default=None, description="Index date to, format DD.MM.YYYY")] = None class DecisionByID(BaseModel): """Single court decision by ID. GET /v1/rozhodnutie/{id}""" id: Annotated[str, Field(description="Decision identifier")] class DecisionAutocomplete(BaseModel): """Autocomplete for court decisions. GET /v1/rozhodnutie/autocomplete""" query: Annotated[Optional[str], Field(default=None, description="Search term")] = None guidSud: Annotated[Optional[str], Field(default=None, description="Court identifier, e.g. 'sud_100'")] = None limit: Annotated[Optional[int], Field(default=None, ge=1, description="Maximum number of results")] = None #################################################################################################################### # .../v1/zmluvy — Contracts #################################################################################################################### class ContractSearch(PaginatedRequest): """List of court contracts with optional filters. GET /v1/zmluvy""" query: Annotated[Optional[str], Field(default=None, description="Search term or phrase")] = None typDokumentuFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Document type facet filter, e.g. ['FAKTURA', 'OBJEDNAVKA', 'ZMLUVA', 'DODATOK']") ] = None odberatelFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Recipient (court) facet filter, e.g. ['Krajský súd v Bratislave']") ] = None dodavatelFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Supplier facet filter, e.g. ['Slovak Telekom, a.s.']") ] = None hodnotaZmluvyFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Contract value range filter: '0-1000', '1000-20000', '20000-100000', '100000-500000', 'Viac ako 500000'") ] = None datumZverejeneniaOd: Annotated[ Optional[str], Field(default=None, description="Publication date from, format DD.MM.YYYY") ] = None datumZverejeneniaDo: Annotated[ Optional[str], Field(default=None, description="Publication date to, format DD.MM.YYYY") ] = None guidSud: Annotated[Optional[str], Field(default=None, description="Court identifier, e.g. 'sud_100'")] = None indexDatumOd: Annotated[Optional[str], Field(default=None, description="Index date from, format DD.MM.YYYY")] = None indexDatumDo: Annotated[Optional[str], Field(default=None, description="Index date to, format DD.MM.YYYY")] = None class ContractByID(BaseModel): """Single contract by ID. GET /v1/zmluvy/{idZmluvy}""" idZmluvy: Annotated[str, Field(description="Contract identifier, e.g. '2156252'")] class ContractAutocomplete(BaseModel): """Autocomplete for contracts. GET /v1/zmluvy/autocomplete""" query: Annotated[Optional[str], Field(default=None, description="Search term")] = None guidSud: Annotated[Optional[str], Field(default=None, description="Court identifier, e.g. 'sud_100'")] = None limit: Annotated[Optional[int], Field(default=None, ge=1, description="Maximum number of results")] = None #################################################################################################################### # .../v1/obcianPojednavania — Civil Proceedings #################################################################################################################### class CivilProceedingsSearch(PaginatedRequest): """List of civil court hearings and publicly announced judgments. GET /v1/obcianPojednavania""" query: Annotated[Optional[str], Field(default=None, description="Search term or phrase")] = None typSuduFacetFilter: Annotated[Optional[List[str]], Field(default=None, description="Court type facet filter")] = None krajFacetFilter: Annotated[Optional[List[str]], Field(default=None, description="Region facet filter")] = None okresFacetFilter: Annotated[Optional[List[str]], Field(default=None, description="District facet filter")] = None usekFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Section facet filter, e.g. ['C', 'O', 'S']") ] = None formaUkonuFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Action form facet filter, e.g. ['Pojednávanie bez rozhodnutia', 'Pojednávanie a rozhodnutie']") ] = None pojednavaniaOd: Annotated[ Optional[str], Field(default=None, description="Hearing date from, format YYYY-MM-DD") ] = None pojednavaniaDo: Annotated[ Optional[str], Field(default=None, description="Hearing date to, format YYYY-MM-DD") ] = None guidSudca: Annotated[Optional[str], Field(default=None, description="Judge identifier, e.g. 'sudca_1'")] = None guidSud: Annotated[Optional[str], Field(default=None, description="Court identifier, e.g. 'sud_100'")] = None spisovaZnacka: Annotated[ Optional[str], Field(default=None, description="Case reference number, e.g. '7C/221/1991'") ] = None verejneVyhlasenie: Annotated[ Optional[bool], Field(default=None, description="True = publicly announced judgment only") ] = None indexDatumOd: Annotated[Optional[str], Field(default=None, description="Index date from, format DD.MM.YYYY")] = None indexDatumDo: Annotated[Optional[str], Field(default=None, description="Index date to, format DD.MM.YYYY")] = None class CivilProceedingsByID(BaseModel): """Single civil hearing by ID. GET /v1/obcianPojednavania/{id}""" id: Annotated[str, Field(description="Hearing identifier, e.g. '121e4d31-695e-41e1-9191-7c9ad5d8d484'")] class CivilProceedingsAutocomplete(BaseModel): """Autocomplete for civil proceedings. GET /v1/obcianPojednavania/autocomplete""" query: Annotated[Optional[str], Field(default=None, description="Search term")] = None guidSud: Annotated[Optional[str], Field(default=None, description="Court identifier, e.g. 'sud_100'")] = None guidSudca: Annotated[Optional[str], Field(default=None, description="Judge identifier, e.g. 'sudca_1'")] = None verejneVyhlasenie: Annotated[ Optional[bool], Field(default=None, description="True = publicly announced judgment only") ] = None limit: Annotated[Optional[int], Field(default=None, ge=1, description="Maximum number of results")] = None #################################################################################################################### # .../v1/spravneKonanie — Administrative Proceedings #################################################################################################################### class AdminProceedingsSearch(PaginatedRequest): """List of administrative proceedings. GET /v1/spravneKonanie""" query: Annotated[Optional[str], Field(default=None, description="Search term or phrase")] = None druhFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Proceeding type facet filter") ] = None datumPravoplatnostiOd: Annotated[ Optional[str], Field(default=None, description="Legal force date from, format YYYY-MM-DD") ] = None datumPravoplatnostiDo: Annotated[ Optional[str], Field(default=None, description="Legal force date to, format YYYY-MM-DD") ] = None class AdminProceedingsByID(BaseModel): """Single administrative proceeding by ID. GET /v1/spravneKonanie/{id}""" id: Annotated[str, Field(description="Proceeding identifier, e.g. 'spravneKonanie_103'")] @field_validator("id") @classmethod def normalize(cls, v: str) -> str: v = v.strip() return f"spravneKonanie_{v}" if v.isdigit() else v class AdminProceedingsAutocomplete(BaseModel): """Autocomplete for administrative proceedings. GET /v1/spravneKonanie/autocomplete""" query: Annotated[Optional[str], Field(default=None, description="Search term")] = None limit: Annotated[Optional[int], Field(default=None, ge=1, description="Maximum number of results")] = None #################################################################################################################### # .../v1/exekutor — Executor #################################################################################################################### class ExecutorSearch(PaginatedRequest): """List of bailiffs (exekútori). GET /v1/exekutor""" query: Annotated[Optional[str], Field(default=None, description="Search term or phrase")] = None sudFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Court facet filter, e.g. 'Krajský súd v Trenčíne'") ] = None krajFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Region facet filter, e.g. 'Košický kraj'") ] = None okresFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="District facet filter") ] = None obecFacetFilter: Annotated[ Optional[List[str]], Field(default=None, description="Municipality facet filter") ] = None stavZapisuFacetFilter: Annotated[ Optional[List[str]], Field( default=None, description=( "Registration status filter. Do not translate values: " "'label.zapis_stav.aktivny', 'label.zapis_stav.neaktivny'" ) ) ] = None class ExecutorByID(BaseModel): """Single bailiff by ID. GET /v1/exekutor/{id}""" id: Annotated[str, Field(description="Bailiff identifier, e.g. 'exekutor_154'")] @field_validator("id") @classmethod def normalize(cls, v: str) -> str: v = v.strip() return f"exekutor_{v}" if v.isdigit() else v class ExecutorByECE(BaseModel): """Single bailiff by ECE registration number. GET /v1/exekutor/ec/{ece}""" ece: Annotated[str, Field(description="Bailiff ECE registration number, e.g. '089'")] @field_validator("ece") @classmethod def normalize(cls, v: str) -> str: v = v.strip() if not v: raise ValueError("ece cannot be empty") return v class ExecutorAutocomplete(BaseModel): """Autocomplete for bailiffs. GET /v1/exekutor/autocomplete""" query: Annotated[Optional[str], Field(default=None, description="Search term")] = None limit: Annotated[Optional[int], Field(default=None, ge=1, description="Maximum number of results")] = None