Módulo de Python que genera un string para la importación de datos en el modelo 303 de la Agencia Tributaria de España para los ejercicios soportados 2025 y 2026 (PRE 303 - Servicio ayuda modelo 303). El string generado se puede guardar en un fichero para importarlo en el modelo 303 para la presentación trimestral del IVA.
Este módulo está diseñado específicamente para facilitar la presentación del IVA trimestral de arrendadores de locales y viviendas urbanas que no realicen ninguna otra actividad. No es válido para otros casos, por lo que se recomienda su uso exclusivamente en el contexto mencionado.
Es importante tener en cuenta que este módulo no es aplicable en los siguientes casos:
- Si durante el trimestre se han realizado:
- Ventas de inmuebles
- Arrendamientos con opción de compra
- Servicios complementarios de hostelería
- Adquisiciones de bienes o servicios a proveedores extranjeros o establecidos en Canarias, Ceuta o Melilla (a excepción de obras realizadas por extranjeros).
- En declaraciones mensuales.
- En el régimen simplificado.
- En el Régimen Especial del Criterio de Caja.
- Si el % atribuible a la Administración del Estado es distinto de 100%.
- En el IVA a la importación liquidado por la Aduana pendiente de ingreso.
- En autoliquidaciones complementarias (opción y número de justificante).
- En casos en los que el volumen de operaciones anual sea igual a 0.
- Cuando existan cuotas pendientes de compensar de periodos anteriores.
- En la cuenta corriente tributaria - ingreso.
- En la cuenta corriente tributaria - devolución.
- En la devolución por transferencia al extranjero.
Por lo tanto, se recomienda al usuario verificar que se cumplen todas las condiciones necesarias antes de utilizar este módulo para la presentación del IVA trimestral.
Este proyecto es una herramienta técnica para ayudar a generar un fichero importable en el modelo 303. No constituye asesoramiento fiscal, contable ni jurídico.
Este proyecto no está afiliado, patrocinado, aprobado ni validado por la Agencia Estatal de Administración Tributaria (AEAT). Corresponde exclusivamente al usuario comprobar la normativa aplicable, los diseños de registro vigentes y el resultado final antes de presentar cualquier autoliquidación.
El software se distribuye bajo licencia MIT y se proporciona "tal cual" ("AS IS"), sin garantías de ningún tipo, expresas o implícitas, incluyendo (sin limitación) exactitud, idoneidad para un propósito concreto, ausencia de errores, continuidad de funcionamiento o adecuación a cambios normativos.
En la máxima medida permitida por la legislación aplicable, el autor y colaboradores no asumen responsabilidad por daños, pérdidas, sanciones, recargos, intereses, costes o reclamaciones derivados del uso, mal uso o imposibilidad de uso de la librería, incluidos errores en datos de entrada, configuraciones incorrectas, cambios de criterio de la AEAT o falta de actualización del software.
El usuario es el único responsable de:
- La veracidad, integridad y actualización de los datos introducidos.
- La revisión manual del fichero generado antes de su presentación.
- La validación final ante la AEAT y el cumplimiento de sus obligaciones fiscales.
Este descargo se interpreta sin perjuicio de los límites imperativos de responsabilidad que no puedan excluirse por ley.
Este módulo requiere Python 3.10 o superior.
El primer paso es recopilar la información necesaria para el trimestre fiscal que desees realizar la declaración. Esta información incluye datos del contribuyente, datos financieros y otros detalles específicos del trimestre. Algunos campos son obligatorios, como el periodo, la base imponible y el NIF del contribuyente, mientras que otros son opcionales dependiendo del contexto, como el volumen anual de operaciones (obligatorio solo en el cuarto trimestre).
Usando la clase Modelo303Data proporcionada por el módulo, puedes definir los datos requeridos. Cada campo tiene validaciones, como la longitud máxima, el formato y la obligatoriedad. Por ejemplo:
from arrendatools.modelo303.application.data import Modelo303Data
from arrendatools.modelo303.domain.enums import Period
datos = Modelo303Data(
ejercicio=Period.FOURTH_QUARTER,
version="1.0",
nif_empresa_desarrollo="12345678X",
razon_social="DE LOS PALOTES PERICO",
nif_contribuyente="12345678X",
iban="ES0012341234123412341234",
base_imponible=10000.00,
base_gastos_bienes_y_servicios=500.00,
cuota_gastos_bienes_y_servicios=105.00,
base_adquisiones_bienes_inversion=3000.00,
cuota_adquisiones_bienes_inversion=630.00,
volumen_anual_operaciones=20000.00
)El módulo incluye una API funcional para obtener el generador según ejercicio. Por ejemplo:
from arrendatools.modelo303.application.facade import get_generator
modelo = get_generator(2025)El proyecto utiliza un único generador para todos los ejercicios soportados:
- Generador único:
arrendatools.modelo303.application.generator.Modelo303Generator - Layouts por año:
arrendatools.modelo303.infrastructure.layout_registry.LAYOUTS
Cada ejercicio define su layout completo: registro de apertura, secciones 00, 01, 02, 03, 04, 05, DID y registro de cierre.
Para añadir un nuevo año (por ejemplo, 2027) hay que revisar 4 piezas: layout, catalog, model y year_overrides.
-
Crear el layout anual. Archivo recomendado:
src/arrendatools/modelo303/infrastructure/layout_2027.py. Puedes hacerlo a partir delayout_2026.pyy ajustar orden de campos/páginas según el diseño oficial del año. -
Registrar el layout en el registry. Edita
src/arrendatools/modelo303/infrastructure/layout_registry.py:- importa
LAYOUTdel nuevo módulo; - añade la entrada
2027: LAYOUT_2027enLAYOUTS.get_generator(...)usa este diccionario para decidir si un ejercicio está soportado.
- importa
-
Revisar
catalog.pypara campos nuevos o cambios de formato. Archivo:src/arrendatools/modelo303/infrastructure/catalog.py.- Si aparecen campos nuevos en el layout, deben existir en
FIELD_CATALOG. - Si cambia longitud/tipo, actualiza
FieldDef(length, field_type, ...). - Para campos numéricos:
- usa
scale_to_cents=Truecuando el valor representa importes monetarios; - usa
scale_to_cents=Falsepara códigos, flags, año, etc.
- usa
- Si cambia una regla de validación de tipo, ajusta
_validate_type(...).
- Si aparecen campos nuevos en el layout, deben existir en
-
Revisar el modelo de dominio para asegurar que todos los campos se resuelven. Archivo:
src/arrendatools/modelo303/domain/model.py.- Si el nuevo layout/catálogo introduce campos de datos (no literales), añade atributos en
Modelo303Model. - Si el año exige lógica distinta en cálculos, intenta mantener los métodos base (
compute_casilla_*) estables y delega diferencias anuales a overrides. - Mantén operaciones monetarias con
Decimalyquantize(...).
- Si el nuevo layout/catálogo introduce campos de datos (no literales), añade atributos en
-
Crear y registrar overrides anuales. Crea
src/arrendatools/modelo303/infrastructure/year_overrides_2027.pycon:CASILLA_DEFAULTS: valores simples por defecto para ese año;CASILLA_CALCULATORS: funciones para campos cuyo cálculo cambia ese año. Luego registra el módulo ensrc/arrendatools/modelo303/infrastructure/year_overrides.py:- importa
CASILLA_DEFAULTSyCASILLA_CALCULATORS; - añade
2027enYEAR_OVERRIDES_REGISTRY.
-
Añadir tests del nuevo ejercicio.
- Crea tests tipo
tests/test_generator_tax_year_2027.pytomando como base los de 2026. - Añade ficheros golden en
tests/golden/2027/.... - Actualiza tests de factoría/soporte de años (
tests/test_modelo303_factory.py) para incluir 2027. - Verifica también los tests de alineación (
tests/test_catalog_model_alignment.py), que detectan campos en layout sin catálogo o campos no renderizables.
- Crea tests tipo
Checklist mínimo para dar por soportado un nuevo año:
get_generator(2027)devuelve generador sin error.- Todos los campos de
layout_2027existen enFIELD_CATALOG. Modelo303Model.from_data(...)genera string válido para escenarios 1T/2T/3T, 4T y sin IBAN.- Golden tests del año pasan.
Ahora ya puedes generar el fichero utilizando el método correspondiente. Este método convierte los datos proporcionados en un formato compatible con el sistema de la Agencia Tributaria. Por ejemplo:
datos_fichero = modelo.generate(datos)A continuación se muestra un ejemplo completo de cómo crear un objeto GeneradorModelo303 para el ejercicio 2025 y generar un archivo con los datos del modelo:
from arrendatools.modelo303.application.facade import get_generator
from arrendatools.modelo303.application.data import Modelo303Data
from arrendatools.modelo303.domain.enums import Period
period = Period.THIRD_QUARTER
anyo_fiscal = 2025
nif_empresa_desarrollo = "12345678X"
version = "v1.0"
nif_contribuyente = "12345678X"
razon_social = "DE LOS PALOTES PERICO"
iban = "ES0012341234123412341234"
base_imponible = 2000.00
base_gastos_bienes_y_servicios = 2500.0
cuota_gastos_bienes_y_servicios = 525.0
base_adquisiones_bienes_inversion = 0.0
cuota_adquisiones_bienes_inversion = 0.0
volumen_anual_operaciones = None
datos_modelo = Modelo303Data(
ejercicio=period,
nif_empresa_desarrollo=nif_empresa_desarrollo,
version=version,
razon_social=razon_social,
nif_contribuyente=nif_contribuyente,
iban=iban,
base_imponible=base_imponible,
base_gastos_bienes_y_servicios=base_gastos_bienes_y_servicios,
cuota_gastos_bienes_y_servicios=cuota_gastos_bienes_y_servicios,
base_adquisiones_bienes_inversion=base_adquisiones_bienes_inversion,
cuota_adquisiones_bienes_inversion=cuota_adquisiones_bienes_inversion,
volumen_anual_operaciones=volumen_anual_operaciones,
)
modelo = get_generator(anyo_fiscal)
datos_fichero = modelo.generate(datos_modelo)
print(datos_fichero)
with open(f"{nif_contribuyente}_{anyo_fiscal}_{period.value}.303", "w") as archivo:
archivo.write(datos_fichero)Es importante tener en cuenta que, aunque el ejemplo anterior es funcional, es posible que la importación en la web de la Agencia Tributaria falle en las validaciones adicionales que esta realiza, por lo que se deben proporcionar los datos correctos para poder importar correctamente el modelo en la web de la Agencia Tributaria.