From f23d0fedfa680ea91a8aa1b9244ad52f1924dced Mon Sep 17 00:00:00 2001 From: "Touati Djamel (otd)" Date: Tue, 28 Feb 2023 14:28:25 +0000 Subject: [PATCH] [FIX] purchase: compute the price with correct UoM in PO alternative MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Djamel Touati (otd) --- addons/purchase/models/purchase.py | 4 ++- .../tests/test_purchase_requisition.py | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py index 77d85dda035..81fe7ef0045 100644 --- a/addons/purchase/models/purchase.py +++ b/addons/purchase/models/purchase.py @@ -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, diff --git a/addons/purchase_requisition/tests/test_purchase_requisition.py b/addons/purchase_requisition/tests/test_purchase_requisition.py index 4555f36d55d..6c8f8ff76a3 100644 --- a/addons/purchase_requisition/tests/test_purchase_requisition.py +++ b/addons/purchase_requisition/tests/test_purchase_requisition.py @@ -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.