aeat.core.external_constants module

External constants registry loaded from external_constants.toml.

Centralises third-party hostnames, AEAT service paths, OAuth scopes, and remote API endpoints. The TOML file sits beside this module and is parsed once per process via load_external_constants(). Every section is modelled as a frozen, strict pydantic v2 model so callers see typed, immutable values and any drift between the TOML and the schema fails fast at import time.

This is a read-only remote-mirror registry for public, externally defined constants. Runtime-tunable values such as timeouts, storage roots, and operator choices belong in core.config.Settings; profile data, tokens, passphrases, bucket ids, and SQL routes do not belong here. Loading the registry only reads packaged TOML (or an explicit audit/test path) and never opens storage, writes files, or contacts remote providers.

The typed root is ExternalConstants, with AEAT-specific subsections grouped under AeatSection; callers normally reach it through core.config.Settings.external_constants(). The volatile Pre303 and IVA-wallet browser surface remains lazily validated as AeatPre303Surface so selector churn does not poison unrelated configuration reads.

DEFAULT_CURRENCY: Final[str]

ISO 4217 currency code for the Euro, used as the functional currency throughout AEAT.

BINARY_MIME_TYPE: Final[str]

Standard binary MIME type for opaque byte-stream payloads (Drive uploads, blob store, fichero).

JSON_MIME_TYPE: Final[str]

IANA-registered MIME type for JSON document payloads.

CSV_MIME_TYPE: Final[str]

IANA-registered MIME type for comma-separated value exports.

JSONL_MIME_TYPE: Final[str]

MIME type for newline-delimited JSON export streams.

XLSX_MIME_TYPE: Final[str]

MIME type for Office Open XML spreadsheet workbooks.

CLASSIFIED_BY_MANUAL: Final[str]

Sentinel written to classified_by when the operator provides a classification directly (no rule engine involved). The field also accepts "rule:<id>" payloads; this named constant prevents the literal from drifting across the application and domain layers.

CLASSIFIED_BY_AUTO: Final[str]

Sentinel written to classified_by when the classification was produced automatically by the rule engine with no operator override.

class AeatDomains(**data)[source]

Bases: _Frozen

AEAT and related government hostnames.

Hostnames are registry data, not executable literals in live drivers. Callers combine these origins with path sections below instead of re-declaring Sede, Cl@ve, BOE, or numbered AEAT subdomain strings.

Parameters:
host_suffix: str
sede: str
www1: str
www2: str
www3: str
www6: str
www12: str
aeat_gob: str
legacy_www: str
clave: str
boe: str
class AeatSedePaths(**data)[source]

Bases: _Frozen

Relative path templates against configured AEAT origins.

These values are route fragments and templates only; consumers choose the correct origin from AeatDomains or an overrideable core.config.Settings field before building a full URL.

Parameters:
  • auth_gate_4033 (str)

  • expedientes_resumen (str)

  • declarations_listing (str)

  • cotejo_query (str)

  • cotejo_document (str)

  • notifications_summary (str)

  • notifications_query (str)

  • certificate_selector (str)

  • censo_g313_launcher (str)

  • r210_simulator_open_ajax (str)

  • borrador_100_detail_template (str)

  • declaracion_consult (str)

  • clave_movil_login (str)

  • expediente_detail_template (str)

  • irpf_expediente_detail_year_prefix (str)

  • irpf_expediente_detail_year_suffix (str)

  • notificaciones (str)

  • iva_compensation_wallet (str)

auth_gate_4033: str
expedientes_resumen: str
declarations_listing: str
cotejo_query: str
cotejo_document: str
notifications_summary: str
notifications_query: str
certificate_selector: str
censo_g313_launcher: str
r210_simulator_open_ajax: str
borrador_100_detail_template: str
declaracion_consult: str
clave_movil_login: str
expediente_detail_template: str
irpf_expediente_detail_year_prefix: str
irpf_expediente_detail_year_suffix: str
notificaciones: str
iva_compensation_wallet: str
class AeatClaveMovilSurface(**data)[source]

Bases: _Frozen

Externally-defined Cl@ve Móvil page identifiers and shape markers.

