[FIX] purchase_stock: update the move price after changing the PO line price

Steps to reproduce the bug:
- Create a storable product “P1”:
    - Standard price: 20$
    - Add vendor in the Purchase tab:
        - name: Azure Interior
        - min qty: 10
        - price: $15

- Create a PO:
    - Vendor: "Azure Interior"
    - Product line: “P1”
Automatically, the Quantity field will automatically get populated as 10 Units
and price:$15 as per the pricelist

- Confirm the PO
A picking will be created containing a stock_move with a price of $15 and a QTY of 10

- Edit the Quantity to 9 Units and save the PO
The price will be updated to $20 on the PO line, but not in the `stock.move`

Problem:
When we update the qty in the PO line, a new move with a quantity of “-1” and
a price of “$20” will be created.
Then, it will be merged with the initial move, but since they are not identical in the price,
we can't merge them, so a new picking is created:
https://github.com/odoo/odoo/blob/dda9700d8236091626cbd78efc0ca4116e1e1acd/addons/stock/models/stock_move.py#L869-L881

Solution:
when the price is updated in a PO line, the price of its linked `stock.move` must also be updated

opw-2825160

closes odoo/odoo#92208

X-original-commit: c8d74a1cb4bfed8226e52e0bc6f243b4e483fc98
Signed-off-by: Djamel Touati (otd) <otd@odoo.com>
Signed-off-by: William Henrotin (whe) <whe@odoo.com>
This commit is contained in:
Touati Djamel (otd)
2022-05-27 10:46:33 +02:00
parent a1c2c6ee1f
commit 537e82d78d
3 changed files with 43 additions and 2 deletions
+2
View File
@@ -366,6 +366,8 @@ class PurchaseOrderLine(models.Model):
lines = self.filtered(lambda l: l.order_id.state == 'purchase')
previous_product_qty = {line.id: line.product_uom_qty for line in lines}
result = super(PurchaseOrderLine, self).write(values)
if 'price_unit' in values:
self.move_ids.price_unit = self.price_unit
if 'product_qty' in values:
lines.with_context(previous_product_qty=previous_product_qty)._create_or_update_picking()
return result
@@ -600,3 +600,44 @@ class TestCreatePicking(common.TestProductCommon):
self.assertEqual(purchase_order_line.product_qty, 45, 'The demand on the Purchase Order should not have been increased since it is has been confirmed.')
purchase_orders = self.env['purchase.order'].search([('partner_id', '=', partner.id)])
self.assertEqual(len(purchase_orders), 2, 'A new RFQ should have been created for missing demand.')
def test_update_qty_purchased(self):
"""
Test that the price unit in the purchase order line and the move is updated
according to the pricelist defined in the product, and that the "stock.moves"
are merged correctly when changing the qty purchased.
"""
# add vendor to the product
self.product_id_1.seller_ids = [(0, 0, {
'partner_id': self.partner_id.id,
'min_qty': 10,
'price': 15,
})]
# Create PO
po_form = Form(self.env['purchase.order'])
po_form.partner_id = self.partner_id
with po_form.order_line.new() as po_line:
po_line.product_id = self.product_id_1
po_line.product_qty = 10
purchase_order = po_form.save()
# Confirm Purchase order
purchase_order.button_confirm()
# Check purchase order state, it should be "purchase".
self.assertEqual(purchase_order.state, 'purchase', 'Purchase order should be in purchase state.')
# Make sure that picking has been created
self.assertEqual(len(purchase_order.picking_ids), 1)
# check that the price list has been applied
self.assertEqual(purchase_order.order_line.price_unit, 15)
self.assertEqual(purchase_order.picking_ids.move_ids.price_unit, 15)
# update the product qty purchased
with po_form.order_line.edit(0) as po_line:
po_line.product_qty = 9
purchase_order = po_form.save()
# verify that the move for the decreased qty has been merged with the initial move
self.assertEqual(len(purchase_order.picking_ids), 1)
self.assertEqual(len(purchase_order.picking_ids.move_ids), 1)
# check that the price has been updated in the purchase order line and in the stock.move
self.assertEqual(purchase_order.order_line.price_unit, 0)
self.assertEqual(purchase_order.picking_ids.move_ids.price_unit, 0)
@@ -88,8 +88,6 @@ class TestStockValuation(TransactionCase):
# update the unit price on the purchase order line
po1.order_line.price_unit = 200
# the unit price on the stock move is not directly updated
self.assertEqual(move1.price_unit, 100)
# validate the receipt
res_dict = picking1.button_validate()