Personalización de la Lógica de Negocio y Wizards
Las acciones de negocio se implementan en métodos del servidor. Una acción del servidor (ir.actions.server) ejecuta operaciones; una automatización determina cuándo dispararlas. Un cron (ir.cron) ejecuta tareas periódicas. Son mecanismos distintos.
1. Decoradores #
| Decorador | Función |
|---|---|
@api.depends | Declara dependencias de un campo calculado. |
@api.onchange | Ayuda al usuario en formularios; se ejecuta en el servidor sobre un pseudorregistro, por petición del cliente. |
@api.constrains | Valida reglas de negocio al crear o modificar los campos declarados. |
@api.model | Recibe self, aunque sus registros concretos no sean relevantes. No equivale a staticmethod. |
@api.model_create_multi | Recibe una lista de valores para creación en lote. |
2. Asistente de préstamo #
Crea wizards/__init__.py con from . import loan_wizard e importa wizards en el inicializador raíz. El asistente utiliza el socio y la fecha introducidos y crea préstamos reales:
Fichero wizards/loan_wizard.py:
1from odoo import fields, models, _ 2from odoo.exceptions import UserError 3 4 5class LibraryLoanWizard(models.TransientModel): 6 _name = 'library.loan.wizard' 7 _description = 'Quick loan wizard' 8 9 partner_id = fields.Many2one('res.partner', required=True) 10 return_date = fields.Date(required=True) 11 12 def action_apply(self): 13 self.ensure_one() 14 if self.env.context.get('active_model') != 'library.book': 15 raise UserError(_('Select books from the library.')) 16 books = self.env['library.book'].browse( 17 self.env.context.get('active_ids', []), 18 ).exists() 19 if not books: 20 raise UserError(_('Select at least one book.')) 21 for book in books: 22 if not book.is_available: 23 raise UserError(_('Book %s is not available.') % book.name) 24 self.env['library.loan'].create({ 25 'partner_id': self.partner_id.id, 26 'book_id': book.id, 27 'return_date': self.return_date, 28 }) 29 book.write({'state': 'borrowed'}) 30 return {'type': 'ir.actions.act_window_close'}
El usuario debe disponer de permiso para modificar libros y crear préstamos. Este ejemplo reserva el asistente al responsable, sin elevar privilegios.
Fichero views/loan_wizard.xml:
1<odoo> 2 <record id="view_library_loan_wizard_form" model="ir.ui.view"> 3 <field name="name">library.loan.wizard.form</field> 4 <field name="model">library.loan.wizard</field> 5 <field name="arch" type="xml"> 6 <form string="Quick loan"> 7 <group><field name="partner_id"/><field name="return_date"/></group> 8 <footer> 9 <button name="action_apply" type="object" string="Confirm" class="btn-primary"/> 10 <button string="Cancel" special="cancel"/> 11 </footer> 12 </form> 13 </field> 14 </record> 15 <record id="action_library_loan_wizard" model="ir.actions.act_window"> 16 <field name="name">Quick loan</field> 17 <field name="res_model">library.loan.wizard</field> 18 <field name="view_mode">form</field> 19 <field name="target">new</field> 20 <field name="binding_model_id" ref="model_library_book"/> 21 <field name="binding_view_types">list,form</field> 22 <field name="group_ids" eval="[(4, ref('group_library_manager'))]"/> 23 </record> 24</odoo>
Añade views/loan_wizard.xml al manifiesto y esta fila al CSV de accesos existente:
1access_library_loan_wizard,Quick loan wizard,library.loan.wizard,group_library_manager,crud,
Actualiza el módulo. Selecciona libros disponibles y abre Acción → Quick loan. TransientModel guarda registros temporales sujetos a limpieza periódica; la acción de cierre no elimina ni revierte los préstamos creados. No uses onchange como única validación de datos recibidos por API o importación.