Parameters:
  • selector_access_url_template (str)

  • selector_access_path_marker (str)

  • dialogo_representacion_path_marker (str)

  • dialogo_representacion_path (str)

  • obtener_clave_movil_path_marker (str)

  • obtener_clave_movil_qr_path_marker (str)

  • cancelar_clave_movil_path_marker (str)

  • obtener_clave_movil_qr_path (str)

  • obtener_clave_movil_non_qr_path (str)

  • autentica_dni_nie_contraste_path (str)

  • cancelar_clave_movil_path (str)

  • obtener_clave_movil_browser_global (str)

  • authorize_button_selector (str)

  • non_qr_link_selector (str)

  • nif_input_selector (str)

  • dni_fecha_input_selector (str)

  • dni_fecha_visible_selector (str)

  • nie_soporte_input_selector (str)

  • nie_soporte_visible_selector (str)

  • continue_button_selector (str)

  • continue_button_visible_selector (str)

  • verification_code_selector (str)

  • wait_text_markers (tuple[str, ...])

  • pending_petition_text_markers (tuple[str, ...])

selector_access_url_template: str
selector_access_path_marker: str
dialogo_representacion_path_marker: str
dialogo_representacion_path: str
obtener_clave_movil_path_marker: str
obtener_clave_movil_qr_path_marker: str
cancelar_clave_movil_path_marker: str
obtener_clave_movil_qr_path: str
obtener_clave_movil_non_qr_path: str
autentica_dni_nie_contraste_path: str
cancelar_clave_movil_path: str
obtener_clave_movil_browser_global: str
authorize_button_selector: str
nif_input_selector: str
dni_fecha_input_selector: str
dni_fecha_visible_selector: str
nie_soporte_input_selector: str
nie_soporte_visible_selector: str
continue_button_selector: str
continue_button_visible_selector: str
verification_code_selector: str
wait_text_markers: tuple[str, ...]
pending_petition_text_markers: tuple[str, ...]
class AeatClavePermanenteSurface(**data)[source]

Bases: _Frozen

Externally-defined Cl@ve Permanente selector-page and IdP form markers.

Cl@ve Permanente reuses the same AEAT auth-method selector page as Cl@ve Movil (selector_access_url_template); the Cl@ve IdP itself then renders a DNI/NIE + password form rather than the QR/push screen. These IdP form selectors and error markers are the least stable part of this surface — they track the Cl@ve frontend, not an AEAT-published contract — and are the needs-design surface tracked by issue #283.

Parameters:
  • selector_access_url_template (str)

  • selector_access_path_marker (str)

  • idp_host_marker (str)

  • username_input_selector (str)

  • password_input_selector (str)

  • submit_button_selector (str)

  • elevation_sms_marker (str)

  • invalid_credentials_marker (str)

  • account_locked_marker (str)

  • password_expired_marker (str)

selector_access_url_template: str
selector_access_path_marker: str
idp_host_marker: str
username_input_selector: str
password_input_selector: str
submit_button_selector: str
elevation_sms_marker: str
invalid_credentials_marker: str
account_locked_marker: str
password_expired_marker: str
class AeatPre303Surface(**data)[source]

Bases: _Frozen

Externally-defined Pre303 and IVA compensation wallet surface markers.

Parameters:
  • presentation_service_path (str)

  • access_help_path (str)

  • faq_general_path (str)

  • faq_specific_path (str)

  • functionalities_path (str)

  • procedures_path (str)

  • iva_wallet_header_tokens (tuple[str, ...])

  • iva_wallet_total_label_tokens (tuple[str, ...])

  • iva_wallet_empty_page_tokens (tuple[str, ...])

  • representation_own_name_selector (str)

  • representation_own_name_label_selector (str)

  • representation_representative_selector (str)

  • representation_submit_selector (str)

  • representation_own_name_action_label (str)

  • wallet_discovered_entrypoint_action_label (str)

  • wallet_execute_read_action_label (str)

  • alert_modal_selector (str)

  • alert_continue_button_text (str)

  • wallet_form_selector (str)

  • wallet_execute_submit_selector (str)

  • tipo_actuacion_own_name_link_selector (str)

  • wallet_ejercicio_input_selector (str)

  • wallet_periodo_input_selector (str)

  • official_access_auth_methods (tuple[str, ...])

