Ir al contenido

Sale → proyecto → factura: automatizar el flujo en Odoo

Server actions, automatizaciones y estados con tracking
26 de junio de 2026 por
Sale → proyecto → factura: automatizar el flujo en Odoo
Atemi, Aitor Atencia

Odoo · Ventas · Automatización

El flujo presupuesto → proyecto → factura es el corazón de muchos negocios de servicios. Odoo lo soporta de serie, pero encadenar los pasos sin intervención manual (y sin disparos infinitos) requiere elegir bien entre automatización declarativa, server action o código Python. Aquí están los tres niveles.

Logo Odoo Flujo
Confirmar la venta crea el proyecto; cerrar el proyecto habilita la factura.

Nativo

Lo que Odoo ya hace solo

PasoMecanismo nativo
Venta → proyectoProducto de tipo servicio con service_tracking="task_in_project"
Proyecto → partes de horasTareas con timesheet_ids facturables
Horas → facturaCrear factura sobre líneas facturables del pedido

Antes de programar nada, revisa si la configuración del producto cubre tu caso. El 70% de las «automatizaciones» que piden los clientes ya existen en los ajustes.

Nivel 1

Automatización declarativa (base.automation)

<record id="automation_so_confirm_notify" model="base.automation">
    <field name="name">Aviso al confirmar pedido</field>
    <field name="model_id" ref="sale.model_sale_order"/>
    <field name="trigger">on_state_set</field>
    <field name="trg_selection_field_id"
           ref="sale.selection__sale_order__state__sale"/>
    <field name="state">code</field>
    <field name="code">
for order in records:
    order.message_post(body="Pedido confirmado, proyecto en marcha.")
    </field>
</record>

Nivel 2

Lógica en el modelo (override de método)

class SaleOrder(models.Model):
    _inherit = 'sale.order'

    def action_confirm(self):
        res = super().action_confirm()
        for order in self:
            if order.project_count and not order.diagnostic_done:
                order._schedule_kickoff_activity()
        return res

    def _schedule_kickoff_activity(self):
        self.activity_schedule(
            'mail.mail_activity_data_todo',
            summary='Reunión de arranque del proyecto',
            user_id=self.user_id.id,
        )

Sobreescribir action_confirm da control total y es testeable. Llama siempre a super() y opera en bucle sobre self para soportar acciones por lotes.

Estados

Tracking en campos de estado

state = fields.Selection([
    ('draft', 'Borrador'),
    ('in_progress', 'En curso'),
    ('to_invoice', 'Por facturar'),
    ('done', 'Cerrado'),
], default='draft', tracking=True)

tracking=True registra cada cambio en el chatter (requiere mail.thread). Así cualquier salto de estado queda auditado con autor y fecha, clave para depurar flujos automatizados.

Decisión

¿Declarativo o código?

CasoRecomendación
Aviso o actividad simplebase.automation (sin desplegar código)
Lógica con varias condicionesOverride de método en módulo
Necesitas tests de regresiónCódigo Python (TransactionCase)
El cliente lo cambiará a menudoDeclarativo, editable desde la UI

Resumen

Primero exprime la configuración nativa (servicios que crean proyectos, líneas facturables). Para la lógica extra, elige base.automation si es simple y editable, u override de método si necesitas control y tests. Añade tracking=True a los estados y vigila los bucles de disparo.

en Odoo
Website y eCommerce: extender plantillas sin romper el tema
theme.ir.ui.view, snippets y páginas dinámicas