How to change value of multiple fields onchange - odoo

I want to change the value of Ordered Qty (product_uom_qty) and prix unitaire (price_unit) when changing the Ligne Contrat. But my onchange functions only work for the Ordered Qty, although both functions are called correctly.
Here is my code :
from datetime import datetime, timedelta
from odoo import api, fields, models, _
# Contrat model
class Contrat(models.Model):
_name = 'contrat.contrat'
_rec_name = 'contrat_name'
contrat_name = fields.Char(string='Nom')
contrat_number = fields.Integer(string="Numero")
date_start = fields.Date(string='Date Debut')
date_end = fields.Date(string="Date Fin")
date_deadline = fields.Date(string="date echeance")
ligne_id = fields.One2many('contrat.lignes','ligne_ids',"mylignes")
# notebook_ids = fields.Many2one('contrat.lignes','ligne_id',string='Notebook')
client_name = fields.Many2one('res.partner',string="Client")
bons_ligne_ids = fields.One2many('sale.order.line', 'contrat_name_id', String='Contrat bons')
class ContratOrder(models.Model):
_name = 'contrat.lignes'
_rec_name = 'ligne_name'
ligne_ids = fields.Many2one('contrat.contrat',string="Contrat")
ligne_name = fields.Char(string="Nom de Ligne")
unit_price = fields.Float(string='Prix Unitaire')
article_name = fields.Many2one('product.template', string="Article")
quantity = fields.Float(string='Quantite')
# modifier les lignes des bons de commands
class bons_lignes(models.Model):
_inherit="sale.order.line"
bons_po = fields.Integer('PO')
contrat_name_id = fields.Many2one('contrat.contrat', string='Contrat')
contrat_lignes_id = fields.Many2one('contrat.lignes', string='Ligne contrat')
product_uom_qty = fields.Float('qtt', related='contrat_lignes_id.quantity')
price_unit = fields.Float(string='Prix Unitaire')
#api.onchange('contrat_lignes_id')
def onchange_conrat_lignes_id(self):
self.price_unit = self.contrat_lignes_id.unit_price
How is it possible to change both fields with one or more onchange functions.
EDIT: Odoo already has a onchange trigger on field product_uom_qty which is changing the field price_unit after calling my onchange methods. How is it possible to get my onchange functions get called later, or just forbid Odoo to call its other functions?

Just use a single onchange method to change both fields.
#api.onchange('contrat_lignes_id')
def onchange_conrat_lignes_id(self):
self.product_uom_qty = self.contrat_lignes_id.quantity
self.price_unit = self.contrat_lignes_id.unit_price

Related

How to use BS4 to .find all id css selector

I'm following this tutorial. But i got stuck here:
for container in containers:
date = container.find('td', class_ = 'date-action').get_text()
date = parser.parse(date.strip()[6:]).date()
dateli.append(date) #make date relevant to current date
description_container_1 = container.find('td', class_ = 'description TL_NPI_TransDesc')
description_container_2 = description_container_1.find('a', class_ = 'transactionTitle')
description = description_container_2.find('span', class_ = 'transTitleForEditDesc').get_text()
descli.append(description)
amount = container.find('td', class_ = ['amount positive TL_NPI_Amt', 'amount TL_NPI_Amt isDebit']).get_text()
amtli.append(float(price_str(amount)))
My problem is how to replace the ('td', class_ = 'date-action') with 'div"[id*="wtDataMov"]', since its the only way to identify the lines i want to get is by a specific part of the a big id LT_BPINetEmpresas_wt37_block_wtMainContent_CW_Contas_Empresas_wtMovimentos_block_wtMovimentosList2_ctl04_wtDataMov.
To use a CSS selector use .select(). In your case to only find the first tag use .select_one()
...
date = container.select_one('div[id*=breakoutLeft]').get_text()

Odoo onchange not working correctly

I'm inherit purchase.order.line and try change value in field. For product_qty I can change value but for price_unit I can't change value.
My custom .py file:
class PurchaseOrderLine(models.Model):
_inherit = 'purchase.order.line'
#api.onchange('product_id')
def my_fucn(self):
for rec in self:
rec.product_qty = 10 #WORKING
rec.price_unit = 1 #NOT WORKING
Maybe is problem because in original purcahase.py odoo file also have #api.onchange('product_id').
Any solution?
You can't predict which onchange method will be triggered first or last, but the original onchange method for product_id changes in purchase.order.line is setting the price_unit field, but not the product_qty field.
So it seems your method is called before the other one, because price_unit is overwritten. You can check that by debugging both methods.
What to do now? I would prefer the extension of the original method:
#api.onchange('product_id')
def the_original_method(self):
res = super(PurchaseOrderLine, self).the_original_method()
# your logic here
return res
In your case a product_qty change will trigger another onchange event. Always have in mind, that field changes can trigger onchange events and field recomputations.
Try to extend both methods:
#api.onchange('product_id')
def onchange_product_id(self):
res = super(PurchaseOrderLine, self).onchange_product_id()
# your logic here
for rec in self:
rec.product_qty = 10 # will trigger _onchange_quantity() on return
return res
#api.onchange('product_qty', 'product_uom')
def _onchange_quantity(self):
res = super(PurchaseOrderLine, self)._onchange_quantity()
# your logic here
for rec in self:
rec.price_unit = 1.0
return res