presentation_service_path: str
access_help_path: str
faq_general_path: str
faq_specific_path: str
functionalities_path: str
procedures_path: str
iva_wallet_header_tokens: tuple[str, ...]
iva_wallet_total_label_tokens: tuple[str, ...]
iva_wallet_empty_page_tokens: tuple[str, ...]
representation_own_name_selector: str
representation_own_name_label_selector: str
representation_representative_selector: str
representation_submit_selector: str
representation_own_name_action_label: str
wallet_discovered_entrypoint_action_label: str
wallet_execute_read_action_label: str
alert_modal_selector: str
alert_continue_button_text: str
wallet_form_selector: str
wallet_execute_submit_selector: str
wallet_ejercicio_input_selector: str
wallet_periodo_input_selector: str
official_access_auth_methods: tuple[str, ...]
class AeatHelpPages(**data)[source]

Bases: _Frozen

Static help/landing pages rooted under the sede origin.

Parameters:
  • csv_verification (str)

  • renta_web_open_landing (str)

  • nif_iva_landing (str)

  • manual_practicos_root (str)

csv_verification: str
renta_web_open_landing: str
nif_iva_landing: str
manual_practicos_root: str
class AeatOracles(**data)[source]

Bases: _Frozen

Absolute URLs of AEAT parity oracles.

Parameters:
  • nif_iva_verification (str)

  • groi_check (str)

  • renta_web_open_app_template (str)

  • groi_auth_unlock_descriptor (str)

  • nif_iva_auth_locked_descriptor (str)

nif_iva_verification: str
groi_check: str
renta_web_open_app_template: str
groi_auth_unlock_descriptor: str
nif_iva_auth_locked_descriptor: str
class AeatLiveSafety(**data)[source]

Bases: _Frozen

Centralized allow-list labels for audited live AEAT browser actions.

The patterns identify reviewed action categories for live-surface guards. They do not authorize a write by themselves; command policy, capability checks, and live-write gates remain responsible for deciding whether an operation may run.

Parameters:
  • auth_browser_action_patterns (tuple[str, ...])

  • wallet_browser_action_patterns (tuple[str, ...])

  • declarations_browser_action_patterns (tuple[str, ...])

  • csv_verify_browser_action_patterns (tuple[str, ...])

  • consult_oracle_browser_action_patterns (tuple[str, ...])

  • renta_web_open_browser_action_patterns (tuple[str, ...])

auth_browser_action_patterns: tuple[str, ...]
wallet_browser_action_patterns: tuple[str, ...]
declarations_browser_action_patterns: tuple[str, ...]
csv_verify_browser_action_patterns: tuple[str, ...]
consult_oracle_browser_action_patterns: tuple[str, ...]
renta_web_open_browser_action_patterns: tuple[str, ...]
class AeatPortalPaths(**data)[source]

Bases: _Frozen

Centralized AEAT portal catalogue paths keyed by Portal id.

Portal entries resolve their route fragments from this registry so the catalogue can describe AEAT surfaces without carrying host or path source literals in each entry module.

Parameters:
  • filing_censo_path_regex (str)

  • filing_censo_path_description (str)

  • paths (dict[str, str])

filing_censo_path_regex: str
filing_censo_path_description: str
paths: dict[str, str]
class AeatSection(**data)[source]

Bases: _Frozen

Aggregates every AEAT-flavoured constant subsection.

The pre303 web-scraping surface (IVA-compensation-wallet routes, representation-gate selectors, parser markers) is the most volatile section of the registry: every value tracks the AEAT portal’s HTML and may break on a portal redesign. To keep that volatility from poisoning the whole registry — and therefore every Settings() construction, since core.config.Settings resolves AEAT-URL defaults through load_external_constants() — the raw [aeat.pre303] mapping is kept untyped and validated lazily into a strict AeatPre303Surface only on first access via the pre303 property. A missing or malformed pre303 block thus never raises while parsing the registry; it surfaces as a clean core.errors.CoreValidationError to the wallet / representation flows that actually consume it, and leaves selector-free commands (config profile status, modelo list, …) entirely unaffected.

Parameters:
domains: AeatDomains
sede_paths: AeatSedePaths
clave_movil: AeatClaveMovilSurface
clave_permanente: AeatClavePermanenteSurface
pre303_raw: dict[str, Any]
help_pages: AeatHelpPages
oracles: AeatOracles
live_safety: AeatLiveSafety
portal_paths: AeatPortalPaths
property pre303: AeatPre303Surface[source]

