Skip to main content
PresupuestoService gestiona el ciclo de vida completo de los presupuestos en LEFA, desde la creación del borrador hasta la conversión en factura. Todos sus métodos son estáticos y operan sobre SQLite mediante SQLAlchemy. La trazabilidad bidireccional entre presupuesto y factura se mantiene automáticamente: al convertir un presupuesto, el campo factura_id del presupuesto y el campo presupuesto_origen_id de la factura quedan enlazados en la base de datos. La serie de numeración de presupuestos es fija y se obtiene de la constante SERIE_PRESUPUESTO definida en lefa.config.

DTO

LineaPresupuestoDTO

Objeto de transferencia para líneas de presupuesto desde la interfaz de usuario.
str
required
Descripción del concepto o servicio presupuestado.
float
required
Número de unidades del concepto.
float
required
Precio por unidad en euros (sin impuestos).

Métodos

listar_todos

Devuelve todos los presupuestos almacenados en la base de datos, independientemente de su estado, ordenados por id descendente. Las relaciones cliente y lineas se cargan con joinedload. Retorna: Lista de objetos Presupuesto desvinculados de la sesión.

obtener_por_id

Carga un presupuesto por su clave primaria con las relaciones cliente y lineas precargadas.
int
required
Identificador del presupuesto en la base de datos.
Retorna: Presupuesto desvinculado de la sesión, o None si no existe.

guardar_borrador

Crea un presupuesto nuevo en estado BORRADOR o actualiza uno existente. El número oficial (numero_presupuesto) permanece NULL hasta la emisión. La serie se asigna automáticamente a partir de SERIE_PRESUPUESTO.
int
required
Cliente destinatario del presupuesto.
list[LineaPresupuestoDTO]
required
Líneas del presupuesto. Debe contener al menos un elemento.
float
required
Porcentaje de IVA (p. ej. 21.0).
float
required
Porcentaje de retención de IRPF (p. ej. 15.0).
int | None
Si se indica, actualiza el borrador existente con ese ID. Las líneas anteriores se eliminan y se reemplazan por las nuevas.
date | None
Fecha de vencimiento de la oferta. Si es None, se calculará automáticamente como hoy + 30 días durante la emisión.
Retorna: Presupuesto en estado BORRADOR desvinculado de la sesión. Lanza ValueError si:
  • lineas está vacía.
  • Se proporciona presupuesto_id pero el presupuesto no existe.
  • El presupuesto encontrado no está en estado BORRADOR.

emitir_presupuesto

Asigna número correlativo y fecha de emisión al presupuesto. Si validez_hasta no fue establecida en el borrador, se calcula automáticamente como hoy + 30 días. La numeración se obtiene mediante NumeracionService.siguiente_secuencia_presupuesto, que mantiene una secuencia independiente de las facturas.
int
required
ID del presupuesto borrador a emitir.
Retorna: Presupuesto en estado EMITIDO con número oficial asignado. Lanza ValueError si:
  • El presupuesto no existe.
  • No está en estado BORRADOR.
  • No tiene líneas.

aceptar

Marca un presupuesto emitido como aceptado por el cliente. Solo es posible si el presupuesto está en estado EMITIDO.
int
required
ID del presupuesto a aceptar.
Retorna: Presupuesto en estado ACEPTADO. Lanza ValueError si:
  • El presupuesto no existe.
  • No está en estado EMITIDO.

rechazar

Marca un presupuesto como rechazado. Acepta presupuestos tanto en estado EMITIDO como ACEPTADO (un cliente puede retractarse de su aceptación).
int
required
ID del presupuesto a rechazar.
Retorna: Presupuesto en estado RECHAZADO. Lanza ValueError si:
  • El presupuesto no existe.
  • El estado no es EMITIDO ni ACEPTADO.

convertir_a_factura

Convierte un presupuesto en un borrador de factura, copiando cliente, líneas y porcentajes de impuestos. Si el presupuesto estaba solo EMITIDO, se acepta automáticamente antes de la conversión. Tras crear el borrador de factura, el presupuesto pasa al estado CONVERTIDO y su campo factura_id queda enlazado con el ID del nuevo borrador, estableciendo la trazabilidad bidireccional.
int
required
ID del presupuesto a convertir. Debe estar en estado EMITIDO o ACEPTADO.
Retorna: int con el ID del borrador de factura recién creado. Lanza ValueError si:
  • El presupuesto no existe.
  • Ya fue convertido (CONVERTIDO).
  • Está en estado RECHAZADO.
  • Está en estado BORRADOR (debe emitirse primero).

Ejemplo de uso: flujo completo de presupuesto a factura

convertir_a_factura abre una sesión para leer el presupuesto y sus líneas, luego la cierra antes de llamar a FacturaService.guardar_borrador (que abre su propia sesión). Esto evita tener dos sesiones anidadas activas sobre la misma conexión SQLite.