[FIX] purchase(_stock): don't recompute price unit

Before this commit, when the quantity of a PO line is changed, its unit
price is recomputed, which means it will be set to 0 if there is no
compatible vendor price for the selected partner/product.
It can be annoying because if the price unit was set manually by the
user, this info is lost.
To avoid that, we don't recompute the unit price if the PO line matches
the following conditions:
- The PO line has already a price unit;
- There is actually no vendor price list for the partner (in such case,
  we prefer to avoid to stick to a price who doesn't match that list);
- The UoM wasn't changed, because if the UoM was changed, the price
  should obviously recomputed (the price unit for 1 unit is not the same
  than for 1 dozen).

How to reproduce:
- Install Stock and Purchase modules;
- In purchase settings, enable "Purchase Agreements";
- Create a product and in its vendor price list (in "Purchase" tab), add
  a price for Partner A (e.g. 10$);
- Create a PO for Partner B, add a PO line for the created product and
  set the `price_unit` higher than the created vendor price (e.g. 15$);
- Confirm the order and go in the "Alternatives" tab;
- Click on "Create Alternative" and select Partner A as the vendor;
- Click on "Compare Product Lines" and choose the line for Partner A;
- Go back in the first created PO (with Partner B as vendor)
  -> the PO line's quantity is to 0, which is good, but its unit price
     is also set to 0 which is annoying.

Additionnaly, in `_get_stock_move_price_unit`, `float_round` the value
just before it was returned because previously, the rouding was done
before the multiplication by the UoM's factor which can cause some
rounding issue if the rouding is not done after that.

closes odoo/odoo#104206

X-original-commit: f5a24b10cb3a4cf32c6c185df65f3099c8da3ff1
Signed-off-by: Tiffany Chang <tic@odoo.com>
Signed-off-by: Steve Van Essche <svs@odoo.com>
This commit is contained in:
svs-odoo
2022-10-27 10:37:40 +02:00
parent 7017150d7d
commit 0ebbc8f1d5
3 changed files with 40 additions and 2 deletions
+6
View File
@@ -1207,6 +1207,12 @@ class PurchaseOrderLine(models.Model):
# If not seller, use the standard price. It needs a proper currency conversion.
if not seller:
unavailable_seller = line.product_id.seller_ids.filtered(
lambda s: s.partner_id == line.order_id.partner_id)
if not unavailable_seller and line.price_unit and line.product_uom == line._origin.product_uom:
# Avoid to modify the price unit if there is no price list for this partner and
# the line has already one to avoid to override unit price set manually.
continue
po_line_uom = line.product_uom or line.product_id.uom_po_id
price_unit = line.env['account.tax']._fix_tax_included_price_company(
line.product_id.uom_id._compute_price(line.product_id.standard_price, po_line_uom),
@@ -217,3 +217,35 @@ class TestPurchaseRequisition(TestPurchaseRequisitionCommon):
groups = self.env['purchase.order.group'].search([('order_ids', 'in', pos.ids)])
self.assertEqual(len(po_5.alternative_po_ids), 0, "Last PO should auto unlink from itself since group should have auto-deleted")
self.assertEqual(len(groups), 0, "The group should have auto-deleted")
def test_09_alternative_po_line_price_unit(self):
"""Checks PO line's `price_unit` is keep even if a line from an
alternative is chosen and thus the PO line's quantity was set to 0. """
# Creates a first Purchase Order.
po_form = Form(self.env['purchase.order'])
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.price_unit = 16
po_1 = po_form.save()
# 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()
# Set a lower price on the alternative and choses this PO line.
po_2 = po_1.alternative_po_ids - po_1
po_2.order_line.price_unit = 12
po_2.order_line.action_choose()
self.assertEqual(
po_1.order_line.product_uom_qty, 0,
"Line's quantity from the original PO should be reset to 0")
self.assertEqual(
po_1.order_line.price_unit, 16,
"Line's unit price from the original PO shouldn't be changed")
+2 -2
View File
@@ -453,13 +453,13 @@ class PurchaseOrderLine(models.Model):
price_unit = self.taxes_id.with_context(round=False).compute_all(
price_unit, currency=self.order_id.currency_id, quantity=qty, product=self.product_id, partner=self.order_id.partner_id
)['total_void']
price_unit = float_round(price_unit / qty, precision_digits=price_unit_prec)
price_unit = price_unit / qty
if self.product_uom.id != self.product_id.uom_id.id:
price_unit *= self.product_uom.factor / self.product_id.uom_id.factor
if order.currency_id != order.company_id.currency_id:
price_unit = order.currency_id._convert(
price_unit, order.company_id.currency_id, self.company_id, self.date_order or fields.Date.today(), round=False)
return price_unit
return float_round(price_unit, precision_digits=price_unit_prec)
def _prepare_stock_moves(self, picking):
""" Prepare the stock moves data for one order line. This function returns a list of