Return the strict-validated AeatPre303Surface (Pre303 / IVA-wallet surface).

Validation is deferred to first access so a malformed or absent [aeat.pre303] block cannot break registry parsing for the many CLI paths that never scrape the AEAT portal. When the block is broken the leaked pydantic.ValidationError is wrapped in a core.errors.CoreValidationError carrying an operator-facing recovery hint.

class GoogleOAuthScopes(**data)[source]

Bases: _Frozen

OAuth scope strings the Google integration requests.

Parameters:
  • openid (str)

  • email (str)

  • drive_file (str)

  • spreadsheets (str)

openid: str
email: str
drive_file: str
spreadsheets: str
class GoogleServices(**data)[source]

Bases: _Frozen

Google-hosted service surfaces.

Parameters:

oauth_scopes (GoogleOAuthScopes)

oauth_scopes: GoogleOAuthScopes
class OnlineServicesSection(**data)[source]

Bases: _Frozen

Aggregates non-AEAT online service constants.

Parameters:

google (GoogleServices)

google: GoogleServices
class ExternalConstants(**data)[source]

Bases: _Frozen

Top-level registry model mirroring the TOML root.

The root intentionally separates AEAT-owned surfaces from other online services so call sites can depend on the narrow subsection they need while still sharing one typed registry load.

Parameters:
aeat: AeatSection
online_services: OnlineServicesSection
PDF_MIME_TYPE: Final[str]

IANA-registered MIME type for PDF document payloads.

PDF_EXTENSION: Final[str]

PDF file-extension string (lower-case, dot-prefixed).

XLS_EXTENSION: Final[Literal['.xls']]

Legacy binary Excel workbook file-extension string (lower-case, dot-prefixed).

XLSX_EXTENSION: Final[Literal['.xlsx']]

Excel / Open-XML workbook file-extension string (lower-case, dot-prefixed).

XLSM_EXTENSION: Final[Literal['.xlsm']]

Excel macro-enabled workbook file-extension string (lower-case, dot-prefixed).

LATIN_1_ENCODING: Final[str]

Legacy ISO-8859-1 / Latin-1 encoding used by AEAT sede fixed-width response bodies.

ISO_8859_1_ENCODING: Final[Literal['iso-8859-1']]

ISO-8859-1 encoding string as accepted by the fichero-BOE wire layer.

Identical in coverage to LATIN_1_ENCODING at runtime; declared as a typed Literal["iso-8859-1"] so callers that pass it to a adapters.outbound.aeat.export._formats._record_spec.FicheroBoeEncoding parameter satisfy the static type checker without a cast.

UTF_8_ENCODING: Final[str]

UTF-8 character encoding used for all text file I/O in the application layer.

BOE_ENCODING_CHOICES: Final[tuple[str, ...]]

Allowed wire encodings for fichero-BOE payloads.

Windows-1252 is a superset of ISO-8859-1 that adds characters in the 0x80-0x9F range; AEAT treats them as equivalent for fichero-BOE purposes. ISO-8859-15 adds the Euro symbol at 0xA4 plus minor deltas.

PROVENANCE_SOURCE_MANUAL_CLI: Final[str]

Provenance source identifier for facts entered interactively via the CLI.

SANDBOX_LABEL_PREFIX: Final[str]

Reserved operator-visible bucket-label prefix identifying a sandbox profile. A profile whose plaintext manifest label starts with this token is a sandbox: an isolated, discardable bucket. Declared in the light core layer so the state-free CLI surface (aeat / --help / --version) can check the active bucket’s sandbox status without importing the heavy bucket_maintenance / workflow facades. bucket_maintenance._sandbox re-exports it as the canonical application-facing name.

OUTPUT_LANGUAGE_ENV_VAR: Final[str]

Environment variable name used to override the CLI output language at runtime.

COLUMNS_ENV_VAR: Final[str]

POSIX / Windows environment variable that Rich uses to determine console column width.

class OutputLanguage(*values)[source]

Bases: StrEnum

Closed enumeration of CLI / API output language BCP-47 tags.

