From 8fbbee1155dddb4cb867a7df38b9772ef61489f8 Mon Sep 17 00:00:00 2001 From: AH-Yussef Date: Fri, 2 Feb 2024 04:41:25 +0200 Subject: [PATCH] [FIX] sale: prevent recomputing unit price for expensed so lines Steps to reproduce - Install Sales, Accounting and purchase apps - Go to Settings and activate Analytic Accounting option. - Create a product that can be expensed and that is re-invoiced at cost + add cost - Create an SO with another product and add an analytic account (activate analytic accounting if not activated by default) + confirm - Create a PO with the expensable product and add the analytic account in the PO lines - Receive product + create bill - The product is added in the SO with 0 quantity and if I change the quantity to one, the price is recomputed according to the sales price (instead of taking into account the cost). Investigation - The `_compute_price_unit()` method doesn't take into account if the so line has been expensed or not opw-3671812 closes odoo/odoo#153358 X-original-commit: 059b19c59a9222b676be5246eb94d680cf6bf27b Signed-off-by: Ali Hassan Youssef (alhy) --- addons/sale/models/sale_order_line.py | 2 +- addons/sale/tests/test_reinvoice.py | 32 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/addons/sale/models/sale_order_line.py b/addons/sale/models/sale_order_line.py index e5612a51570..5e55897a949 100644 --- a/addons/sale/models/sale_order_line.py +++ b/addons/sale/models/sale_order_line.py @@ -464,7 +464,7 @@ class SaleOrderLine(models.Model): for line in self: # check if there is already invoiced amount. if so, the price shouldn't change as it might have been # manually edited - if line.qty_invoiced > 0: + if line.qty_invoiced > 0 or (line.product_id.expense_policy == 'cost' and line.is_expense): continue if not line.product_uom or not line.product_id: line.price_unit = 0.0 diff --git a/addons/sale/tests/test_reinvoice.py b/addons/sale/tests/test_reinvoice.py index 69d2e99cb33..1baffd482ca 100644 --- a/addons/sale/tests/test_reinvoice.py +++ b/addons/sale/tests/test_reinvoice.py @@ -277,3 +277,35 @@ class TestReInvoice(TestSaleCommon): self.assertFalse(so_line4, "No re-invoicing should have created a new sale line with product #2") self.assertEqual(so_line1.qty_delivered, 1, "No re-invoicing should have impacted exising SO line 1") self.assertEqual(so_line2.qty_delivered, 1, "No re-invoicing should have impacted exising SO line 2") + + def test_not_recomputing_unit_price_for_expensed_so_lines(self): + # Required for `analytic_account_id` to be visible in the view + self.env.user.groups_id += self.env.ref('analytic.group_analytic_accounting') + + # create SO line and confirm SO (with only one line) + sol_1 = self.env['sale.order.line'].create({ + 'product_id': self.company_data['product_order_cost'].id, + 'product_uom_qty': 2, + 'qty_delivered': 1, + 'order_id': self.sale_order.id, + }) + self.sale_order.action_confirm() + + # create invoice lines and validate it + move_form = Form(self.AccountMove) + move_form.partner_id = self.partner_a + with move_form.invoice_line_ids.new() as line_form: + line_form.product_id = self.company_data['product_order_cost'] + line_form.quantity = 3.0 + line_form.analytic_distribution = {self.analytic_account.id: 100} + invoice = move_form.save() + invoice.action_post() + + # update the quantity of the expensed line + sol_2 = self.sale_order.order_line.filtered(lambda sol: sol != sol_1 and sol.product_id == self.company_data['product_order_cost']) + + sol_2_subtotal_before = sol_2.price_unit + sol_2.product_uom_qty = 3.0 + sol_2_subtotal_after = sol_2.price_unit + + self.assertEqual(sol_2_subtotal_before, sol_2_subtotal_after)