aeat.core.setup_answers module

Canonical typed-answer model and projection slot for the setup flow.

SetupAnswers is the authoritative typed-answers model for the wizard setup flow. Domain modules import it from here, not from the application wizard layer, so the permitted dependency direction remains domain-to-core rather than domain-to-application.

This module owns typed answer validation and the core registration slot for the reverse projection from persisted canonical-token strings. It does not own prompt rendering, profile persistence, secure storage, deadline scheduling, or registry semantics. The application wizard registers its concrete projector at startup with register_project_answers(); domain consumers call project_answers() through this core slot and receive ProjectAnswersNotRegisteredError if startup has not installed it.

The contract mirrors aeat.core.wizard_catalogue: the application layer declares the SETUP_FLOW descriptor, while core exposes the stable answer model and the projection hook. Downstream profile construction, including taxpayer_profile_from_mapping, therefore stays aligned with wizard canonical-token parsing without importing application modules directly.

Domain taxonomy types (EntityType, IVARegime, etc.) are imported lazily inside validators rather than at module level to break the circular import path: aeat.core.setup_answers -> aeat.domain.deadlines._models -> aeat.domain.deadlines.__init__ -> aeat.domain.deadlines._profiles -> aeat.core.setup_answers. This mirrors the deferral strategy used in aeat.core.resources._repos.* and is the established project pattern.

exception ProfileRegistrationError(message=None, *, context=None, suggestion=None, translated_message=None)[source]

Bases: CoreError

Raised when register_project_answers() is called a second time with a different callable.

A double-registration with the same callable is a safe no-op; a double-registration with a different callable is a programming error that must be surfaced as a typed, registry-bound exception so callers receive a structured error envelope rather than a bare RuntimeError.

Parameters:
  • message (str | None)

  • context (dict[str, object] | None)

  • suggestion (str | None)

  • translated_message (str | None)

Return type:

None

code: ClassVar[ErrorCode]
exception ProjectAnswersNotRegisteredError[source]

Bases: CoreError

Raised when domain code calls project_answers() before registration.

Return type:

None

code: ClassVar[ErrorCode]
class ProjectAnswersFn(*args, **kwargs)[source]

Bases: Protocol

Structural type for the project_answers callable.

Satisfied by aeat.application.wizard._persistence.project_answers. Domain code depends only on this protocol.

register_project_answers(fn)[source]

Register the concrete project_answers implementation from the application layer.

Call exactly once at application startup (e.g. in aeat.application.wizard._persistence module body after the function is defined). A second call with an identical callable is a no-op; a second call with a different callable raises ProfileRegistrationError. Domain code should depend on project_answers(), not on the application-layer implementation object registered here.

Return type:

None

Parameters:

fn (ProjectAnswersFn)

get_project_answers()[source]

Return the registered project_answers implementation.

Return type:

ProjectAnswersFn

Returns:

The ProjectAnswersFn registered via register_project_answers().

Raises:

ProjectAnswersNotRegisteredError – When the application layer has not yet called register_project_answers().

project_answers(flow, values)[source]

Invoke the registered project_answers implementation.

Delegates to the application-layer function registered via register_project_answers(). Domain callers import this function from aeat.core.setup_answers so they never acquire a direct dependency on aeat.application.wizard._persistence.

Parameters:
  • flow (Any) – The wizard flow descriptor identifying which flow to project answers for.

  • values (Mapping[str, str]) – Mapping of canonical token keys to raw string values collected from the wizard or read from profile storage. Blank strings preserve undeclared optional facts for the registered projector to interpret.

Return type:

BaseModel

Returns:

A typed answers model instance produced by the registered implementation.

class SetupAnswers(**data)[source]

Bases: BaseModel

Typed answers collected by the setup flow.

Canonical home is aeat.core.setup_answers. The application wizard layer imports SetupAnswers from here; the domain deadline engine likewise imports it from here — no layer needs to cross the hexagonal boundary.

