[FIX] account, purchase: price_unit as Float
The price unit on the account move line is defined as a monetary field. However, on a Sales Order or on a Purchase Order, the price unit is defined as a float with precision 'Product Price'. Therefore, when an invoice is generated from a SO or a PO, inconsistencies arise if the product price precision is larger than the currency precision. opw-673251
This commit is contained in:
@@ -635,7 +635,7 @@ class AccountTax(models.Model):
|
|||||||
# the 'Account' decimal precision + 5), and that way it's like
|
# the 'Account' decimal precision + 5), and that way it's like
|
||||||
# rounding after the sum of the tax amounts of each line
|
# rounding after the sum of the tax amounts of each line
|
||||||
prec = currency.decimal_places
|
prec = currency.decimal_places
|
||||||
if company_id.tax_calculation_rounding_method == 'round_globally':
|
if company_id.tax_calculation_rounding_method == 'round_globally' or not bool(self.env.context.get("round", True)):
|
||||||
prec += 5
|
prec += 5
|
||||||
total_excluded = total_included = base = round(price_unit * quantity, prec)
|
total_excluded = total_included = base = round(price_unit * quantity, prec)
|
||||||
|
|
||||||
@@ -650,7 +650,7 @@ class AccountTax(models.Model):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
tax_amount = tax._compute_amount(base, price_unit, quantity, product, partner)
|
tax_amount = tax._compute_amount(base, price_unit, quantity, product, partner)
|
||||||
if company_id.tax_calculation_rounding_method == 'round_globally':
|
if company_id.tax_calculation_rounding_method == 'round_globally' or not bool(self.env.context.get("round", True)):
|
||||||
tax_amount = round(tax_amount, prec)
|
tax_amount = round(tax_amount, prec)
|
||||||
else:
|
else:
|
||||||
tax_amount = currency.round(tax_amount)
|
tax_amount = currency.round(tax_amount)
|
||||||
@@ -676,8 +676,8 @@ class AccountTax(models.Model):
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
'taxes': sorted(taxes, key=lambda k: k['sequence']),
|
'taxes': sorted(taxes, key=lambda k: k['sequence']),
|
||||||
'total_excluded': currency.round(total_excluded),
|
'total_excluded': currency.round(total_excluded) if bool(self.env.context.get("round", True)) else total_excluded,
|
||||||
'total_included': currency.round(total_included),
|
'total_included': currency.round(total_included) if bool(self.env.context.get("round", True)) else total_included,
|
||||||
'base': base,
|
'base': base,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -733,6 +733,3 @@ class AccountOperationTemplate(models.Model):
|
|||||||
@api.onchange('name')
|
@api.onchange('name')
|
||||||
def onchange_name(self):
|
def onchange_name(self):
|
||||||
self.label = self.name
|
self.label = self.name
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1068,7 +1068,7 @@ class AccountInvoiceLine(models.Model):
|
|||||||
required=True, domain=[('deprecated', '=', False)],
|
required=True, domain=[('deprecated', '=', False)],
|
||||||
default=_default_account,
|
default=_default_account,
|
||||||
help="The income or expense account related to the selected product.")
|
help="The income or expense account related to the selected product.")
|
||||||
price_unit = fields.Monetary(string='Unit Price', required=True)
|
price_unit = fields.Float(string='Unit Price', required=True, digits=dp.get_precision('Product Price'))
|
||||||
price_subtotal = fields.Monetary(string='Amount',
|
price_subtotal = fields.Monetary(string='Amount',
|
||||||
store=True, readonly=True, compute='_compute_price')
|
store=True, readonly=True, compute='_compute_price')
|
||||||
price_subtotal_signed = fields.Monetary(string='Amount Signed', currency_field='company_currency_id',
|
price_subtotal_signed = fields.Monetary(string='Amount Signed', currency_field='company_currency_id',
|
||||||
@@ -1126,7 +1126,8 @@ class AccountInvoiceLine(models.Model):
|
|||||||
|
|
||||||
fix_price = self.env['account.tax']._fix_tax_included_price
|
fix_price = self.env['account.tax']._fix_tax_included_price
|
||||||
if self.invoice_id.type in ('in_invoice', 'in_refund'):
|
if self.invoice_id.type in ('in_invoice', 'in_refund'):
|
||||||
if not self.price_unit or float_compare(self.price_unit, self.product_id.standard_price, precision_digits=self.currency_id.rounding) == 0:
|
prec = self.env['decimal.precision'].precision_get('Product Price')
|
||||||
|
if not self.price_unit or float_compare(self.price_unit, self.product_id.standard_price, precision_digits=prec) == 0:
|
||||||
self.price_unit = fix_price(self.product_id.standard_price, taxes, fp_taxes)
|
self.price_unit = fix_price(self.product_id.standard_price, taxes, fp_taxes)
|
||||||
else:
|
else:
|
||||||
self.price_unit = fix_price(self.product_id.lst_price, taxes, fp_taxes)
|
self.price_unit = fix_price(self.product_id.lst_price, taxes, fp_taxes)
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ class account_voucher_line(models.Model):
|
|||||||
account_id = fields.Many2one('account.account', string='Account',
|
account_id = fields.Many2one('account.account', string='Account',
|
||||||
required=True, domain=[('deprecated', '=', False)],
|
required=True, domain=[('deprecated', '=', False)],
|
||||||
help="The income or expense account related to the selected product.")
|
help="The income or expense account related to the selected product.")
|
||||||
price_unit = fields.Monetary(string='Unit Price', required=True, oldname='amount')
|
price_unit = fields.Float(string='Unit Price', required=True, digits=dp.get_precision('Product Price'), oldname='amount')
|
||||||
price_subtotal = fields.Monetary(string='Amount',
|
price_subtotal = fields.Monetary(string='Amount',
|
||||||
store=True, readonly=True, compute='_compute_subtotal')
|
store=True, readonly=True, compute='_compute_subtotal')
|
||||||
quantity = fields.Float(digits=dp.get_precision('Product Unit of Measure'),
|
quantity = fields.Float(digits=dp.get_precision('Product Unit of Measure'),
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class AccountInvoice(models.Model):
|
|||||||
'uom_id': line.product_uom.id,
|
'uom_id': line.product_uom.id,
|
||||||
'product_id': line.product_id.id,
|
'product_id': line.product_id.id,
|
||||||
'account_id': self.env['account.invoice.line'].with_context({'journal_id': self.journal_id.id, 'type': 'in_invoice'})._default_account(),
|
'account_id': self.env['account.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),
|
'price_unit': line.order_id.currency_id.compute(line.price_unit, self.currency_id, round=False),
|
||||||
'quantity': qty,
|
'quantity': qty,
|
||||||
'discount': 0.0,
|
'discount': 0.0,
|
||||||
'account_analytic_id': line.account_analytic_id.id,
|
'account_analytic_id': line.account_analytic_id.id,
|
||||||
@@ -79,7 +79,7 @@ class AccountInvoice(models.Model):
|
|||||||
def _onchange_currency_id(self):
|
def _onchange_currency_id(self):
|
||||||
if self.currency_id:
|
if self.currency_id:
|
||||||
for line in self.invoice_line_ids.filtered(lambda r: r.purchase_line_id):
|
for line in self.invoice_line_ids.filtered(lambda r: r.purchase_line_id):
|
||||||
line.price_unit = line.purchase_id.currency_id.compute(line.purchase_line_id.price_unit, self.currency_id)
|
line.price_unit = line.purchase_id.currency_id.compute(line.purchase_line_id.price_unit, self.currency_id, round=False)
|
||||||
|
|
||||||
@api.onchange('invoice_line_ids')
|
@api.onchange('invoice_line_ids')
|
||||||
def _onchange_origin(self):
|
def _onchange_origin(self):
|
||||||
@@ -120,6 +120,7 @@ class AccountInvoice(models.Model):
|
|||||||
reference_account_id = i_line.product_id.product_tmpl_id.get_product_accounts(fiscal_pos=fpos)['stock_input'].id
|
reference_account_id = i_line.product_id.product_tmpl_id.get_product_accounts(fiscal_pos=fpos)['stock_input'].id
|
||||||
diff_res = []
|
diff_res = []
|
||||||
account_prec = inv.company_id.currency_id.decimal_places
|
account_prec = inv.company_id.currency_id.decimal_places
|
||||||
|
product_prec = self.env['decimal.precision'].precision_get('Product Price')
|
||||||
# calculate and write down the possible price difference between invoice price and product price
|
# calculate and write down the possible price difference between invoice price and product price
|
||||||
for line in res:
|
for line in res:
|
||||||
if line.get('invl_id', 0) == i_line.id and reference_account_id == line['account_id']:
|
if line.get('invl_id', 0) == i_line.id and reference_account_id == line['account_id']:
|
||||||
@@ -131,19 +132,21 @@ class AccountInvoice(models.Model):
|
|||||||
if valuation_stock_move:
|
if valuation_stock_move:
|
||||||
valuation_price_unit = valuation_stock_move[0].price_unit
|
valuation_price_unit = valuation_stock_move[0].price_unit
|
||||||
if inv.currency_id.id != company_currency.id:
|
if inv.currency_id.id != company_currency.id:
|
||||||
valuation_price_unit = company_currency.with_context(date=inv.date_invoice).compute(valuation_price_unit, inv.currency_id)
|
valuation_price_unit = company_currency.with_context(date=inv.date_invoice).compute(valuation_price_unit, inv.currency_id, round=False)
|
||||||
if valuation_price_unit != i_line.price_unit and line['price_unit'] == i_line.price_unit and acc:
|
if float_compare(valuation_price_unit, i_line.price_unit, precision_digits=product_prec) != 0\
|
||||||
|
and float_compare(line['price_unit'], i_line.price_unit, precision_digits=product_prec) == 0\
|
||||||
|
and acc:
|
||||||
# price with discount and without tax included
|
# price with discount and without tax included
|
||||||
price_unit = i_line.price_unit * (1 - (i_line.discount or 0.0) / 100.0)
|
price_unit = i_line.price_unit * (1 - (i_line.discount or 0.0) / 100.0)
|
||||||
if line['tax_ids']:
|
if line['tax_ids']:
|
||||||
#line['tax_ids'] is like [(4, tax_id, None), (4, tax_id2, None)...]
|
#line['tax_ids'] is like [(4, tax_id, None), (4, tax_id2, None)...]
|
||||||
taxes = self.env['account.tax'].browse([x[1] for x in line['tax_ids']])
|
taxes = self.env['account.tax'].browse([x[1] for x in line['tax_ids']])
|
||||||
price_unit = taxes.compute_all(price_unit, currency=inv.currency_id, quantity=1.0)['total_excluded']
|
price_unit = taxes.with_context(round=False).compute_all(price_unit, currency=inv.currency_id, quantity=1.0)['total_excluded']
|
||||||
line.update({'price': round(valuation_price_unit * line['quantity'], account_prec)})
|
line.update({'price': round(valuation_price_unit * line['quantity'], account_prec)})
|
||||||
diff_res.append({
|
diff_res.append({
|
||||||
'type': 'src',
|
'type': 'src',
|
||||||
'name': i_line.name[:64],
|
'name': i_line.name[:64],
|
||||||
'price_unit': round(price_unit - valuation_price_unit, account_prec),
|
'price_unit': round(price_unit - valuation_price_unit, product_prec),
|
||||||
'quantity': line['quantity'],
|
'quantity': line['quantity'],
|
||||||
'price': round((price_unit - valuation_price_unit) * line['quantity'], account_prec),
|
'price': round((price_unit - valuation_price_unit) * line['quantity'], account_prec),
|
||||||
'account_id': acc,
|
'account_id': acc,
|
||||||
|
|||||||
@@ -535,7 +535,7 @@ class PurchaseOrderLine(models.Model):
|
|||||||
order = line.order_id
|
order = line.order_id
|
||||||
price_unit = line.price_unit
|
price_unit = line.price_unit
|
||||||
if line.taxes_id:
|
if line.taxes_id:
|
||||||
price_unit = line.taxes_id.compute_all(price_unit, currency=line.order_id.currency_id, quantity=1.0)['total_excluded']
|
price_unit = line.taxes_id.with_context(round=False).compute_all(price_unit, currency=line.order_id.currency_id, quantity=1.0)['total_excluded']
|
||||||
if line.product_uom.id != line.product_id.uom_id.id:
|
if line.product_uom.id != line.product_id.uom_id.id:
|
||||||
price_unit *= line.product_uom.factor / line.product_id.uom_id.factor
|
price_unit *= line.product_uom.factor / line.product_id.uom_id.factor
|
||||||
if order.currency_id != order.company_id.currency_id:
|
if order.currency_id != order.company_id.currency_id:
|
||||||
|
|||||||
Reference in New Issue
Block a user