Presupuesto representa una oferta comercial previa a la facturación. Un presupuesto no tiene validez fiscal por sí mismo, pero puede convertirse en una Factura una vez aceptado por el cliente. LEFA gestiona su ciclo de vida completo a través del enum EstadoPresupuesto, desde la fase de borrador hasta la conversión o el rechazo. Al igual que las facturas, el campo numero_presupuesto permanece NULL mientras el presupuesto es un borrador, y se asigna en el momento de su emisión.
Tabla SQL
La tabla en la base de datos SQLite se llamapresupuestos. Define la siguiente restricción de unicidad:
Como
numero_presupuesto admite NULL, múltiples borradores pueden coexistir sin violar la restricción hasta que se les asigna número.
Campos
int
required
Clave primaria autoincrementada. Identificador único e inmutable del presupuesto en la base de datos.
str | None
Número oficial del presupuesto (máx. 30 caracteres). Es
NULL mientras el presupuesto está en estado BORRADOR. Se asigna al emitirlo y queda protegido por la restricción uq_numero_presupuesto.str
Serie del presupuesto (máx. 20 caracteres). Valor por defecto:
"PRES". Permite identificar distintas series de presupuestación.int
required
Clave foránea hacia
clientes.id. Identifica el cliente al que va dirigida la oferta. No puede ser NULL.date | None
Fecha de emisión del presupuesto. Permanece
NULL en borradores. Se almacena como tipo Date de SQLAlchemy.date | None
Fecha límite de validez de la oferta. Pasada esta fecha, el presupuesto puede considerarse expirado. Puede ser
NULL si no se fija plazo.EstadoPresupuesto
required
Estado actual del presupuesto según el enum
EstadoPresupuesto. Valor por defecto: EstadoPresupuesto.BORRADOR.float
required
Porcentaje de IVA aplicable al presupuesto. Valor por defecto:
21.0. Se traspasa a la factura resultante al convertir.float
required
Porcentaje de retención de IRPF. Valor por defecto:
15.0. Se traspasa a la factura resultante al convertir.int | None
Clave foránea hacia
facturas.id. Se rellena cuando el presupuesto ha sido convertido en factura. NULL mientras no se haya convertido.Enum EstadoPresupuesto
EstadoPresupuesto hereda de str y enum.Enum, por lo que sus valores son cadenas de texto serializables directamente.
Un presupuesto en estado
CONVERTIDO tiene su campo factura_id apuntando a la factura generada. La factura, a su vez, registra el presupuesto de origen en presupuesto_origen_id.Relaciones
Cliente
Relación muchos-a-uno hacia el modelo
Cliente. Accesible como atributo de instancia. Se configura con back_populates="presupuestos".list[LineaPresupuesto]
Relación uno-a-muchos hacia
LineaPresupuesto. Las líneas se ordenan por LineaPresupuesto.id y se eliminan en cascada (cascade="all, delete-orphan") al borrar el presupuesto.Propiedades calculadas
Todos los métodos de cálculo operan sobre la colecciónself.lineas y los porcentajes fiscales almacenados en la instancia, con la misma lógica que el modelo Factura.
Modelo LineaPresupuesto
Cada Presupuesto contiene una lista de objetos LineaPresupuesto almacenados en la tabla lineas_presupuesto. Representan los conceptos o servicios incluidos en la oferta.
int
required
Clave primaria autoincrementada de la línea del presupuesto.
int
required
Clave foránea hacia
presupuestos.id. Vincula la línea con su presupuesto padre.str
required
Descripción del concepto o servicio ofertado (máx. 500 caracteres). No puede ser
NULL.float
required
Número de unidades del concepto. Valor por defecto:
1.0.float
required
Precio estimado por unidad en euros. Valor por defecto:
0.0.Propiedad subtotal
cantidad × precio_unitario, redondeado a dos decimales. Es la base sobre la que Presupuesto.calcular_subtotal() acumula el importe total de la oferta.
La estructura de
LineaPresupuesto es intencionalmente idéntica a la de LineaFactura. Esto facilita la conversión directa de presupuesto a factura: cada línea del presupuesto se duplica como línea de la factura resultante.