The model stores canonical answer tokens and typed taxonomy values for the setup flow. It is not the persisted profile record and it is not the deadline-engine taxpayer profile; those are produced downstream by wizard persistence and deadline profile projection. Where validators allow the empty string, the value means undeclared/no answer rather than false, zero, or a default legal fact.

Field annotations use Any for domain taxonomy union types because those types are loaded lazily inside validators to prevent a circular import. That Any is not a loose schema: validators enforce the same invariants the original typed annotations carried, reject values outside the declared enum / blank-string set, and raise ProfileAnswerTypeError.

Parameters:
  • tax_id (str)

  • name (str)

  • surnames (str)

  • legal_name (str)

  • activity (str)

  • address_postcode (str)

  • activity_start_date (str)

  • taxation_type (Any)

  • output_language (OutputLanguage)

  • entity_type (Any)

  • legal_entity_form (Any)

  • incn_prior_12_months (str)

  • new_entity_first_two_profit_periods (Any)

  • ley_49_2002_option_declared (Any)

  • ley_49_2002_option_date (str)

  • ley_49_2002_renunciation_declared (Any)

  • ley_49_2002_renunciation_date (str)

  • irpf_income_categories (str)

  • taxpayer_sex (Any)

  • taxpayer_marital_status (Any)

  • taxpayer_marriage_date (str)

  • taxpayer_birth_date (str)

  • taxpayer_disability_grade (Any)

  • taxpayer_death_date (str)

  • spouse_tax_id (str)

  • spouse_name (str)

  • spouse_surnames (str)

  • spouse_birth_date (str)

  • spouse_sex (Any)

  • spouse_disability_grade (Any)

  • spouse_non_resident_irpf (bool)

  • spouse_eu_eea_resident (bool)

  • spouse_eu_eea_country (str)

  • family_descendants_eu_eea_deduction (bool)

  • family_minor_children_in_unit (bool)

  • situacion_familiar (Any)

  • unidad_familiar_descendientes_exclusivos (Any)

  • iva_regime (Any)

  • iva_roi_enrolled (bool)

  • iva_oss_enrolled (bool)

  • iva_group_member_enrolled (bool)

  • iva_group_dominant_entity_enrolled (bool)

  • iva_sii_enrolled (bool)

  • iva_redeme_enrolled (bool)

  • iva_intracommunity_operations_exceed_50000_eur (bool)

  • enrollment_large_company (bool)

  • enrollment_public_administration_budget_gt_6000000 (bool)

  • has_employees (bool)

  • pays_professionals_with_retencion (bool)

  • professional_income_withholding_ge_70pct (bool)

  • art109_activity_income_withholding_ge_70pct (bool)

  • pays_rent_with_retencion (bool)

  • pays_capital_income_with_retencion (bool)

  • modelo_111_no_retenciones_periods (str)

  • irpf_estimation_regime (Any)

  • objective_estimation_modulos_iae_epigraph (str)

  • objective_estimation_modulos_module_1_units (str)

  • objective_estimation_modulos_module_2_units (str)

  • objective_estimation_modulos_module_3_units (str)

  • objective_estimation_modulos_module_4_units (str)

  • objective_estimation_modulos_module_5_units (str)

  • objective_estimation_modulos_module_6_units (str)

  • objective_estimation_modulos_module_7_units (str)

  • irpf_special_regime (Any)

  • irpf_special_regime_start_date (str)

  • does_intracomunitario (bool)

  • third_party_transactions_above_347_threshold (bool)

  • bienes_extranjero_above_threshold (bool)

  • monedas_virtuales_extranjero_above_threshold (bool)

  • tax_residence_ccaa (Any)

  • fiscal_residency (Any)

  • country_of_fiscal_residence (str)

  • representante_fiscal_nif (str)

  • representante_fiscal_nombre (str)

  • cloud_evidence_upload (bool)

  • llm_vision (bool)

  • google_export (bool)

  • notes (str)