Odoo 8 override _amount_line

I'm trying to override the _amount_line function in sale.order.line model in order to add custum logic.
Here is my code:
class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'
def _amount_line(self):
tax_obj = self.env['account.tax']
cur_obj = self.env['res.currency']
res = {}
for line in self:
print line.tax_id
price = self._calc_line_base_price(line)
qty = self._calc_line_quantity(line)
print" price:{} & quantity: {}".format(price,qty)
taxes = tax_obj.compute_all(line.tax_id, price, qty,
line.product_id,
line.order_id.partner_id)
cur = line.order_id.pricelist_id.currency_id
res[line.id] = cur_obj.round(cur, taxes['total'])
return res
remise_palier = fields.Float('Remise palier (%)')
remise_total = fields.Float('Remise totale (%)')
price_subtotal = fields.Float(compute='_amount_line', string='Subtotal')
When i run Odoo, i get that error:
You have made mistake in compute_all method calling.
This method should be like this,
#api.multi
def _amount_line(self):
tax_obj = self.env['account.tax']
cur_obj = self.env['res.currency']
for line in self:
print line.tax_id
price = self._calc_line_base_price(line)
qty = self._calc_line_quantity(line)
print" price:{} & quantity: {}".format(price,qty)
taxes = line.tax_id.compute_all(price, qty, line.product_id, line.order_id.partner_id)
cur = line.order_id.pricelist_id.currency_id
line.price_subtotal = cur.round(taxes['total'])
In Odoo V8+ the compute_all call should be on the taxes itself. You don't need to call it as "class method". Following snippet should work for you:
#api.multi
# #api.depends() use it for recomputation triggers
def _amount_line(self):
for line in self:
print line.tax_id
price = self._calc_line_base_price(line)
qty = self._calc_line_quantity(line)
print" price:{} & quantity: {}".format(price,qty)
taxes = line.tax_id.compute_all(
price, qty, line.product_id, line.order_id.partner_id)
cur = line.order_id.pricelist_id.currency_id
line.price_subtotal = cur.round(taxes['total'])
Edit: You don't need to return something on new API computed field functions. Just assign the values to the computed field(s).
Edit2: There is a new API style method for currency round(), too. I've changed my snippet.

Increment integer fileds Odoo

I have added this fields under account.invoice in order to get an autoincrement number but it doesn't work.
Help me please to figure out my error
Example Code
class invoice(osv.osv):
_inherit = 'account.invoice'
def _get_increment(self, cr, uid, ids, fields, arg, context=None):
if context is None: context = {}
res = {}
if type == 'out_invoice':
ids = self.search(cr,uid,[('id','!=',False),('type','in',('out_invoice','out_refund'))])
if ids:
last_id = ids and max(ids)
print 'last_id',last_id
for invoice in self.browse(cr, uid, last_id, context):
print 'invoice', invoice
if invoice.name1:
res[invoice.id] = invoice.name1
else :
res[invoice.id] = invoice.name1 + 1
return res
_columns={
'name1':fields.function(_get_increment, type='integer', string='Name1'),
}
First of all. Your function never returns a value since type is never set.
Which means the if condition is never triggered.
At second. I'd suggest that you'd use the new Odoo API.
function fields are replaced by the compute attribute on fields and the declaration no longer takes place in the _columns dictionary.
New API
instead of importing from openerp.osv you should import the following:
from openerp import fields, models, api
The code would look like this:
from openerp import fields, models, api
class invoice(models.Model):
_inherit = 'account.invoice'
name1 = fields.Integer('Name1', compute='_get_increment')
#api.one
def _get_increment(self):
self.name1 = 1 + 1 #This value should be the value that you've calculated
the only thing you need to do in the method _get_increment is set self.name1.
In the new API self is a record. So self.id would get you the id of the record and so on.

Odoo: Access field by it's name (given as string)

I have a model, where I want to access a field, given by a string. Example:
def test(self):
field = 'name'
name = getattr(self, field)
This works fine - name is set to self.name. But then I want to access a related field:
def test2(self):
field = 'partner_id.name'
name = getattr(self, field)
That doesn't work (because 'partner_id.name' does not exist on self). Any idea how to do it right?
getattr doesn't support the dot notation, only simple attribute names. You can however create a simple function that does:
def getfield(model, field_name):
value = model
for part in field_name.split('.'):
value = getattr(value, part)
return value
You would use it like this:
def test2(self):
field = 'partner_id.name'
name = getfield(self, field)
You need to use the object that contain partner_id.name
def test2(self):
field = 'name'
object = self.pool.get('res.partner').browse(cr, uid, self.partner_id.id)#v7
#object = self.env['res.partner'].browse(self.partner_id.id)#v8
name = getattr(object, field)
I also came across another solution, inspired by the mail template system:
from openerp.tools.safe_eval import safe_eval as eval
def test2(self):
field = 'partner_id.name'
field = 'object.' + field
name = eval(field, {'object': self})