The four members match the locale catalogues committed under src/aeat/locales/. Adding a new operator-facing language requires landing the catalogue first and then extending this enum so the loader-side gates remain in sync.

ES
EN
CA
HU
DEFAULT_OUTPUT_LANGUAGE: Final[OutputLanguage]

BCP-47 language tag for the default CLI and API output language (Spanish).

SUPPORTED_OUTPUT_LANGUAGES: Final[tuple[str, ...]]

Ordered tuple of BCP-47 language tags supported by the CLI and API output layer. Kept as tuple[str, ...] (not tuple[OutputLanguage, ...]) so click.Choice(SUPPORTED_OUTPUT_LANGUAGES) renders the operator-facing lowercase tags ([es|en|ca|hu]) on parse failure rather than the enum NAMES ([ES|EN|CA|HU]) that Click derives from StrEnum members. The OutputLanguage enum stays the canonical closed-set authority above; this constant is the str-typed projection used at the click.Choice boundary.

M347_THRESHOLD_EUR: Final[Decimal]

RD 1065/2007 art. 33.1 (“operaciones que en su conjunto … hayan superado la cifra de 3.005,06 euros”), which fixes the figure; art. 31.1 only defines the general obligation. Counterparties whose annual operations total at most this amount are NOT declarable.

Type:

Modelo 347 declaration floor per counterparty. Binding provision

IVA_BIEN_INVERSION_MUEBLE_VENTANA_ANOS: Final[int]

IVA regularización de deducciones por bienes de inversión — regulatory constants (LIVA arts. 107-109, Ley 37/1992, BOE-A-1992-28740), re-read verbatim from the bundled consolidated corpus corpus/normatives/html/ley-37-1992-art-107.html and -art-109.html per legal-grounding-verifies-bundled-authoritative-corpus.

Art. 107.Uno: movable capital goods regularise over the “cuatro años naturales siguientes” to acquisition; art. 107.Tres: “terrenos o edificaciones” over the “nueve años naturales siguientes”. These are the count of FOLLOWING years in the regularisation window (the acquisition year itself is the year the deduction was made).

IVA_BIEN_INVERSION_REGULARIZACION_UMBRAL_PUNTOS: Final[Decimal]

the regularisation is practised only “cuando … exista una diferencia superior a diez puntos” between the definitive deduction percentage of the year and the one that prevailed in the acquisition year. The gate is STRICT (> 10 points); a difference of exactly 10 points does not trigger a regularisation. Binding provision: Art. 107.Uno LIVA (Ley 37/1992).

Type:

Art. 107.Uno

IVA_BIEN_INVERSION_MUEBLE_DIVISOR: Final[Decimal]

“La diferencia positiva o negativa se dividirá por cinco o, tratándose de terrenos o edificaciones, por diez”. The per-year regularisation quotient divides the deduction difference by 5 for movable goods and 10 for land/buildings. Binding provision: Art. 109.3.º LIVA (Ley 37/1992).

Type:

Art. 109.3.º

IVA_BIEN_ESCASO_VALOR_UMBRAL_EUR: Final[Decimal]

a good “cuyo valor de adquisición sea inferior a quinientas mil pesetas” is NOT a bien de inversión. The consolidated corpus still states the figure in pesetas; 500.000 ptas is the historic amount whose euro equivalent is 3.005,06 € (the same figure the Modelo 347 floor carries). A good whose acquisition value is at or above this threshold may qualify; below it is excluded. Binding provision: Art. 108.Dos.5.º LIVA (Ley 37/1992).

Type:

Art. 108.Dos.5.º bienes-de-escaso-valor exclusion

MODELO_720_REPORTING_THRESHOLD_EUR: Final[Decimal]

RD 1065/2007 arts. 42 bis/ter/quater (added by RD 1558/2012) under LGT DA 18ª — each block (cuentas / valores-seguros / inmuebles) carries an independent 50.000 € umbral. An obligation block is declarable iff its aggregate valuation strictly exceeds this amount.

Type:

Modelo 720 declaration floor per regulatory obligation bloque. Binding provision

MODELO_840_IAE_CIFRA_NEGOCIOS_EXEMPTION_THRESHOLD_EUR: Final[Decimal]

