Computed field on a tree view in odoo 12 - python

I'm trying to compute a value to be displayed in a tree view, the problem is that my private function never gets executed and not setting the value for my computed field.
I've simplified the following code:
class ProjectProject(models.Model):
_inherit = "project.project"
assigned = fields.Char(string='Assigned multi', compute='_roles_assigned', store=False)
#api.multi
#api.depends('task_ids')
def _roles_assigned(self):
#do dome calculations
assigned = ' test of 1' #'0 / {total}'.format(total=total)
return assigned
as you see in the image the value is always blank

When we display computed field in tree view, it will have multiple records set. So we have to set value for each record set.
Try with following code:
#api.multi
def _roles_assigned(self):
#do dome calculations
for record in self:
assigned = ' test of 1' #'0 / {total}'.format(total=total)
record.assigned = assigned

You have to iterate over the records and assign some value to it, check the code below.
#api.multi
def _roles_assigned(self):
for rec in self:
rec.assigned = 'assign your value here'

Related

Phython - Selenium return class name inside another class

I'm trying to check / return the class name exists within another class name, here is my code so far which only returns the first value in the first span '1'.
TagListPost = driver.find_elements_by_class_name("-V_eO")
for k in TagListPost:
print(k.text)
I know k.text will only return text values, I'm not sure what I need to do to return the nested class name '_1P1TY coreSpriteHeartSmall'.
I've also tried this:
PostType = driver.find_elements_by_class_name('_1P1TY coreSpriteHeartSmall')
for j in PostType:
Print(j)
I've had no luck, it doesn't return anything because it's obviously finding the class and returning the value store in the class which is null. The code above attempts to print the class handle but 'j' is empty.
Link to HTML I wish to return values from
If you want to get class attribute values of nested elements try:
TagListPost = driver.find_elements_by_class_name("-V_eO")
for k in TagListPost:
PostType = k.find_element_by_xpath('./span[#class]')
print(PostType.get_attribute('class'))

how to make the method run once for specific record on odoo?

