[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:
Touati Djamel (otd)
2023-10-05 15:36:26 +00:00
committed by Djamel Touati
parent a0d4c62108
commit 6af53f5f48
2 changed files with 37 additions and 21 deletions
@@ -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)