IAE art. 82.1.c net-turnover exemption ceiling for Modelo 840 threshold continuity. Binding provision: TRLRHL RDL 2/2004 art. 82.1.c (“importe neto de la cifra de negocios inferior a 1.000.000 de euros”). The gate is STRICTLY BELOW this amount; an INCN equal to 1,000,000.00 EUR is not within the turnover-based exemption.

ART_7P_EXEMPTION_CAP_EUR: Final[Decimal]

Art. 7.p) LIRPF (Ley 35/2006, BOE-A-2006-20764) annual exemption cap for foreign-work income of maritime and other qualifying workers. The exempt amount is the lesser of the proportional daily salary for qualifying days and this ceiling. Binding provision: Art. 7.p) LIRPF.

MULTIPLE_PAGADORES_SECONDARY_THRESHOLD_EUR: Final[Decimal]

Art. 96.3 LIRPF (Ley 35/2006) secondary-pagador trigger amount. When work income comes from more than one pagador, the reduced filing-exemption limit (see WORK_INCOME_MULTIPLE_PAGADORES_REDUCED_LIMIT_EUR_BY_YEAR) applies only when the aggregate income from the 2nd and subsequent pagadores STRICTLY exceeds this amount; at or below it the general 22.000 € limit is retained (Art. 96.3.a.1.º). Binding provision: Art. 96.3 LIRPF (Ley 35/2006). This trigger is year-stable and has not been revalued.

WORK_INCOME_GENERAL_DECLARATION_LIMIT_EUR: Final[Decimal]

Art. 96.2.a) LIRPF (Ley 35/2006) GENERAL filing-exemption ceiling for rendimientos íntegros del trabajo. A natural person whose work income does not exceed this amount (single pagador, or multiple pagadores with the 2nd-and- subsequent aggregate at or below 1.500 €) is NOT obliged to file Modelo 100 on account of work income. Binding provision: Art. 96.2.a) LIRPF (Ley 35/2006). This ceiling is year-stable.

WORK_INCOME_MULTIPLE_PAGADORES_REDUCED_LIMIT_EUR_BY_YEAR: Final[Mapping[int, Decimal]]

Art. 96.3 LIRPF (Ley 35/2006) REDUCED filing-exemption ceiling for rendimientos íntegros del trabajo, keyed by filing year (the year the income was obtained). The general 22.000 € ceiling drops to this reduced amount when work income comes from more than one pagador AND the 2nd-and-subsequent aggregate exceeds MULTIPLE_PAGADORES_SECONDARY_THRESHOLD_EUR (1.500 €). The amount is DATED: 2019-2022 use 14.000 € (Art. 96.3 LIRPF base value, post-Ley 26/2014); 2023 uses 15.000 € (Ley 31/2022 PGE-2023, BOE-A-2022-22128, art. 96.3 modification); 2024-2026 use 15.876 € (RD-Ley 4/2024, BOE-A-2024-13066, art. 96.3 modification, confirmed by the bundled consolidated LIRPF art-96 corpus). Binding provision: Art. 96.3 LIRPF (Ley 35/2006), as modified per year above. A filing year beyond the latest tabulated entry resolves to the latest known amount (forward-compatible) until a new law revalues it.

MODELO_202_ART_40_3_INCN_THRESHOLD_EUR: Final[Decimal]

Art. 40.3 LIS (Ley 27/2014, BOE-A-2014-12328) INCN threshold that makes the base-imponible pago-fraccionado modality MANDATORY for Modelo 202. A taxpayer whose importe neto de la cifra de negocios in the 12 months prior to the start of the relevant período impositivo exceeded this amount must use the art. 40.3 modality; below it, the art. 40.2 (cuota) modality is optional. Binding provision: Ley 27/2014 art. 40.3 (modalidad obligatoria por cifra de negocios).

MODELO_100_ART_20_TRABAJO_REDUCCION_RNT_CEILING_EUR: Final[Decimal]