i'm trying to do a method with a button the add the total value of a Bill to the value of another object it working well but every time I press the button it adds the total value of the bill to the other object value, I need anything make scenes to prevent adding the bill value multiple times , here is the code
class acc_inv_prop(models.Model):
_inherit = 'account.invoice'
property_id = fields.Many2one(comodel_name="account.asset.asset", string="Property", required=False, )
def prop_up_value(self):
self.property_id.value += self.amount_total
pass
what I can do on the object account.asset.asset to check the current bill was added before and raise error and if the bill is a new one add it's value normally but also for one time only
any help will be appreciated
Besides adding something to the value of an account.asset.asset making me uncomfortable (Shouldn't you make a logic that determines the full value of the asset from the invoice?)
You would need an additional field to remember that you added the amount already:
class acc_inv_prop(models.Model):
_inherit = 'account.invoice'
property_id = fields.Many2one(comodel_name="account.asset.asset", string="Property", required=False, )
property_last_added_value = fields.Float(string='Last Value Added to Property', readonly=True, digits=0)
def prop_up_value(self):
if self.property_last_added_value != self.amount_total:
self.property_id.value -= self.property_last_added_value
self.property_id.value += self.amount_total
self.property_last_added_value = self.amount_total

Django multiwidget and validation issue

I have been subclassing multiwidget to create an HTML5 range slider synchronised with a NumberInput field using this code:
class SplitRangeNumberWidget(MultiWidget):
def __init__(self):
widgets = (
forms.NumberInput(attrs={'type':'range',
'onchange':'this.nextElementSibling.value=this.value',
'oninput':'this.nextElementSibling.value=this.value',
'step':'any',
'min':0,
'max':1}),
forms.NumberInput(attrs={'step':'any',
'onchange':'this.previousElementSibling.value=this.value',
'oninput':'this.previousElementSibling.value=this.value',})
)
super(SplitRangeNumberWidget, self).__init__(widgets)
def decompress(self, value):
if value:
return [value, value]
return [None, None]
When I instanciate it and use it in a Form such as:
class ParameterForm(forms.ModelForm):
class Meta:
model = Parameter
fields = ['name','value','min_value','max_value']
widgets = {'value':SplitRangeNumberWidget()}
, the widget works fine: changing the slider or the numberinput does change the other field. However, when doing a POST, the form does not validate and I get this error in form.errors (for 3 parameters):
[{'value': ['Enter a number.']}, {'value': ['Enter a number.']},
{'value': ['Enter a number.']}]
The widgets alone do work well and form is correctly bound. But not in a multiwidget. What am I doing wrong? I added
def value_from_datadict(self, data, files, name):
num = [widget.value_from_datadict(data, files, name + '_%s' % i)
for i, widget in enumerate(self.widgets)]
return [float(num[0]), float(num[1])]
but this still does not work.
Thanks for your help.
I found the solution: I needed to implement
def value_from_datadict(self, data, files, name):
value_list = [widget.value_from_datadict(data, files, name + '_%s' % i)
for i, widget in enumerate(self.widgets)]
try:
value = value_list[0]
except ValueError:
return None
else:
return value
To paraphrase the documentation: The default implementation of value_from_datadict() returns a list of values corresponding to each Widget. This is appropriate when using a MultiWidget with a MultiValueField, but since we want to use this widget with a TextField which takes a single value, we have overridden this method to combine the data of all the subwidgets into a value.

If I change a field value in an api.onchange method, it's not updated in the view. Why?

I have a function executing in a api.onchange('bom_line_ids'), inside this function I want to have a if statement to clear bom_line_ids if a condition is matched. I used self.bom_line_ids.product_id = False
but for some reason the field is cleared (saw this in the prints, but it's not updated in the view).
#api.onchange('bom_line_ids')
def get_excl_list(self):
list1 = []
for i in self.excl_list:
list1.append(i.id)
list2 = []
for j in self.bom_line_ids:
list2.append(j.product_id.id)
if j.product_id.id in list1:
warning_message = "Product: " + self.env['product.template'].search([('id','=',j.product_id.id)]).name + " can't be added to the BoM.\n Please select another product."
print "self.bom_line_ids.product_id", self.bom_line_ids.product_id
self.bom_line_ids.product_id = False
print "self.bom_line_ids.product_id", self.bom_line_ids.product_id
return { 'warning': {'title': 'Product error', 'message':warning_message} }
There is an issue in Odoo talking about this. Someone already made a pull request.
You can check as well this other question to solve the issue manually: One2many field on_change function can't change its own value?
Maybe you have to select on which record on bom_line_ids you want to remove the product, because self.bom_line_ids is a one2many.
Replace
self.bom_line_ids.product_id = False
by
j.product_id = False
or
self.bom_line_ids[self.bom_line_ids.index(j)].product_id = False
Yes it happens. When You try to set value for a field through onchange method, the change doesnot appear on the view. However the field value does change. I fixed this issue by setting the 'compute in the field property and the function set here is the same as in the on_change'. So the value get updated in the view as well. For eg ->
job_titles = fields.Char('Job',compute='myemply_name',store=True)
#api.onchange('new_empl')
#api.depends('new_empl')
def myemply_name(self):
self.job_titles = value

Python - Partially override method

Is it possible to partially override a method? What I mean for example I have one method and I want to update it with some modifications, but I don't want to change whole method (I couldn't figure out how to update old method by inheriting it, but not entirely changing it). So is it possible to do something like this:
class A(object):
def test(self, num):
tmp = 3
res = tmp + num
print
return res
a = A()
a.test(5)
returns 8
class B(A):
def test(self, num):
tmp = 5
a = super(B, self).test(num)
return a
b = B()
b.test(5)
returns 10
Is there a way to update only tmp value, leaving res = tmp + num, so it would use it as it is defined in A class. Or if I want to update like this, there is only way to rewrite everything in that method(because using super I only get the final value that method returns)?
As suggested I update question with method I try to only partially update it:
def _display_address(self, cr, uid, address, without_company=False, context=None):
'''
The purpose of this function is to build and return an address formatted accordingly to the
standards of the country where it belongs.
:param address: browse record of the res.partner to format
:returns: the address formatted in a display that fit its country habits (or the default ones
if not country is specified)
:rtype: string
'''
# get the information that will be injected into the display format
# get the address format
address_format = address.country_id and address.country_id.address_format or \
"%(street)s\n%(street2)s\n%(city)s %(state_code)s %(zip)s\n%(country_name)s"
args = {
'state_code': address.state_id and address.state_id.code or '',
'state_name': address.state_id and address.state_id.name or '',
'country_code': address.country_id and address.country_id.code or '',
'country_name': address.country_id and address.country_id.name or '',
'company_name': address.parent_id and address.parent_id.name or '',
}
for field in self._address_fields(cr, uid, context=context):
args[field] = getattr(address, field) or ''
if without_company:
args['company_name'] = ''
elif address.parent_id:
address_format = '%(company_name)s\n' + address_format
return address_format % args
So for this method I only need to update/change address_format and args, inserting additional values.
Since tmp is a local variable of A's test function, there is no (portable) way to access it. Either make tmp another parameter of test, and just pass in the appropriate value (possible with a suitable default if none is passed), or make it a field of A and override that field's value in B.
Edit: Seeing the actual code, and learning that you aren't allowed to change it, makes this a lot more difficult. Basically, you would have to copy-paste the superclass's code and just change the parts necessary. The good solutions all require modifying the superclass's method.

Categories

Resources