[FIX] sale_stock_margin: convert purchase_price
When confirming a SO, if the costing method of a product's category is
not `Standard' and if the SO's currency is different from the company's
currency, the cost of the product won't be converted to the SO's
currency
To reproduce the error:
1. In Settings, enable:
- Margins
- Multi-Currencies
2. Create a product category PC:
- Costing Method: FIFO
3. Create a product P:
- Product Type: Storable
- Product Category: PC
- Sales Price: 200
- Cost: 100
4. Update P's quantity to 1
5. Create a pricelist PL:
- Currency: EUR
6. Create a SO:
- Pricelist: PL
- Order Lines:
- 1 x P
7. Add field "Cost" to the tree view of the order lines
- The value is correctly converted
8. Confirm the SO
Error: The cost of the order line is now 100€. This is actually the USD
cost, it should be converted
This code applies the same conversion as when the cost method is
standard:
https://github.com/odoo/odoo/blob/8a8ff03f6111f377bcd9c2b0f584c450b82a4182/addons/sale_margin/models/sale_order.py#L42-L48
OPW-2563442
closes odoo/odoo#73786
X-original-commit: 04e4cd91637c836b4d856b8638d88c5cf1770421
Signed-off-by: Rémy Voet <ryv-odoo@users.noreply.github.com>
Signed-off-by: Adrien Widart <adwid@users.noreply.github.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, models
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class SaleOrderLine(models.Model):
|
||||
@@ -14,7 +14,15 @@ class SaleOrderLine(models.Model):
|
||||
if not line.move_ids:
|
||||
lines_without_moves |= line
|
||||
elif line.product_id.categ_id.property_cost_method != 'standard':
|
||||
line.purchase_price = line.product_id.with_company(line.company_id)._compute_average_price(0, line.product_uom_qty, line.move_ids)
|
||||
purch_price = line.product_id.with_company(line.company_id)._compute_average_price(0, line.product_uom_qty, line.move_ids)
|
||||
if line.product_uom and line.product_uom != line.product_id.uom_id:
|
||||
line.purchase_price = line.product_id.uom_id._compute_price(line.purchase_price, line.product_uom)
|
||||
purch_price = line.product_id.uom_id._compute_price(purch_price, line.product_uom)
|
||||
to_cur = line.currency_id or line.order_id.currency_id
|
||||
line.purchase_price = line.product_id.cost_currency_id._convert(
|
||||
from_amount=purch_price,
|
||||
to_currency=to_cur,
|
||||
company=line.company_id or self.env.company,
|
||||
date=line.order_id.date_order or fields.Date.today(),
|
||||
round=False,
|
||||
) if to_cur and purch_price else purch_price
|
||||
return super(SaleOrderLine, lines_without_moves)._compute_purchase_price()
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import fields
|
||||
|
||||
from odoo.tests.common import Form
|
||||
from odoo.addons.stock_account.tests.test_stockvaluationlayer import TestStockValuationCommon
|
||||
|
||||
|
||||
class TestSaleStockMargin(TestStockValuationCommon):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestSaleStockMargin, cls).setUpClass()
|
||||
cls.pricelist = cls.env['product.pricelist'].create({'name': 'Simple Pricelist'})
|
||||
|
||||
#########
|
||||
# UTILS #
|
||||
#########
|
||||
@@ -15,6 +23,7 @@ class TestSaleStockMargin(TestStockValuationCommon):
|
||||
'name': 'Sale order',
|
||||
'partner_id': self.env.ref('base.partner_admin').id,
|
||||
'partner_invoice_id': self.env.ref('base.partner_admin').id,
|
||||
'pricelist_id': self.pricelist.id,
|
||||
})
|
||||
|
||||
def _create_sale_order_line(self, sale_order, product, quantity, price_unit=0):
|
||||
@@ -156,3 +165,37 @@ class TestSaleStockMargin(TestStockValuationCommon):
|
||||
self.assertAlmostEqual(order_line_1.margin, 34) # (60 - 43) * 2
|
||||
self.assertAlmostEqual(order_line_2.margin, 30) # (20 - 12.5) * 4
|
||||
self.assertAlmostEqual(sale_order.margin, 64)
|
||||
|
||||
def test_so_and_multicurrency(self):
|
||||
ResCurrencyRate = self.env['res.currency.rate']
|
||||
company_currency = self.env.company.currency_id
|
||||
other_currency = self.env.ref('base.EUR') if company_currency == self.env.ref('base.USD') else self.env.ref('base.USD')
|
||||
|
||||
ResCurrencyRate.create({'currency_id': company_currency.id, 'rate': 1})
|
||||
other_currency_rate = ResCurrencyRate.search([('name', '=', fields.Date.today()), ('currency_id', '=', other_currency.id)])
|
||||
if other_currency_rate:
|
||||
other_currency_rate.rate = 2
|
||||
else:
|
||||
ResCurrencyRate.create({'currency_id': other_currency.id, 'rate': 2})
|
||||
|
||||
so = self._create_sale_order()
|
||||
so.pricelist_id = self.env['product.pricelist'].create({
|
||||
'name': 'Super Pricelist',
|
||||
'currency_id': other_currency.id,
|
||||
})
|
||||
|
||||
product = self._create_product()
|
||||
product.standard_price = 100
|
||||
product.list_price = 200
|
||||
|
||||
so_form = Form(so)
|
||||
with so_form.order_line.new() as line:
|
||||
line.product_id = product
|
||||
so = so_form.save()
|
||||
so_line = so.order_line
|
||||
|
||||
self.assertEqual(so_line.purchase_price, 200)
|
||||
self.assertEqual(so_line.price_unit, 400)
|
||||
so.action_confirm()
|
||||
self.assertEqual(so_line.purchase_price, 200)
|
||||
self.assertEqual(so_line.price_unit, 400)
|
||||
|
||||
Reference in New Issue
Block a user