aeat.domain.renta._maritime_exemption module¶
Maritime worker IRPF exemption calculation engine.
Implements the three legally distinct exemption pathways for trabajadores
del mar and the associated profile completeness gate. Each calculation
function returns a CasillaObservation carrying the exempt amount
and its full legal provenance.
Active exemption axes (2024/2025):
- Art. 7.p) LIRPF (Ley 35/2006, BOE-A-2006-20764)
Conditions: foreign-flagged vessel OR international waters; foreign entity receiving services; territory with CDI or equivalent income tax. Annual cap: 60,100 EUR. Formula: min(annual_salary / 365 * qualifying_days, 60_100)
- REBECA 50% exemption (Ley 19/1994, Arts. 73.2 73.3 75.1 75.3, BOE-A-1994-15794)
Crew of REBECA-registered vessels or scheduled Canary Islands routes. Exempt 50% is excluded from the Modelo 111 withholding base by employer.
Inactive axis (future variant):
- DA 41 LIRPF (Ley 35/2006 DA 41, added by Ley 26/2014 BOE-A-2014-12327)
50% exemption for tuna fleet crew. Requires EU state-aid clearance not granted as of 2024/2025. Engine raises MaritimeExemptionInactiveError when the selector resolves True so it is never silently applied.
Profile completeness gate (not a calculation axis):
- RETM mandatory filing (Ley 35/2006 Art. 96, BOE-A-2006-20764)
Since January 2023 all RETMAR-registered workers must file IRPF regardless of income level. Raises ProfileCompletenessError; it does not alter casilla values.
- Provisions outside scope:
The transitional withholding rule from January 2015 (a different disposicion adicional with no maritime content) must not be cited as a maritime exemption anchor in any registry or code artefact. Art. 17.1.d) / Art. 9 RIRPF daily allowance caps apply generically; TEAC narrowed their scope for crew whose ordinary workplace is the vessel (STS 954/2020, STS 3185/2021). No special per-diem exists in any currently applicable LIRPF provision for these workers.
- exception MaritimeExemptionInactiveError(message=None, *, context=None, suggestion=None, translated_message=None)[source]¶
Bases:
RentaErrorRaised when the DA 41 selector resolves True for a trabajador del mar.
DA 41 LIRPF requires prior EU state-aid clearance under TFEU rules. That clearance has not been granted as of 2024/2025. The engine raises this error instead of silently producing an exempt-income observation, which would be legally incorrect output.
Once EU clearance is granted a follow-up task must flip the binding status in trabajador_del_mar.toml and add oracle-backed tests; no code change in this module is required.
Legal authority: Ley 35/2006 DA 41 BOE-A-2006-20764 (as amended by Ley 26/2014 BOE-A-2014-12327).
- Parameters:
- Return type:
None
- code: ClassVar[ErrorCode]¶
- exception ProfileCompletenessError(message=None, *, context=None, suggestion=None, translated_message=None)[source]¶
Bases:
RentaErrorRaised when a RETMAR-registered worker’s profile is presented for filing.
Since 2023, all workers registered in the maritime special Social Security regime must file an IRPF declaration regardless of income level (Ley 35/2006 art. 96, BOE-A-2006-20764). This is a profile completeness gate — it does not alter casilla values or formula execution paths.
Callers should surface the mandatory-filing status to the operator in CLI JSON output; the warning must not suppress further processing.
- Parameters:
- Return type:
None
- code: ClassVar[ErrorCode]¶
- class MaritimeWorkerFacts(worker_class=None, vessel_flag=None, waters_type=None, vessel_registry=None, tuna_fleet=False, pending_eu_clearance=False, retmar_registered=False)[source]¶
Bases:
objectResolved profile facts that gate maritime exemption pathway selection.
All fields are optional and default to the non-triggering value so that callers building partial profiles do not require every fact to be present. A profile without worker_class = “trabajador_del_mar” is unaffected by any predicate in this module.
- Variables:
worker_class – Must be
"trabajador_del_mar"to activate any maritime exemption pathway.vessel_flag –
"ES"(Spanish-flagged) or"foreign".waters_type –
"national"or"international".vessel_registry – One of
"REBECA","rebeca_eu_eea","scheduled_canary_route", orNone.tuna_fleet – Whether the vessel is a qualifying tuna fleet vessel (DA 41 selector; currently always inactive).
pending_eu_clearance – Mirrors the DA 41 TOML selector field. Must be True alongside tuna_fleet to trigger the inactive gate.
retmar_registered – Whether the taxpayer is in the RETMAR register. Drives the mandatory-filing completeness check only.
- Parameters:
- art_7p_eligible(facts)[source]¶
Return True when Art. 7.p) LIRPF applies to the worker profile.
Conditions (conjunctive): - worker_class == “trabajador_del_mar” - vessel_flag == “foreign” OR waters_type == “international”
The ADR notes that international waters qualify for foreign-flagged vessels per AEAT accepted practice, confirmed by TEAR Galicia December 2024 for Galician fishing crew and by Supreme Court doctrine extended April 2025 to military Navy in NATO/UN sea operations.
Legal authority: Ley 35/2006 Art. 7.p) BOE-A-2006-20764.
- Return type:
- Parameters:
facts (MaritimeWorkerFacts)
- rebeca_eligible(facts)[source]¶
Return True when the REBECA 50% exemption applies to the worker profile.
Conditions: - worker_class == “trabajador_del_mar” - vessel_registry in {“REBECA”, “rebeca_eu_eea”, “scheduled_canary_route”}
The “rebeca_eu_eea” value covers the 2021 extension to crews of REBECA-registered company vessels enrolled in other EU/EEA member state registries (Ley 19/1994 Art. 75.1).
Legal authority: Ley 19/1994 Arts. 73.2 73.3 75.1 75.3 BOE-A-1994-15794.
- Return type:
- Parameters:
facts (MaritimeWorkerFacts)
- da41_eligible(facts)[source]¶
Return True when the DA 41 tuna-fleet selector resolves.
DA 41 requires: - worker_class == “trabajador_del_mar” - tuna_fleet == True - pending_eu_clearance == True
The binding is currently inactive_pending_eu_clearance. Callers must check the return value and raise MaritimeExemptionInactiveError when True; this predicate is deliberately separated from the error-raising path so it can be tested independently.
Legal authority: Ley 35/2006 DA 41 BOE-A-2006-20764 (as amended by Ley 26/2014 BOE-A-2014-12327).
- Return type:
- Parameters:
facts (MaritimeWorkerFacts)
- calculate_art_7p_exemption(*, annual_salary, qualifying_days, facts)[source]¶
Calculate the Art. 7.p) exempt amount and return a
CasillaObservation.- Formula (Ley 35/2006 Art. 7.p) BOE-A-2006-20764):
exempt_amount = min(annual_salary / 365 * qualifying_days, 60_100)
The observation carries legal_refs and source_refs from the registry binding entry so the provenance is traceable from calculation to CLI emit.
- Parameters:
annual_salary (
Decimal) – Gross annual employment salary in EUR (Decimal).qualifying_days (
int) – Calendar days of work effectively performed outside Spanish territory within the tax year. Must be in [1, 365].facts (
MaritimeWorkerFacts) – Resolved MaritimeWorkerFacts. art_7p_eligible must be True; raises RentaValidationError otherwise.
- Return type:
- Returns:
CasillaObservationfor the renta exenta casilla with the exempt amount and full legal provenance.- Raises:
RentaValidationError – When eligibility predicate is not satisfied or when input values are out of range.
- calculate_rebeca_exemption(*, gross_navigation_income, facts)[source]¶
Calculate the REBECA 50% exempt amount and return a typed CasillaObservation.
- Formula (Ley 19/1994 Arts. 73-75 BOE-A-1994-15794):
exempt_amount = gross_navigation_income * 0.50
The 50% fraction is statutory and not variable by election.
- Parameters:
gross_navigation_income (
Decimal) – Total gross employment income from navigation in EUR (Decimal). Must be positive.facts (
MaritimeWorkerFacts) – Resolved MaritimeWorkerFacts. rebeca_eligible must be True; raises RentaValidationError otherwise.
- Return type:
- Returns:
CasillaObservationfor the renta exenta casilla with the exempt amount and full legal provenance.- Raises:
RentaValidationError – When eligibility predicate is not satisfied or when input values are out of range.
- guard_da41_inactive(facts)[source]¶
Raise MaritimeExemptionInactiveError if DA 41 selector resolves True.
This function must be called before any code path that would produce DA 41 exempt-income output. DA 41 requires EU state-aid clearance not granted as of 2024/2025; silently producing an exempt amount would be legally incorrect.
- Parameters:
facts (
MaritimeWorkerFacts) – Resolved MaritimeWorkerFacts.- Raises:
MaritimeExemptionInactiveError – When da41_eligible returns True.
- Return type:
- check_retmar_mandatory_filing(facts)[source]¶
Raise ProfileCompletenessError when retmar_registered is True.
Since 2023, all workers registered in the maritime special Social Security regime must file an IRPF declaration regardless of income level (Ley 35/2006 art. 96, BOE-A-2006-20764). This is a completeness gate only — it must not suppress further processing or alter casilla values.
Callers should catch ProfileCompletenessError, surface the message to the operator, and continue processing.
- Parameters:
facts (
MaritimeWorkerFacts) – Resolved MaritimeWorkerFacts.- Raises:
ProfileCompletenessError – When retmar_registered is True.
- Return type: