[FIX] purchase: compute the price with correct UoM in PO alternative

Steps to reproduce the bug:
- install the `purchase_requisition` module
- Create a storable product “P1”:
    - UoM: unit
    - cost: 10
- Create a PO:
    - Add 1 unit of “P1”:
        - Change the UoM from unit to Dozen
        - the unit price will be updated from 10 to 120
     - Save the PO
- Create a Po alternative

Problem:
The “Unit of measure” is correctly copied, but the unit price is wrongly
computed “10” instead of 120.

When creating the PO alternative, we copy the uom of the original
lines in the vals:
https://github.com/odoo/odoo/blob/4c2163d2b195a0c829d4e24a7afc3347e7c3401a/addons/purchase_requisition/wizard/purchase_requisition_create_alternative.py#L84

then, The line is created with the correct UoM, but we force the call
to `onchange_product_id`:
https://github.com/odoo/odoo/blob/c677f45dcb050ce7e6f755b71e56c9b9120bf613/addons/purchase/models/purchase.py#L1371-L1372

So `_product_id_change` will be called:
https://github.com/odoo/odoo/blob/c677f45dcb050ce7e6f755b71e56c9b9120bf613/addons/purchase/models/purchase.py#L1163

And the product UoM “Unit” will be set in the `purchase.order.line`:
https://github.com/odoo/odoo/blob/c677f45dcb050ce7e6f755b71e56c9b9120bf613/addons/purchase/models/purchase.py#L1171

Therefore, the unit price will be calculated with Unit instead of dozen:
https://github.com/odoo/odoo/blob/c677f45dcb050ce7e6f755b71e56c9b9120bf613/addons/purchase/models/purchase.py#L1225

Solution:
We have to ensure that the values only created by onchanges and not
provided during the alternative PO creation are still created via the
`onchange_product_id`. Therefore we avoid the incorrect uom reassignment
during the calculation of the unit price when creation is from an alt
PO creation with uom included.

closes odoo/odoo#117808

X-original-commit: 93769b9b51196c0aed74fc74cca1fcacdc59f789
Signed-off-by: Tiffany Chang <tic@odoo.com>
Signed-off-by: Djamel Touati (otd) <otd@odoo.com>
This commit is contained in:
Touati Djamel (otd)
2023-04-05 17:31:55 +02:00
parent 7ca2d7dbd6
commit f23d0fedfa
2 changed files with 29 additions and 1 deletions
+3 -1
View File
@@ -1179,7 +1179,9 @@ class PurchaseOrderLine(models.Model):
if not self.product_id:
return
self.product_uom = self.product_id.uom_po_id or self.product_id.uom_id
# 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
product_lang = self.product_id.with_context(
lang=get_lang(self.env, self.partner_id.lang).code,
partner_id=self.partner_id.id,
@@ -285,6 +285,32 @@ class TestPurchaseRequisition(TestPurchaseRequisitionCommon):
po_1.order_line.price_unit, 16,
"Line's unit price from the original PO shouldn't be changed")
def test_10_alternative_po_line_price_unit_different_uom(self):
""" Check that the uom is copied in the alternative PO, and the "unit_price"
is calculated according to this uom and not that of the product """
# Creates a first Purchase Order.
po_form = Form(self.env['purchase.order'])
self.product_09.standard_price = 10
po_form.partner_id = self.res_partner_1
with po_form.order_line.new() as line:
line.product_id = self.product_09
line.product_qty = 1
line.product_uom = self.env.ref('uom.product_uom_dozen')
po_1 = po_form.save()
self.assertEqual(po_1.order_line[0].price_unit, 120)
# Creates an alternative PO.
action = po_1.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.copy_products = True
alt_po_wizard = alt_po_wizard_form.save()
alt_po_wizard.action_create_alternative()
po_2 = po_1.alternative_po_ids - po_1
self.assertEqual(po_2.order_line[0].product_uom, po_1.order_line[0].product_uom)
self.assertEqual(po_2.order_line[0].price_unit, 120)
def test_11_alternative_po_from_po_with_requisition_id(self):
"""Create a purchase order from a blanket order, then check that the alternative purchase order
can be created and that the requisition_id is not set on it.