[FIX] purchase: set the correct price in alternative PO

Steps to reproduce the bug:
- Create a storable product “P1”:
    - Price at “Wood corner”:
        - $5, min qty =1
    - Price at “Open wood:
        - $6, min qty = 1
        - $4, min qty = 10

- Create a purchase order at wood corner:
    - 100 units
> the price is automatically computed at $500

- Go to Alternative tab in the PO:
   - Create a one for “Openwood” and copy lines

Problem:
The price for 100 units is computed as $600 instead of $400.

When we create the alternative purchase order, in the "create" function
of “purchase.order.line,” we receive only the quantity as "qty=100" in
the values. Therefore, the missing fields should be prepared.

https://github.com/odoo/odoo/blob/a9cbd2a2ae2e21f1ba14379aecd908c44497b8ab/addons/purchase/models/purchase.py#L1102

https://github.com/odoo/odoo/blob/a9cbd2a2ae2e21f1ba14379aecd908c44497b8ab/addons/purchase/models/purchase.py#L1102

First, the line is created with the received values (“qty=100”), and
the price_unit is computed correctly as $4.

https://github.com/odoo/odoo/blob/a9cbd2a2ae2e21f1ba14379aecd908c44497b8ab/addons/purchase/models/purchase.py#L1400

So, the price_unit is computed correctly at $4

However, the “onchange_product_id” function is then called, resetting
the price_unit and product_qty to 0.

https://github.com/odoo/odoo/blob/a9cbd2a2ae2e21f1ba14379aecd908c44497b8ab/addons/purchase/models/purchase.py#L1401

https://github.com/odoo/odoo/blob/a9cbd2a2ae2e21f1ba14379aecd908c44497b8ab/addons/purchase/models/purchase.py#L1176

Afterward, the “_suggest_quantity()” function is called

https://github.com/odoo/odoo/blob/a9cbd2a2ae2e21f1ba14379aecd908c44497b8ab/addons/purchase/models/purchase.py#L1180

suggesting a minimal quantity based on the seller (so=1).

https://github.com/odoo/odoo/blob/a9cbd2a2ae2e21f1ba14379aecd908c44497b8ab/addons/purchase/models/purchase.py#L1363

Therefore, the price_unit is computed based on qty=1, resulting in $6.

Finally, the price is returned because it is the only missing field.

opw-3497825

closes odoo/odoo#137774

X-original-commit: 0781198f1b5e5d6a4e2722ea3c663b74fb131bc3
Signed-off-by: Djamel Touati (otd) <otd@odoo.com>
This commit is contained in:
Djamel Touati
2023-10-06 07:12:13 +00:00
parent a5f01f9d7a
commit ad253ef4c2
2 changed files with 43 additions and 4 deletions
+3 -4
View File
@@ -1165,7 +1165,8 @@ class PurchaseOrderLine(models.Model):
@api.onchange('product_id')
def onchange_product_id(self):
if not self.product_id:
# TODO: Remove when onchanges are replaced with computes
if not self.product_id or (self.env.context.get('origin_po_id') and self.product_qty):
return
# Reset date, price and quantity since _onchange_quantity will provide default values
@@ -1179,9 +1180,7 @@ class PurchaseOrderLine(models.Model):
if not self.product_id:
return
# TODO: Remove when onchanges are replaced with computes
if not (self.env.context.get('origin_po_id') and self.product_uom and self.product_id.uom_id.category_id == self.product_uom_category_id):
self.product_uom = self.product_id.uom_po_id or self.product_id.uom_id
self.product_uom = self.product_id.uom_po_id or self.product_id.uom_id
product_lang = self.product_id.with_context(
lang=get_lang(self.env, self.partner_id.lang).code,
partner_id=self.partner_id.id,
@@ -431,3 +431,43 @@ 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)
def test_alternative_po_with_multiple_price_list(self):
vendor_a = self.env["res.partner"].create({
"name": "Supplier A",
})
vendor_b = self.env["res.partner"].create({
"name": "Supplier B",
})
product = self.env['product.product'].create({
'name': 'Product',
'seller_ids': [(0, 0, {
'partner_id': vendor_a.id,
'price': 5,
}), (0, 0, {
'partner_id': vendor_b.id,
'price': 4,
'min_qty': 10,
}), (0, 0, {
'partner_id': vendor_b.id,
'price': 6,
'min_qty': 1,
}),
]
})
po_form = Form(self.env['purchase.order'])
po_form.partner_id = vendor_a
with po_form.order_line.new() as line:
line.product_id = product
line.product_qty = 100
po_orig = po_form.save()
self.assertEqual(po_orig.order_line.price_unit, 5)
# 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 = vendor_b
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
self.assertEqual(po_alt.order_line.price_unit, 4)