Art. 20 LIRPF (Ley 35/2006) rendimiento-neto-del-trabajo ceiling above which the reducción por obtención de rendimientos del trabajo is zero. The reduction is a piecewise-linear function of the rendimiento neto del trabajo (RNT) that decays to zero at this ceiling: for RNT strictly below it the general reduction is positive; at or above it the reduction is nil. Used by the Modelo 100 art. 20 advisory to flag a possibly-unapplied reduction (RNT inside the band but the general-reduction casilla zero) — a no-silent-under-declaration safeguard. The DATED per-ejercicio schedule is authoritative in the registry; this is the current (2024-2025) ceiling raised by RDL 4/2024. Binding provision: Ley 35/2006 art. 20, schedule per RDL 4/2024 art. 3.1 (BOE-A-2024-12944).

MODELO_100_ART_52_INDIVIDUAL_SUBLIMIT_EUR: Final[Decimal]

Art. 52.1 LIRPF (Ley 35/2006) individual-contribution sub-limit for the reducción por aportaciones y contribuciones a sistemas de previsión social. The joint reducción (casilla 0468) is capped at the lesser of 30% of net yields and EUR 10.000, but a taxpayer whose aportaciones are PURELY individual — no plan-de-empleo worker contribution (casilla 0426) and no contribución empresarial (casilla 0427) backing the EUR 8.500 increment — is bound by the lower EUR 1.500 general limit; the EUR 8.500 increment “siempre que tal incremento provenga de contribuciones empresariales, o de aportaciones del trabajador al mismo instrumento de previsión social”. Used by the Modelo 100 art. 52 advisory to flag a possible over-reduction (a granted reducción above this sub-limit with no employer-linked backing) — a no-silent-under-declaration safeguard pending the full individual/ employer contribution-split compute (Phase 2b, 2026-07-01-modelo-100-trabajo-casilla-compute-adr). Binding provision: Ley 35/2006 art. 52.1.

DEFAULT_IVA_GENERAL_RATE_PCT: Final[Decimal]

Default IVA general-rate percentage for input/pre-fill purposes. This is the LIVA art. 90 Uno general rate (Ley 37/1992, BOE-A-1992-28740) currently in force for Spain (ES). The DATED authoritative percentage lives in registry/aeat/iva/rates.toml and is resolved via domain.iva.lookup_rate(); this constant is bound to that registry authority by a gate test so it cannot silently drift.

CLAVE_MOVIL_DIAGNOSTIC_NAMESPACE: Final[str]

Secure-object namespace slug for Cl@ve Móvil auth diagnostics. Used by the auth diagnostics service and the persistence namespace registry.

RETENCIONES_MODELOS: Final[tuple[Modelo, ...]]

Modelos belonging to the retenciones aggregation family (withholding/retention filings). Covers: M111 (labour income), M115 (leases), M123 (capital yields), M180 (lease annual), M190 (labour annual summary), M193 (capital yields annual summary).

COUNTERPART_MODELOS: Final[tuple[Modelo, ...]]

Modelos belonging to the counterpart aggregation family (third-party declaration filings). Covers: M347 (annual operations with third parties), M349 (intra-EU operations summary).

FOREIGN_ASSET_MODELOS: Final[tuple[Modelo, ...]]

Modelos belonging to the foreign assets aggregation family (overseas-asset declaration). Covers: M720 (assets and rights abroad declaration per Ley 7/2012).

IVA_REGIME_MODELOS: Final[tuple[Modelo, ...]]

Modelos belonging to the IVA regime gating group (value-added tax periodic filings). Covers: M303 (quarterly/monthly IVA self-assessment), M390 (IVA annual summary).

REBECA_MARITIME_EXEMPTION_FRACTION: Final[Decimal]

REBECA 50% exemption of qualifying maritime navigation income. Applies to crew of REBECA-registered vessels and scheduled Canary Islands routes. Binding provision: Ley 19/1994 art. 75.1 (BOE-A-1994-15794) fixes the 50 por 100 renta exenta; art. 73 establishes REBECA eligibility. Catalogue: ley-19-1994:art-75.

AMORTIZACION_INMUEBLE_RATE: Final[Decimal]

3% amortización de inmuebles arrendados; rate fixed by RD 439/2007 (RIRPF) art. 14.2.a (“3 por 100 sobre el mayor de coste de adquisición o valor catastral, excluido el suelo”). Deductibility base: Ley 35/2006 art. 23 (capital inmobiliario gastos deducibles).

DEDUCCION_MATERNIDAD_MENSUAL_EUR: Final[int]

