Skip to content

Commit

Permalink
[FIX] purchase_requisition: convert purchase price to current currency
Browse files Browse the repository at this point in the history
Bug introduced in:
odoo@8f96e08

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#135037

Signed-off-by: Tiffany Chang (tic) <tic@odoo.com>
  • Loading branch information
DjamelTouati committed Oct 4, 2023
1 parent 4f2da91 commit c452728
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 21 deletions.
8 changes: 4 additions & 4 deletions addons/purchase_requisition/models/purchase.py
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,10 @@ def get_tender_best_lines(self):
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
Expand Down
50 changes: 33 additions & 17 deletions addons/purchase_requisition/tests/test_purchase_requisition.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@

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):
Expand Down Expand Up @@ -376,30 +379,51 @@ def test_12_alternative_po_line_different_currency(self):
'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
Expand All @@ -408,11 +432,3 @@ def test_12_alternative_po_line_different_currency(self):
# 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)

0 comments on commit c452728

Please sign in to comment.