aeat.application.calculations._maritime_exemption_service module¶
Application-layer service for maritime worker IRPF exemption resolution.
Bridges the domain maritime exemption engine with the application observation
pipeline. The service accepts resolved
MaritimeWorkerFacts and income
inputs, evaluates the Art. 7.p) and REBECA selectors, delegates calculation to
calculate_art_7p_exemption() and
calculate_rebeca_exemption(), and
returns typed CasillaObservation
rows alongside a derived flat casilla_values mapping.
The flat mapping is for human readability; the typed observation tuple is the
canonical contract per aeat-calculation-grounding because it carries
legal_refs and source_refs from the registry binding entries.
Calling conventions:
result = resolve_maritime_exemption(
facts=MaritimeWorkerFacts(
worker_class="trabajador_del_mar",
vessel_flag="foreign",
waters_type="international",
),
annual_salary=Decimal("36500"),
qualifying_days=180,
)
# result.observations: tuple of CasillaObservation with legal_refs/source_refs
# result.casilla_values: {casilla_id: Decimal} derived view
Error handling:
MaritimeExemptionInactiveError - DA 41 selector resolved True (inactive)
ProfileCompletenessError - RETMAR mandatory filing gate triggered
RentaValidationError - input validation failed
Callers are responsible for catching
ProfileCompletenessError,
surfacing its message to the operator, and continuing processing. It is not a
blocking calculation error.
- class MaritimeExemptionResult(**data)[source]¶
Bases:
BaseModelTyped result for a maritime worker exemption resolution.
Carries the ordered tuple of
CasillaObservationrows with full legal/source provenance and a derived flat mapping for human readability. Theobservationsfield is the canonical contract; callers must not persist or transmit only the flatcasilla_valuesview.- Parameters:
observations (tuple[CasillaObservation, ...])
retmar_mandatory_filing (bool)
- observations: tuple[CasillaObservation, ...]¶
- retmar_mandatory_filing: bool¶
- property casilla_values: Mapping[CasillaId, Decimal]¶
Derived flat view from canonical observations.
Returns a
Mapping[CasillaId, Decimal]for display and operator preview paths. The canonical storage isobservations; this view must not be used for persistence or wire payloads because it omitsCasillaObservationprovenance.
- resolve_maritime_exemption(*, facts, annual_salary=None, qualifying_days=None, gross_navigation_income=None)[source]¶
Resolve the applicable maritime exemption pathway and produce typed observations.
Evaluates
art_7p_eligible()andrebeca_eligible()in order. For each eligible pathway the corresponding domain calculation function is called and itsCasillaObservationis appended to the result.The DA 41 inactive guard runs before any calculation: if the DA 41 selector resolves true (currently when
tuna_fleetandpending_eu_clearanceare both set on a trabajador del mar profile),MaritimeExemptionInactiveErroris raised and no observations are produced.The RETMAR mandatory-filing gate is checked independently through
check_retmar_mandatory_filing(). Whenretmar_registeredis true,ProfileCompletenessErroris raised. Callers should catch it, surface the message to the operator, and continue processing. The gate does not suppress exemption calculations.- Parameters:
facts (
MaritimeWorkerFacts) – Resolved MaritimeWorkerFacts from the user profile.annual_salary (
Decimal|None) – Gross annual salary in EUR. Required when Art. 7.p) is potentially eligible.qualifying_days (
int|None) – Days of work outside Spain in the tax year. Required when Art. 7.p) is potentially eligible.gross_navigation_income (
Decimal|None) – Total gross navigation income in EUR. Required when REBECA is potentially eligible.
- Return type:
- Returns:
MaritimeExemptionResultwith typed observations and flat view.- Raises:
RentaValidationError – Eligibility predicate mismatch or invalid input. The DA 41 inactive guard and RETMAR completeness gate raise their own typed exceptions from the called guards.