I have this model and method in odoo
class stock_transfer_details_items(models.TransientModel):
_inherit = 'stock.transfer_details_items'
lot_id = fields.Many2one('stock.production.lot', 'Lot/Serial Number')
q_auth = fields.Boolean(related='lot_id.q_auth', string="Quality Auth.")
needs_auth = fields.Boolean(related='product_id.needs_quality_auth')
#api.onchange("needs_auth")
def _onchange_NQA_domain(self):
domain = {'domain': {'lot_id': [('product_id', '=', rec.product_id.id)]}}
if rec.needs_auth:
domain = {'domain': {'lot_id': [('q_auth', '!=', False), ('product_id', '=', rec.product_id.id)]}}
return domain
All this code is working ok. My problem is that I need to apply this domain when the wizard opens. #api.depends means that the value changes depending on the value of needs_auth but it actually don't work if I don't interact with the checkbox of needs_auth. I want to apply the domain when the view is open and not interact with the needs_auth field, because the user will not be allow to interact.
The solution for your problem is to use fields_view_get.
It was already mentioned before here : https://stackoverflow.com/a/54825093/9796551
#api.model
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
res = super(stock_transfer_details_items,self).fields_view_get(view_id=view_id,
view_type=view_type,
toolbar=toolbar,
submenu=submenu)
if view_type == 'form':
domain = "["
# Your condition...
domain += "]"
res['fields']['lot_id']['domain'] = domain
return res
Related
I am trying to update the domain filter for a many2one field from button click, the function runs, but I do not see any change on the UI, here is the class I am using:
class ProjectTask(models.Model):
_inherit = 'project.task'
my_users = fields.Many2one('res.users', string="My Users", readonly=False)
def filterUsers(self):
domain = ...mydomainTogetUsers
filtered_users = self.env['res.users'].search(domain).mapped('id')
return {'domain': {'my_users ': [('id', 'in', filtered_users)]}}
I have the following object button on view to execute function:
<button name="filterUsers" string="Filter Users" type="object" class="oe_highlight"/>
Function gets executed but many2one field remains the same.
Is there any way to update the field list after calling the function?
try to change in your search method like following :
def filterUsers(self):
domain = ...mydomainTogetUsers
filtered_users = self.env['res.users'].search(my_users).mapped('id')
#or this line:
filtered_users = self.env['res.users'].mapped(my_users).mapped('id')
return {'domain': {'my_users ': [('id', 'in', filtered_users)]}}
I want to change the retrieved set of values of a many2many field according to a many2one field onchange function, it worked well with another many2one field, but doesn't seem to filter the outcome on a many2many field
my code is as follows
class CustomPurchase(models.Model):
_name = 'custom.purchase'
_description = 'Purchase Record'
supplier_id = fields.Many2one('custom.supplier', string='Supplier', required=True)
product_ids = fields.Many2many('custom.supply.line', string='Purchase Lines', required=True)
#api.onchange('supplier_id')
def onchange_supplier(self):
selected_lines = []
if self.supplier_id:
for rec in self:
selected_lines = rec.env['custom.supply.line'].search([('supplier_id', '=', rec.supplier_id.id)])
domain = {'product_ids': [('id', '=', selected_lines.id)]}
return {'domain': domain, 'value': {'selected_lines': []}}
Expected behavior is to have just the items related to the supplier_id many2one field
Produced behavior is all the items are retrieved
Edit:
I've noticed that i when i remove widget="section_and_note_one2many" the domain works perfectly, yet the tree view can't be edited within the same form, even with editable="bottom"
You can add check using supplier field directly inside domain.
Code:
#api.onchange('supplier_id')
def onchange_supplier(self):
domain = {'product_ids': []}
for rec in self:
if rec.supplier_id:
domain = {'product_ids': [('supplier_id', '=', rec.supplier_id.id)]}
return {'domain': domain}
UPDATE:
Try to implement this as same as in /addons/mrp/models/mrp_bom.py on attribute_value_ids. [Version:12]
Imagine you want to fill a field in the sale.order form with a default value, the same text will be used for each company that is being used in Odoo. Sometimes the usual way to proceed is to use a common field in the res.company model. Other option is to add a field that is filled with some other content in the res.partner form, when the customer is selected.
But the problem I found is: if I want to get the translations for that field, which are already in the original one, I would have to do it manually, inheriting the create method of ir.translation. When the field is copied to the sale.order form a record for the current used language is created, so I took advantage of it to create the rest of records. Is there a better way to do this?
Also, I would like to add that after saving the record I press the world icon to translate the text again, new translations are created with the current text. So I would need to translate everything again on every sale.order record.
I did this in the ir.translation model for a simple text field in order to create the translations of the rest of languages. The field field_to_translate is translatable on both sides:
#api.model
def create(self, vals):
record = super(IrTranslation, self).create(vals)
name = vals.get('name', False) # name of the field to translate
lang = vals.get('lang', False) # creating record for this language
if 'context' in dir(self.env):
cur_lang = self.env.context.get('lang', False) # current used language
if name == 'sale.order,field_to_translate' and lang == cur_lang:
langs = self.env['ir.translation']._get_languages()
langs = [l[0] for l in langs if l[0] != cur_lang] # installed languages
for l in langs:
if self.env.user.company_id.field_to_translate:
t = self.env['ir.translation'].search([
('lang', '=', l),
('type', '=', 'model'),
('name', '=', 'res.company,field_to_translate')
])
if t:
self.env['ir.translation'].create({
'lang': l,
'type': 'model',
'name': 'sale.order,field_to_translate',
'res_id': record.res_id,
'src': record.src,
'value': t.value,
'state': 'translated',
})
Ah, and I want to do this because I want to print them on different reports. The language of these report will depend on the customer lang field.
In short, how can I set a translatable field in res.company as a default value in other field in the sale.order model? The translations to other languages should be copied as well. My above proposal is kind of cumbersome
Well, finally I have created the translations in the create method of sale.order. I have used a customized translate_fields method of the ir.translation model in order to create the translations automatically and then I update all their values manually with the correct language translation.
On the other hand I found this class in the l10n_multilang module that can be useful for other people that may find the same problem:
class AccountChartTemplate(models.Model):
_inherit = 'account.chart.template'
#api.multi
def process_translations(self, langs, in_field, in_ids, out_ids):
"""
This method copies translations values of templates into new Accounts/Taxes/Journals for languages selected
:param langs: List of languages to load for new records
:param in_field: Name of the translatable field of source templates
:param in_ids: Recordset of ids of source object
:param out_ids: Recordset of ids of destination object
:return: True
"""
xlat_obj = self.env['ir.translation']
#find the source from Account Template
for lang in langs:
#find the value from Translation
value = xlat_obj._get_ids(in_ids._name + ',' + in_field, 'model', lang, in_ids.ids)
counter = 0
for element in in_ids.with_context(lang=None):
if value[element.id]:
#copy Translation from Source to Destination object
xlat_obj._set_ids(
out_ids._name + ',' + in_field,
'model',
lang,
out_ids[counter].ids,
value[element.id],
element[in_field]
)
else:
_logger.info('Language: %s. Translation from template: there is no translation available for %s!' % (lang, element[in_field]))
counter += 1
return True
#api.multi
def process_coa_translations(self):
installed_langs = dict(self.env['res.lang'].get_installed())
company_obj = self.env['res.company']
for chart_template_id in self:
langs = []
if chart_template_id.spoken_languages:
for lang in chart_template_id.spoken_languages.split(';'):
if lang not in installed_langs:
# the language is not installed, so we don't need to load its translations
continue
else:
langs.append(lang)
if langs:
company_ids = company_obj.search([('chart_template_id', '=', chart_template_id.id)])
for company in company_ids:
# write account.account translations in the real COA
chart_template_id._process_accounts_translations(company.id, langs, 'name')
# copy account.tax name translations
chart_template_id._process_taxes_translations(company.id, langs, 'name')
# copy account.tax description translations
chart_template_id._process_taxes_translations(company.id, langs, 'description')
# copy account.fiscal.position translations
chart_template_id._process_fiscal_pos_translations(company.id, langs, 'name')
return True
#api.multi
def _process_accounts_translations(self, company_id, langs, field):
in_ids, out_ids = self._get_template_from_model(company_id, 'account.account')
return self.process_translations(langs, field, in_ids, out_ids)
#api.multi
def _process_taxes_translations(self, company_id, langs, field):
in_ids, out_ids = self._get_template_from_model(company_id, 'account.tax')
return self.process_translations(langs, field, in_ids, out_ids)
#api.multi
def _process_fiscal_pos_translations(self, company_id, langs, field):
in_ids, out_ids = self._get_template_from_model(company_id, 'account.fiscal.position')
return self.process_translations(langs, field, in_ids, out_ids)
def _get_template_from_model(self, company_id, model):
out_data = self.env['ir.model.data'].search([('model', '=', model), ('name', '=like', str(company_id)+'\_%')])
out_ids = self.env[model].search([('id', 'in', out_data.mapped('res_id'))], order='id')
in_xml_id_names = [xml_id.partition(str(company_id) + '_')[-1] for xml_id in out_data.mapped('name')]
in_xml_ids = self.env['ir.model.data'].search([('model', '=', model+'.template'), ('name', 'in', in_xml_id_names)])
in_ids = self.env[model+'.template'].search([('id', 'in', in_xml_ids.mapped('res_id'))], order='id')
return (in_ids, out_ids)
I want to hide the create button based on the field "type" of model res.partner, by passing in the active_id from context to fields_view_get.
However, i am not able to access any fields, BESIDES the "id" field. I use logger to log the output/ value of the fields
My code:
class sale_order(models.Model):
_description = 'fields view get'
_inherit = "sale.order"
#api.model
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
_logger = logging.getLogger(__name__)
res = super(sale_order, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
active_id = self.env.context.get('active_id', False)
customer = self.env['res.partner'].browse(active_id)
_logger.info('sale__customer.id: %d', customer.id)
_logger.info('sale__customer.name : %d', customer.name)
#I am getting output from the first log, but not the second
doc = etree.XML(res['arch'])
if view_type == 'tree':
for node_form in doc.xpath("//tree"):
node_form.set("create", 'false')
res['arch'] = etree.tostring(doc)
return res
sale_order()
I am getting output from the first log but not the second.
and I can see that customer.name is false but it is actually not.
How can I access the fields in the customer object?
Here's my class:
employee_ids = fields.Many2many('hr.employee', string="Empls")
status = fields.Selection([
('draft', 'Draft'),
('done', 'Done'),
])
then in fields_view_get method i want to iterate through employee_ids and make list of each employee.
def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
if context is None:
context = {}
res = super(help_desk, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar,submenu=False)
#here i want to iterate throught employee_ids and make list of each employee
for f in res['fields']:
if f == 'status':
res['fields'][f]['selection'] = #put list here
return res
how can i do it? thanks
I am supposing help_desk model have 3 fields Selection,Many2one and Many2many:
status = fields.Selection([
('draft', 'Draft'),
('done', 'Done'),
])
partner_id = fields.Many2one(comodel_name='res.partner', string='Partner')
employee_ids = fields.Many2many('hr.employee', string="Empls")
Now if you want to apply some logic so go through the below mention lines.
Well method like fields_get ,fields_view_get help us in improving UI experience by applying the filter/domain on fly.
so the code is here:
#api.model
def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False):
res = super(help_desk, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu)
PartnerObj= self.env['res.partner']
domain = [('phone','!=',False)]# put your domain or just place blank list
partners = PartnerObj.search(domain)
if partners
for field in res['fields']:
# if field == 'partner_id':
# res['fields'][field]['domain'] = [('id', 'in', partners.ids)]
elif field == 'employee_ids':
res['fields'][field]['domain'] = [('id', 'in', partners.ids)]
elif field=='status':
# Appending the partners in status doesn't making any sense but as per your words "put list here"
res['fields'][field]['selection'] = partners and [(partner.id, partner.name) for partner in partners] or [('', '')]
return res
here i have put the domain on Many2one and Many2many and add some dynamic list based on domain inside the Selection field.
you can also refer account/models/chart_template.py.