Art. 81 LIRPF (Ley 35/2006, BOE-A-2006-20764) monthly accrual per hijo menor de tres años. Proration of the €1,200 annual cap; casilla 0611 carries integer euros only.

DEDUCCION_MATERNIDAD_ANUAL_CAP_EUR: Final[int]

Art. 81 LIRPF (Ley 35/2006, BOE-A-2006-20764) annual cap per hijo menor de tres años. The deducción accrues at €100/month and is capped at this amount per hijo; casilla 0611.

INCREMENTO_GUARDERIA_POR_HIJO_CAP_EUR: Final[int]

Art. 81 LIRPF (Ley 35/2006, BOE-A-2006-20764) incremento por gastos de custodia en guardería o centro de educación infantil autorizado, per hijo menor de tres años cap. Capped at the lesser of real gastos, this amount × hijos_menores_3, and SS cotizaciones; casilla 0613. Note: this is Art. 81 LIRPF (deducción maternidad supplemento), NOT Art. 81 bis (familia numerosa / discapacidad).

MINIMO_DESCENDIENTE_MAX_AGE: Final[int]

Art. 58.1 LIRPF (Ley 35/2006, BOE-A-2006-20764) ordinary mínimo-por-descendientes age ceiling: a descendant qualifies for the ordinary mínimo while younger than 25 (exclusive) at year end, unless disabled (which removes the age limit).

MINIMO_MENOR_TRES_MAX_AGE: Final[int]

Art. 58.2 LIRPF (Ley 35/2006, BOE-A-2006-20764) bajo-3-años supplement age ceiling: “Cuando el descendiente sea menor de tres años, el mínimo … se aumentará”. The additional mínimo applies to a descendant younger than 3 (exclusive) at year end.

CUSTODIA_COMPARTIDA_PRORRATA_FACTOR: Final[Decimal]

Art. 61.4ª LIRPF (Ley 35/2006, BOE-A-2006-20764) custodia compartida prorrata factor: under the normas comunes, when two contribuyentes have the right to the same mínimo “su importe se prorrateará entre ellos por partes iguales” — a 50 % split between the two custodial parents.

DT12_RESCATE_REDUCCION_RATE: Final[Decimal]

LIRPF Disposición Transitoria 12ª (Ley 35/2006, BOE-A-2006-20764) reducción rate: 40 % reducción on the part of a plan-de-pensiones capital rescate attributable to contributions made on or before 31-12-2006.

SAL_RESERVA_DOTACION_RATE: Final[Decimal]

Ley 44/2015 art. 14.1 (BOE-A-2015-11071) SAL/SLL reserva especial dotación rate: 10 % of net profit endowed each year (“se dotará con el diez por ciento del beneficio líquido de cada ejercicio”).

SAL_RESERVA_CAPITAL_MULTIPLE: Final[Decimal]

Ley 44/2015 art. 14.1 (BOE-A-2015-11071) SAL/SLL reserva especial accumulation cap multiple: the reserve accrues until it exceeds twice the share capital (“hasta que alcance al menos una cifra superior al doble del capital social”).

PRORRATA_ESPECIAL_MANDATORY_MULTIPLE: Final[Decimal]

LIVA art. 103.Dos (Ley 37/1992, BOE-A-1992-28740) prorrata especial mandatory multiple: the especial regime is mandatory when the general-regime deduction exceeds the especial-regime deduction by more than ten percent — i.e. when deduction_general > deduction_especial * 1.10.

PRORRATA_SECTORAL_SEPARATION_SPREAD_PP: Final[Decimal]

LIVA art. 9.1.c (Ley 37/1992, BOE-A-1992-28740) sectoral-separation threshold: régimen de sectores diferenciados is mandatory when the spread between the highest and lowest general prorrata across sectors exceeds fifty percentage points.

load_external_constants(path=None)[source]

Return the parsed external-constants registry.

Cached per-process; the first call reads and validates external_constants.toml from the package directory via importlib.resources so the resolution path is identical under editable installs and built wheels. Passing path is reserved for audits and tests that need to validate an alternate TOML payload against the same schema.

Parameters:

path (Path | None) – Optional TOML file to parse instead of the packaged registry.

Return type:

ExternalConstants

Returns:

The process-wide cached ExternalConstants instance.