Odoo 8 override _amount_line - odoo

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.

Related

How to add another discount to subtotal in Quotation Order?

There is a subtotal (price_subtotal) field in Quotation Order Line.
I have added a new field extra_discount.
I have tried this code but to no avail.
#api.depends('product_uom_qty', 'price_unit', 'extra_discount')
def compute_all(self):
for record in self:
record.price_subtotal = (record.product_uom_qty * record.price_unit) - record.extra_discount
It does nothing to the subtotal.
So, how do I make this happen?
I would try to override the computation method behind the field sale.order.line.price_subtotal.
But i'm not sure if api.depends() extensions (adding one more recomputation trigger field) are working as expected.
But it should look something like that:
class SaleOrderLine(models.Model):
_inherit = "sale.order.line"
extra_discount = fields.Float()
#api.depends('product_uom_qty', 'discount', 'price_unit',
'tax_id', 'extra_discount')
def _compute_amount(self):
"""
Compute the amounts of the SO line.
Fully overridden to add field extra_discount to the
formula and triggers.
"""
for line in self:
price = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
# new: substract extra_discount
price -= line.extra_discount
taxes = line.tax_id.compute_all(price, line.order_id.currency_id, line.product_uom_qty, product=line.product_id, partner=line.order_id.partner_shipping_id)
line.update({
'price_tax': sum(t.get('amount', 0.0) for t in taxes.get('taxes', [])),
'price_total': taxes['total_included'],
'price_subtotal': taxes['total_excluded'],
})
if self.env.context.get('import_file', False) and not self.env.user.user_has_groups('account.group_account_manager'):
line.tax_id.invalidate_cache(['invoice_repartition_line_ids'], [line.tax_id.id])

How to change value of multiple fields onchange

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

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

More practical way to add my code to original method

So i'm overriding _prepare_invoice_line_from_po_line method. I'm satisfied with the result I'm getting but I want to make the code more elegant. Basically, it's copy past from original method but I only added a small part of it ( you can check it below). How can I add my code to this method without copy/past all original method?
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
price_by_pricelist = fields.Float("Price by Pricelist")
line_color = fields.Boolean()
#api.multi
def _prepare_invoice_line_from_po_line(self, line):
super(AccountInvoice,self)._prepare_invoice_line_from_po_line(line)
if line.product_id.purchase_method == 'purchase':
qty = line.product_qty - line.qty_invoiced
else:
qty = line.qty_received - line.qty_invoiced
if float_compare(qty, 0.0, precision_rounding=line.product_uom.rounding) <= 0:
qty = 0.0
taxes = line.taxes_id
invoice_line_tax_ids = self.purchase_id.fiscal_position_id.map_tax(taxes)
invoice_line = self.env['account.invoice.line']
data = {
'purchase_line_id': line.id,
'name': line.name,
'origin': self.purchase_id.origin,
'uom_id': line.product_uom.id,
'product_id': line.product_id.id,
'account_id': invoice_line.with_context({'journal_id': self.journal_id.id, 'type': 'in_invoice'})._default_account(),
'price_unit': line.order_id.currency_id.compute(line.price_unit, self.currency_id, round=False),
'quantity': qty,
'discount': 0.0,
'account_analytic_id': line.account_analytic_id.id,
'invoice_line_tax_ids': invoice_line_tax_ids.ids,
'price_by_pricelist': line.product_id.seller_ids[0].price,
}
if data['price_by_pricelist'] != line.price_unit:
self.line_color = True
account = invoice_line.get_invoice_line_account('in_invoice', line.product_id, self.purchase_id.fiscal_position_id, self.env.user.company_id)
if account:
data['account_id'] = account.id
return data
My part
'price_by_pricelist': line.product_id.seller_ids[0].price,
if data['price_by_pricelist'] != line.price_unit:
self.line_color = True
something like this should do the trick.
data = super(AccountInvoice,self)._prepare_invoice_line_from_po_line(line)
data.update({'price_by_pricelist': line.product_id.seller_ids[0].price}) # update the dictionary
if data['price_by_pricelist'] != line.price_unit:
self.line_color = True
return data
Steps:
Call super() to return the data from the original function
update the dictionary with the data you want
Do your data manipulation and what have you
return the data
Hope this helps :)

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.