12. Desarrollando con Odoo (7). Herencia prototípica. Separar vistas. Widget many2many. Pasar información a un formulario "hijo": Context, active_id, origin, default_field
1. Problema con las relaciones many2many
La herencia prototípica es la herencia tradicional donde aparece una nueva tabla y las vistas no nos valen. Solamente se utiliza en Odoo para el caso que el modelo nuevo queramos desligarlo del todo del modelo padre. Normalmente utilizaremos aquella que solo utilizamos :_ inherit="padre" sin utilizar el _name o dejando a _name="padre")
Como vimos, para la herencia prototípica se utiliza (_name="hijo" y _inherit="padre")
Pero hay que tener cuidado pues los campos del padre de tipo Many2many no se pueden copiar pues la tabla puente que une las dos tablas de la relación tiene que ser nueva pues ahora utilizamos la tabla hijo en vez de la padre!!
Como es una tabla nueva, se tendrá que añadir al fichero de permisos "ir.model.access.csv"
2. Separar vistas, menús y modelos
Si creamos varios ficheros de vistas se debe:
- Añadir la información entre las etiquetas <odoo> y <data>
- Copiar las vistas tree y form , actions para un mismo modelo en un mismo fichero.
- Todos los menús sem colocaran en un mismo fichero llamado menu.xml
- Se añade al elemento "data" del fichero __manifest__.py, pero el orden a incluir es primero "menu.xml", y luego por orden que aparecen en el menú preferiblemente
{ 'name': "ximoapp01", 'summary': """ Short (1 phrase/line) summary of the module's purpose, used as subtitle on modules listing or apps.openerp.com""", 'description': """ Long description of module's purpose """, 'author': "My Company", 'website': "https://www.yourcompany.com", # Categories can be used to filter modules in modules listing # Check https://github.com/odoo/odoo/blob/16.0/odoo/addons/base/data/ir_module_category_data.xml # for the full list 'category': 'Uncategorized', 'version': '0.1', # any module necessary for this one to work correctly 'depends': ['base'], # always loaded 'data': [ 'security/ir.model.access.csv', 'views/project.xml', 'views/history.xml', 'views/task.xml', 'views/sprint.xml', 'views/technology.xml', 'views/bug.xml', 'views/improvement.xml', 'views/developer.xml',
'views/views.xml',
'views/templates.xml','views/menu.xml',], # only loaded in demonstration mode 'demo': [ 'demo/demo.xml', ], }
<odoo> <data> <!-- 1.1 TREE explicit list view definition --> <record model="ir.ui.view" id="ximoapp01.task_list"> <field name="name">ximoapp01 task list</field> <field name="model">ximoapp01.task</field> <field name="arch" type="xml"> <tree> <field name="name"/> <field name="description"/> <field name="code"/> <field name="start_date"/> <field name="duration"/> <field name="end_date"/> <field name="is_paused"/> <field name="sprint"/> <field name="technologies"/> <field name="history"/> <field name="developers"/> </tree> </field> </record> <!-- 1.2 FORM explicit list view definition --> <record model="ir.ui.view" id="ximoapp01.task_form"> <field name="name">ximoapp01 task form</field> <field name="model">ximoapp01.task</field> <field name="arch" type="xml"> <form> <group> <field name="name"/> <field name="description"/> <field name="definition_date"/> <field name="code"/> <field name="start_date"/> <field name="duration"/> <field name="end_date"/> <field name="is_paused"/> <field name="sprint"/> <field name="technologies"/> <field name="history"/> <field name= "developers" domain="[('is_dev','=',True)]" context="{'form_view_ref':'ximoapp01.developer_form'}"> </field> </group> </form> </field> </record> <!-- 2. actions opening views on models --> <record model="ir.actions.act_window" id="ximoapp01.action_task_window"> <field name="name">ximoapp01 task window</field> <field name="res_model">ximoapp01.task</field> <field name="view_mode">tree,form</field> </record> <!-- 3. menu categories --> <menuitem name="Tasks" id="ximoapp01.menu_2_task_list" parent="ximoapp01.menu_2" action="ximoapp01.action_task_window"/> </data> </odoo>
<odoo> <data> <!-- Top menu item --> <menuitem name="ximoapp01" id="ximoapp01.menu_root"/> <!-- menu categories --> <menuitem name="Projects & Histories" id="ximoapp01.menu_1" parent="ximoapp01.menu_root"/> <menuitem name="Tasks & Sprints" id="ximoapp01.menu_2" parent="ximoapp01.menu_root"/> <menuitem name="Human resources" id="ximoapp01.menu_3" parent="ximoapp01.menu_root"/> <!-- <menuitem name="Menu 2" id="ximoapp01.menu_2" parent="ximoapp01.menu_root"/> --> <!-- actions --> <menuitem name="Projects" id="ximoapp01.menu_1_project_list" parent="ximoapp01.menu_1" action="ximoapp01.action_project_window"/> <menuitem name="Histories" id="ximoapp01.menu_1_history_list" parent="ximoapp01.menu_1" action="ximoapp01.action_history_window"/> <menuitem name="Tasks" id="ximoapp01.menu_2_task_list" parent="ximoapp01.menu_2" action="ximoapp01.action_task_window"/> <menuitem name="Sprints" id="ximoapp01.menu_2_sprint_list" parent="ximoapp01.menu_2" action="ximoapp01.action_sprint_window"/> <menuitem name="Technologies" id="ximoapp01.menu_2_technology_list" parent="ximoapp01.menu_2" action="ximoapp01.action_technology_window"/> <menuitem name="Developers" id="ximoapp01.menu_3_developer_list" parent="ximoapp01.menu_3" action="ximoapp01.action_developer_window"/> <!-- <menuitem name="Server to list" id="ximoapp01" parent="ximoapp01.menu_2" action="ximoapp01.action_server"/> </data> </odoo>
3. Widget many2many
Veamos el widget many2many aplicado al campo developer de la vista task
<field name= "developers" domain="[('is_dev','=',True)]" context="{'form_view_ref':'ximoapp01.developer_form'}" widget= "many2many_tags"> </field>
Y aparece un widget parecido a este
4. Pasar información al formulario
Ya vimos que el context permite pasar información. Si vamos a un campo many2many le indicamos el context que coja el valor de un campo al abrir su formulario correspondiente. Veamos los pasos a realizar
1. Para la vista de developers.xml, en el campo tasks, creamos una variable llamada "current_developer"(podria ser otro nombre cualquiera), que le asignamos el valor "active_id" que es el valor del id de la tabla del form del que partimos (o sea el id del developer).
<field name="tasks" context="{'current_developer':active_id}"> </field>
2. En el modelo de task , creamos una función antes de la definición del campo developers que se llame _get_default_developer, que obtenga el developer y retorne su id.
3. A continuación en dicho modelo, le decimos que el campo developer tiene un default que apunta a dicha función
def _get_default_developer(self): developer= self.browse(self._context.get('current_developer')) if developer: return [developer.id] else: return [] developers = fields.Many2many(comodel_name="res.partner",
relation="partner_task",
column1="task_id",
column2="partner_id",
default=_get_default_developer,
help="Desarrolladores")
5. Errores producidos
5.1 Propiedad origin para ids no disponibles
Dentro de proyecto ir a historia y crear una tarea y dice puede asignar el proyecto, pero no se produce dicho error al ir a historia directamente del menu.
Es decir "Proyecto-Historia-Nueva Tarea" falla pero "Historia-Nueva Tarea" no falla
El problema viene de que dentro del modelo task tenemos esta funcion que utiliza el campo "record.history.project.id" que puede que no contenga un valor aún y por tanto el project.id y todavía no está disponible por no estar almacenado en BD
@api.depends('history') def _get_sprint(self): for record in self: sprints = self.env['ximoapp01.sprint'].search([('project.id', '=', record.history.project.id)]) found = False for sprint in sprints: if not found: if isinstance(sprint.end_date, datetime.datetime): if sprint.end_date > datetime.datetime.now(): record.sprint = sprint.id found = True if not found: record.sprint = False
Para solucionar el problema si "record.history.project.id" no está ya generado, este valor se obtendrá de la propiedad "origin" --> "record.history.project.id.origin"
@api.depends('history') def _get_sprint(self): for record in self: #sprints = self.env['ximoapp01.sprint'].search([('project.id', '=', record.history.project.id)]) if isinstance(record.history.project.id, models.NewId): id_project= int (record.history.id.origin) else: id_project= record.history.id sprints = self.env['ximoapp01.sprint'].search([('project.id', '=', id_project)]) found = False for sprint in sprints: if not found: if isinstance(sprint.end_date, datetime.datetime): if sprint.end_date > datetime.datetime.now(): record.sprint = sprint.id found = True if not found: record.sprint = False
5.2 Widget many2many creación de res.partner con is_dev=Fase
En el modelo task, al crear un desarrollador con el widget many2many, se crea con is_dev=False, con lo que ya no se puede buscar en el form de desarroladores. Para ello en el campo developer de la vista debemos añadir al context 'default_is_dev' : True
<field name= "developers" domain="[('is_dev','=',True)]" context="{'form_view_ref':'ximoapp01.developer_form' , 'default_is_dev':True }" widget= "many2many_tags"> </field>
Comentarios
Publicar un comentario