[FIX] purchase_requisition: convert purchase price to current currency
Bug introduced in: https://github.com/odoo/odoo/pull/128327/commits/8f96e08985ebac3309745f1036a5e83d287e6382 Steps to reproduce the bug: - Activate 2 currencies (assume EUR and USD, conversion rate: 0.65 EUR = 1 USD) - Create new product “P1”: - Purchase tab: - add two vendors: - Vendor_USD, currency = USD, price = 100 - Vendor_EUR, currency = EUR, price = 80 - Create PO: - vendor = vendor_EUR - Currency = Eur - Add P1, Unit price should be 80 - Alternative tab > Create alternative > Vendor = Vendor_EUR - Compare product lines Issue: The line with price = 100 USD is highlighted as being the cheapest option, but if we apply conversion rules, 80 EUR = 123,07 USD > 100 USD. Solution: Before selecting the cheapest line, we convert the prices of the purchase order lines that are in a currency other than the current currency of the company. opw-3378253 closes odoo/odoo#137642 X-original-commit: c45272828ee85bc23dd97dc93dc741f8f59a5305 Signed-off-by: Tiffany Chang (tic) <tic@odoo.com> Signed-off-by: Djamel Touati (otd) <otd@odoo.com>
This commit is contained in:
committed by
Djamel Touati
parent
a0d4c62108
commit
6af53f5f48
@@ -235,10 +235,10 @@ class PurchaseOrder(models.Model):
|
||||
current_price_subtotal = product_to_best_price_line[line.product_id][0].price_subtotal
|
||||
current_price_unit = product_to_best_price_unit[line.product_id][0].price_unit
|
||||
if multiple_currencies:
|
||||
price_subtotal *= line.order_id.currency_rate
|
||||
price_unit *= line.order_id.currency_rate
|
||||
current_price_subtotal *= product_to_best_price_line[line.product_id][0].order_id.currency_rate
|
||||
current_price_unit *= product_to_best_price_unit[line.product_id][0].order_id.currency_rate
|
||||
price_subtotal /= line.order_id.currency_rate
|
||||
price_unit /= line.order_id.currency_rate
|
||||
current_price_subtotal /= product_to_best_price_line[line.product_id][0].order_id.currency_rate
|
||||
current_price_unit /= product_to_best_price_unit[line.product_id][0].order_id.currency_rate
|
||||
|
||||
if current_price_subtotal > price_subtotal:
|
||||
product_to_best_price_line[line.product_id] = line
|
||||
|
||||
@@ -7,7 +7,10 @@ from odoo.tests import Form
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo.tests.common import tagged
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestPurchaseRequisition(TestPurchaseRequisitionCommon):
|
||||
|
||||
def test_00_purchase_requisition_users(self):
|
||||
@@ -375,30 +378,51 @@ class TestPurchaseRequisition(TestPurchaseRequisitionCommon):
|
||||
'currency_id': self.env.ref('base.EUR').id,
|
||||
'rate': 0.5,
|
||||
}])
|
||||
vendor_usd = self.env["res.partner"].create({
|
||||
"name": "Supplier A",
|
||||
})
|
||||
vendor_eur = self.env["res.partner"].create({
|
||||
"name": "Supplier B",
|
||||
})
|
||||
|
||||
product = self.env['product.product'].create({
|
||||
'name': 'Product',
|
||||
'seller_ids': [(0, 0, {
|
||||
'partner_id': vendor_usd.id,
|
||||
'price': 100,
|
||||
'currency_id': currency_usd.id,
|
||||
}), (0, 0, {
|
||||
'partner_id': vendor_eur.id,
|
||||
'price': 80,
|
||||
'currency_id': currency_eur.id,
|
||||
})]
|
||||
})
|
||||
po_form = Form(self.env['purchase.order'])
|
||||
po_form.partner_id = self.res_partner_1
|
||||
po_form.currency_id = currency_usd
|
||||
po_form.partner_id = vendor_eur
|
||||
po_form.currency_id = currency_eur
|
||||
with po_form.order_line.new() as line:
|
||||
line.product_id = self.product_09
|
||||
line.product_id = product
|
||||
line.product_qty = 1
|
||||
line.price_unit = 10
|
||||
po_orig = po_form.save()
|
||||
self.assertEqual(po_orig.order_line.price_unit, 80)
|
||||
self.assertEqual(po_orig.currency_id, currency_eur)
|
||||
|
||||
# Creates an alternative PO
|
||||
action = po_orig.action_create_alternative()
|
||||
alt_po_wizard_form = Form(self.env['purchase.requisition.create.alternative'].with_context(**action['context']))
|
||||
alt_po_wizard_form.partner_id = self.res_partner_1
|
||||
alt_po_wizard_form.partner_id = vendor_usd
|
||||
alt_po_wizard_form.copy_products = True
|
||||
alt_po_wizard = alt_po_wizard_form.save()
|
||||
alt_po_wizard.action_create_alternative()
|
||||
|
||||
po_alt = po_orig.alternative_po_ids - po_orig
|
||||
po_alt.currency_id = currency_eur
|
||||
po_alt.order_line.price_unit = 12
|
||||
# po_alt has cheaper price_unit/price_subtotal after conversion USD -> EUR
|
||||
# 12 USD = 12 * 0.5 = 6 EUR < 10 EUR
|
||||
# Ensure that the currency in the alternative purchase order is set to USD
|
||||
# because, in some case, the company's default currency is EUR.
|
||||
self.assertEqual(po_alt.currency_id, currency_usd)
|
||||
self.assertEqual(po_alt.order_line.price_unit, 100)
|
||||
|
||||
# po_alt has cheaper price_unit/price_subtotal after conversion USD -> EUR
|
||||
# 80 / 0.5 = 160 USD > 100 EUR
|
||||
best_price_ids, best_date_ids, best_price_unit_ids = po_orig.get_tender_best_lines()
|
||||
self.assertEqual(len(best_price_ids), 1)
|
||||
# Equal dates
|
||||
@@ -407,11 +431,3 @@ class TestPurchaseRequisition(TestPurchaseRequisitionCommon):
|
||||
# alt_po is cheaper than orig_po
|
||||
self.assertEqual(best_price_ids[0], po_alt.order_line.id)
|
||||
self.assertEqual(best_price_unit_ids[0], po_alt.order_line.id)
|
||||
|
||||
po_alt.order_line.price_unit = 20
|
||||
# po_alt has same price_unit/price_subtotal after conversion USD -> EUR
|
||||
# 20 USD = 20 * 0.5 = 10 EUR
|
||||
best_price_ids, best_date_ids, best_price_unit_ids = po_orig.get_tender_best_lines()
|
||||
self.assertEqual(len(best_price_ids), 2)
|
||||
self.assertEqual(len(best_date_ids), 2)
|
||||
self.assertEqual(len(best_price_unit_ids), 2)
|
||||
|
||||
Reference in New Issue
Block a user