tax_id: str
name: str
surnames: str
legal_name: str
activity: str

Free-text actividad económica / epígrafe IAE description.

address_postcode: str

Optional Spanish postcode for the taxpayer’s activity/contact address.

activity_start_date: str

Optional ISO-8601 censo alta date for the economic activity.

taxation_type: Any
output_language: OutputLanguage
entity_type: Any
legal_entity_form: Any
incn_prior_12_months: str

Optional INCN as a canonical decimal string.

new_entity_first_two_profit_periods: Any

Optional three-state bool for LIS Art. 29 new-entity rate.

ley_49_2002_option_declared: Any

Optional three-state bool for the Ley 49/2002 Title II option.

ley_49_2002_option_date: str

ISO-8601 date declared for the Ley 49/2002 Title II option.

ley_49_2002_renunciation_declared: Any

Optional three-state bool for Ley 49/2002 Title II renunciation.

ley_49_2002_renunciation_date: str

ISO-8601 date declared for the Ley 49/2002 Title II renunciation.

irpf_income_categories: str

Comma-separated set of IrpfIncomeCategory tokens.

taxpayer_sex: Any
taxpayer_marital_status: Any
taxpayer_marriage_date: str

ISO-8601 date when the current marriage began.

taxpayer_birth_date: str
taxpayer_disability_grade: Any
taxpayer_death_date: str
spouse_tax_id: str
spouse_name: str
spouse_surnames: str
spouse_birth_date: str
spouse_sex: Any
spouse_disability_grade: Any
spouse_non_resident_irpf: bool
spouse_eu_eea_resident: bool
spouse_eu_eea_country: str
family_descendants_eu_eea_deduction: bool
family_minor_children_in_unit: bool
situacion_familiar: Any

Art. 82 LIRPF family situation governing conjunta eligibility.

unidad_familiar_descendientes_exclusivos: Any

Custodia compartida progenitor claiming the monoparental unidad familiar.

iva_regime: Any
iva_roi_enrolled: bool
iva_oss_enrolled: bool
iva_group_member_enrolled: bool
iva_group_dominant_entity_enrolled: bool
iva_sii_enrolled: bool
iva_redeme_enrolled: bool
iva_intracommunity_operations_exceed_50000_eur: bool
enrollment_large_company: bool
enrollment_public_administration_budget_gt_6000000: bool
has_employees: bool
pays_professionals_with_retencion: bool
professional_income_withholding_ge_70pct: bool
art109_activity_income_withholding_ge_70pct: bool
pays_rent_with_retencion: bool
pays_capital_income_with_retencion: bool
modelo_111_no_retenciones_periods: str
irpf_estimation_regime: Any
objective_estimation_modulos_iae_epigraph: str
objective_estimation_modulos_module_1_units: str
objective_estimation_modulos_module_2_units: str
objective_estimation_modulos_module_3_units: str
objective_estimation_modulos_module_4_units: str
objective_estimation_modulos_module_5_units: str
objective_estimation_modulos_module_6_units: str
objective_estimation_modulos_module_7_units: str
irpf_special_regime: Any

IRPF special-regime axis. Blank for the general regime.

irpf_special_regime_start_date: str

ISO-8601 opt-in election date for the special regime.

does_intracomunitario: bool
third_party_transactions_above_347_threshold: bool
bienes_extranjero_above_threshold: bool
monedas_virtuales_extranjero_above_threshold: bool
tax_residence_ccaa: Any
fiscal_residency: Any

Fiscal residency category.

country_of_fiscal_residence: str

ISO 3166-1 alpha-2 code of the country of fiscal residence.

representante_fiscal_nif: str

NIF/NIE of the fiscal representative in Spain.

representante_fiscal_nombre: str

Full name of the fiscal representative in Spain.

cloud_evidence_upload: bool
llm_vision: bool
google_export: bool
notes: str