Good day!
Is there a way to add a button above the Tree View in Odoo?
I would like to run a function whenever the User Clicks the button.
If this is not possible can you help me with an alternative?
here is my code on view:
'''<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="account_payment_import_view_tree" model="ir.ui.view">
<field name="name">account.payment.import.view.tree</field>
<field name="model">account.payment.import</field>
<field name="arch" type="xml">
<tree string="Payment Imports" decoration-info="payment_id != False" decoration-danger="error_msg != False">
<field name="transaction_date"/>
<field name="facts_id"/>
<field name="paid_in_lei"/>
<field name="paid_in_euro"/>
<field name="amount"/>
<field name="account"/>
<field name="account_no"/>
<field name="document_no"/>
<field name="details_bk_statement"/>
<field name="error_msg"/>
<field name="invoice_number" invisible="1"/>
<field name="payment_id" widget="many2onebutton" invisible="1"/>
<field name="invoice_id" widget="many2onebutton" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="currency_id" invisible="1"/>
</tree>
</field>
</record>
<record id="account_payment_import_action" model="ir.actions.act_window">
<field name="name">Payment Imports</field>
<field name="res_model">account.payment.import</field>
<field name="view_mode">tree</field>
<field name="domain">[]</field>
<field name="context">{'edit': 0}</field>
</record>
<menuitem
id="account_payment_import_menu"
name="Payment Imports"
action="account_payment_import_action"
parent="account.menu_finance_receivables"
sequence="160"/>
</odoo>'''
Well, here's my attempt to get the button in the tree view. I'll try to explain you well step by step.
First we have to add the button to the tree view via qweb, inheriting the tree view from the web module.
This will make our new button appear in all tree views, which we don't want. So to avoid that we add a condition t-if='widget.modelName == "account.payment.import"' which will cause the button to be generated only for the views whose model is the one that interests us. We also add a CSS class oe_new_custom_button to be able to identify the button from the javascript.
Let's call the file that contains this qweb tree_view_button.xml and place it in your_module_name/static/src/xml.
<?xml version="1.0" encoding="UTF-8"?>
<templates>
<t t-extend="ListView.buttons">
<t t-jquery="div.o_list_buttons" t-operation="append">
<button type="button" t-if='widget.modelName == "account.payment.import"'
class="oe_new_custom_button btn btn-primary">Custom Button
</button>
</t>
</t>
</templates>
Second we must give functionality to the button, we achieve this through javascript.
Here we inherit the tree view controller, called ListController, whose its role is to render and bind all extra buttons/pager in the control panel, among other things.
Let's call the file that contains this javascript tree_view_button.js and place it in your_module_name/static/src/js.
odoo.define('your_module_name.tree_view_button', function (require){
"use strict";
var ajax = require('web.ajax');
var ListController = require('web.ListController');
ListController.include({
renderButtons: function($node) {
this._super.apply(this, arguments);
var self = this;
if (this.$buttons) {
$(this.$buttons).find('.oe_new_custom_button').on('click', function() {
//custom code
});
}
},
});
});
Finally, we add our javascript to the odoo assets and configure the manifest to take all our changes.
Let's call the file that contains the assets assets.xml and place it in your_module_name/views.
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<template id="assets_backend" name="your_module_name_assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/your_module_name/static/src/js/tree_view_button.js"></script>
</xpath>
</template>
</data>
</odoo>
And that's what it should look like manifest.py.
{
'data': [
[ ... ]
'views/assets.xml', # <- important
],
"qweb": ['static/src/xml/*.xml'], # <- important
}
We already have everything, but now, what can be done from javascript?
A little bit of everything, but the most important thing would be the following.
Call a model method
odoo.define('your_module_name.tree_view_button', function (require){
"use strict";
var ajax = require('web.ajax');
var ListController = require('web.ListController');
var rpc = require('web.rpc')
ListController.include({
renderButtons: function($node) {
this._super.apply(this, arguments);
var self = this;
if (this.$buttons) {
$(this.$buttons).find('.oe_new_custom_button').on('click', function() {
rpc.query({
model: 'account.payment.import',
method: 'some_method',
args: [],
}).then(function(res){
// console.log(res)
// self.reload();
})
});
}
},
});
});
The first argument of args is a list of the ids you want to appear in the self variable of the some_method.
Call an action
odoo.define('your_module_name.tree_view_button', function (require){
"use strict";
var ajax = require('web.ajax');
var ListController = require('web.ListController');
ListController.include({
renderButtons: function($node) {
this._super.apply(this, arguments);
var self = this;
if (this.$buttons) {
$(this.$buttons).find('.oe_new_custom_button').on('click', function() {
self.do_action('model_name.action_id', {
additional_context: {},
});
});
}
},
});
});
additional_context should be, for example,
{
'active_id': 1,
}
The end
That's all, I hope it works for you. I attach an image of what the button would look like.
Related
I have one field was the M2o and that opposite O2m. I try to display the O2m field in the M2o class just like that and display all the O2m field in the tree view. But I need to hide the one column is based on the ir.config_parameter
from odoo import models, fields, api
class AbcXyz(models.Model):
_name='abc.xyz'
b_ids=fields.One2many('xyz.abc','a_id',string="Xyz")
#api.model
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
res = super(AbcXyz, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
if view_type=='form' and self.b_ids:
for line in self.b_ids:
is_applying_view = eval(self.env['ir.config_parameter'].sudo().get_param('test_module.is_applying_k_qty'))
doc = etree.XML(res['arch'])
if is_applying_view:
for node in doc.xpath("//field[#name='line.k_qty']"):
node.set('invisible', '0')
else:
for node in doc.xpath("//field[#name='line.cartoon_qty']"):
node.set('invisible', '1')
return res
class XyzAbc(models.Model)
_name='xyz.abc'
#api.multi
def get_default_k_qty_visible(self):
return eval(self.env['ir.config_parameter'].sudo().get_param('test_module.is_applying_k_qty'))
a_id=fields.Many2one('abc.xyz',string="ABC")
<!---other fields--->
k_qty=fields.Integer(string="Cartoon Qty", default=0)
is_k_qty_visible = fields.Boolean(string="Is K Qty Visible", compute=get_default_cartoon_qty_visible, store=True)
based is_k_qty_visible I try to hide the k_qty column.
<record id="abc_form_view" model="ir.ui.view">
<field name="name">abc.form.view</field>
<field name="model">abc.xyz</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="ABC Process">
<notebook>
<page string="K Qty">
<field name="b_ids" nolabel='1' mode="tree">
<tree>
<field name="k_qty" attrs="{'invisible':[('is_k_qty_visible','!=',True)]}" />
</tree>
</field>
</page>
</notebook>
</form>
</field>
<record>
But it not working for me.
This is not the answer of this question. I have share some information.
This code is used to hide fields in one2many(tree) in odoo11
<
field name="my_field" attrs="{'column_invisible': [('parent.field_name','=',False)]}" />
this type of code only works gives 'parent' in condition
I think this will type of code will work in odoo12 too.
I want to add new attributes in product tree view but an error happened when I started my server and updated my addons look like :
ParseError: "Erreur lors de la validation de la contrainte
Mod\xe8le non trouv\xe9 : product.template
Contexte de l'erreur :
Vue `productTree`
[view_id: 752, xml_id: n/a, model: product.template, parent_id: 308]
None" while parsing /opt/odoo/odoo-10.0/addons/test_tuto/views/views.xml:3, near
<record id="view_product_tree_inherit" model="ir.ui.view">
<field name="inherit_id" ref="product.product_template_tree_view"/>
<field name="name">productTree</field>
<field name="model">product.template</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<xpath expr="/tree/field[#name='categ_id']" position="after">
<field name="calories"/>
<field name="servingsize"/>
<field name="lastupdated"/>
</xpath>
</field>
</record>
Here is my view source code,
<record id="view_product_tree_inherit" model="ir.ui.view">
<field name="inherit_id" ref="product.product_template_tree_view"/>
<field name="name">productTree</field>
<field name="model">product.template</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<xpath expr="/tree/field[#name='categ_id']" position="after">
<field name="calories"/>
<field name="servingsize"/>
<field name="lastupdated"/>
</xpath>
</field>
</record>
And here is the python code I added 3 fields in my class inherit from product template class.
from odoo import models, fields, api
class test_tuto(models.Model):
_inhirit = 'product.template'
calories = fields.Integer("Calories")
servingsize = fields.Float("Serving size")
lastupdated = fields.Datetime('Last Updated')
as you request here you are my manifest.py file
I write my xml code in views.xml file
# -*- coding: utf-8 -*-
{
'name': "Test_tuto",
'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': "http://www.yourcompany.com",
# Categories can be used to filter modules in modules listing
# Check https://github.com/odoo/odoo/blob/10.0/odoo/addons/base/module/module_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/views.xml',
'views/templates.xml',
],
# only loaded in demonstration mode
'demo': [
'demo/demo.xml',
],
}
Please try changing your "xpath" like this
add 'product' in depends
'depends': ['base','product'],
<xpath expr="//tree/field[#name='categ_id']" position="after">
<field name="calories"/>
<field name="servingsize"/>
<field name="lastupdated"/>
</xpath>
class InvoiceWizard(models.TransientModel):
_name = "pos.order.invoice.wizard"
date_order = fields.Datetime(string='Date Order', readonly=True)
partner_id = fields.Many2one('res.partner', string='Partner')
#api.multi
def to_invoice(self):
pos_order = self.env['pos.order'].search([('id','=',self._context.get('active_id'))])
pos_order.create_invoice()
<record id="pos_order_invoice_done" model="ir.ui.view">
<field name="name">pos.order.wizard.invoice</field>
<field name="model">pos.order.invoice.wizard</field>
<field name="arch" type="xml">
<form string="To Invoice">
<group>
<field name="partner_id"/>
<field name="date_order"/>
</group>
<footer>
<button name="to_invoice"
string="Finished" type="object"
class="btn-primary"/>
<button string="Cancel"
class="btn-default"
special="cancel" />
</footer>
</form>
</field>
</record>
My goal is to create invoice from pos order with this 2 fields that manuale i will select in wizard. what do i'm missing here? i need to transfer data from those fields to create_invoice() method.
partner_id is required in invoice object, so you must fill the fields in create method like:
#api.multi
def to_invoice(self):
invoice_obj =self.env['account.invoice']
values = {'partner_id' : self.partner_id,
'date_invoice' : self.date_order
}
invoice_obj.create(values)
note : make sure all fields required is filled.
I have these 2 buttons in form view:
<button name="%(action_view_task_make_situation)d" string="Create work situation" type="action" states="open" context="{'type': 'situation'}"/>
<button name="%(action_make_general_final_count)d" string="Create Final General Count" type="action" states="done" context="{'type': 'final_count'}"/>
with these actions:
<record id="action_view_task_make_situation" model="ir.actions.act_window">
<field name="name">Make Situation</field>
<field name="res_model">task.make.situation</field>
<field name="type">ir.actions.act_window</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="context">{'type':True}</field>
</record>
<record id="action_make_general_final_count" model="ir.actions.act_window">
<field name="name">Make General Final Count</field>
<field name="res_model">task.make.situation</field>
<field name="type">ir.actions.act_window</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="context">{'type':False}</field>
</record>
now I have task.make.situation model:
class TaskMakeSituation(models.TransientModel):
_name = "task.make.situation"
type = fields.Char(compute = "compute_type", string="Type", readonly= True)
#api.multi
def compute_type(self):
if self._context.get('type', True):
return "situation"
else:
return "final_count"
But when I click one of the buttons the wizard appears with an empty type field.
Compute method have to "write" their values directly into the records:
#api.multi
def compute_type(self):
context_type = self._context.get('type', True)
for record in self:
if context_type:
record.type = "situation"
else:
record.type = "final_count"
Aside from this, your solution should simply use default values for field type. First change your field to a normal char field:
type = fields.Char(string="Type", readonly=True)
Little hint: the parameter string isn't necessary in this example, because newer Odoo versions will use the field name to generate the labels (string becomes the field label) for example: name will get Name or partner_id will get Partner (_id will be dropped).
Now change the button context, use default_type:
<button name="%(action_view_task_make_situation)d"
string="Create work situation" type="action" states="open"
context="{'default_type': 'situation'}"/>
<button name="%(action_make_general_final_count)d"
string="Create Final General Count" type="action" states="done"
context="{'default_type': 'final_count'}"/>
The prefix default_ in combination with a field name, will be used in later default extraction for the creation of a record.
Just try adding "default_" before type in the context, like this:
context="{'default_type': False}"
and only use boolean because you validate boolean in compute_type, make this in the views too.
Model
class ItemStocks(models.Model):
_name = 'item.stocks'
item_url = fields.Char('View Item')
ItemStocks()
View
<record id="view_item_stocks_form" model="ir.ui.view">
<field name="name">item.stocks.form</field>
<field name="model">item.stocks</field>
<field name="arch" type="xml">
<form string="Item Stocks">
...
<page string="Live Site">
<form string="Embedded Webpage" version="7.0" edit="false">
<iframe marginheight="0" marginwidth="0" frameborder="0"
src="{Variable for this.item_url}" width="100%" height="1000"/>
</form>
</page>
...
</form>
</field>
</record>
How can I replace {Variable for this.item_url} with a valid expression for the field in model? Is there a better way to do like this? What would you prefer to solve the requirement of showing dynamically an embedded webpage?
Context: Odoo 8, New Api, ir.ui.view
**`Image Url wise Set Dynamic Iframe In Odoo`**
# v11 odoo community
you need to create fields like this :
image_url = fields.Char('Image Url')
img_attach = fields.Html('Image Html')
# set image_url in iframe
#api.onchange('image_url')
def onchange_image_url(self):
if self.image_url:
self.img_attach = '<img id="img" src="%s"/>' % self.image_url
# set image_url in form view
<field name="image_url" />
# after added script
<script>
if(document.getElementById("img")){
var value= document.getElementById("img").src;
document.getElementById("custom_src").src=value;
}
</script>
# also set iframe in form view
<iframe id="custom_src" src="" width="200" height="200" />
#output
show the image : https://i.stack.imgur.com/0x7et.png